aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/QmlChanges.txt364
-rw-r--r--src/declarative/debugger/debugger.pri23
-rw-r--r--src/declarative/debugger/qdeclarativedebug.cpp1021
-rw-r--r--src/declarative/debugger/qdeclarativedebug_p.h386
-rw-r--r--src/declarative/debugger/qdeclarativedebugclient.cpp292
-rw-r--r--src/declarative/debugger/qdeclarativedebugclient_p.h103
-rw-r--r--src/declarative/debugger/qdeclarativedebuggerstatus.cpp54
-rw-r--r--src/declarative/debugger/qdeclarativedebuggerstatus_p.h68
-rw-r--r--src/declarative/debugger/qdeclarativedebughelper.cpp76
-rw-r--r--src/declarative/debugger/qdeclarativedebughelper_p.h73
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver.cpp375
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver_p.h88
-rw-r--r--src/declarative/debugger/qdeclarativedebugserverconnection_p.h73
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice.cpp220
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p.h94
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p_p.h71
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace.cpp218
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace_p.h131
-rw-r--r--src/declarative/debugger/qpacketprotocol.cpp507
-rw-r--r--src/declarative/debugger/qpacketprotocol_p.h125
-rw-r--r--src/declarative/declarative.pro43
-rw-r--r--src/declarative/graphicsitems/graphicsitems.pri94
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors.cpp1165
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors_p.h206
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors_p_p.h170
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp378
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanimatedimage_p.h116
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanimatedimage_p_p.h87
-rw-r--r--src/declarative/graphicsitems/qdeclarativeborderimage.cpp619
-rw-r--r--src/declarative/graphicsitems/qdeclarativeborderimage_p.h111
-rw-r--r--src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h106
-rw-r--r--src/declarative/graphicsitems/qdeclarativeevents.cpp237
-rw-r--r--src/declarative/graphicsitems/qdeclarativeevents_p_p.h141
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp1799
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable_p.h229
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable_p_p.h241
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflipable.cpp254
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflipable_p.h100
-rw-r--r--src/declarative/graphicsitems/qdeclarativefocuspanel.cpp89
-rw-r--r--src/declarative/graphicsitems/qdeclarativefocuspanel_p.h78
-rw-r--r--src/declarative/graphicsitems/qdeclarativefocusscope.cpp73
-rw-r--r--src/declarative/graphicsitems/qdeclarativefocusscope_p.h69
-rw-r--r--src/declarative/graphicsitems/qdeclarativegraphicswidget.cpp125
-rw-r--r--src/declarative/graphicsitems/qdeclarativegraphicswidget_p.h90
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp3125
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview_p.h288
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimage.cpp584
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimage_p.h100
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimage_p_p.h79
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase.cpp284
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase_p.h116
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h93
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimplicitsizeitem.cpp92
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p.h100
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p_p.h90
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp3724
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.h234
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem_p.h624
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemchangelistener_p.h76
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp261
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemsmodule_p.h63
-rw-r--r--src/declarative/graphicsitems/qdeclarativelayoutitem.cpp112
-rw-r--r--src/declarative/graphicsitems/qdeclarativelayoutitem_p.h94
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp3606
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview_p.h372
-rw-r--r--src/declarative/graphicsitems/qdeclarativeloader.cpp597
-rw-r--r--src/declarative/graphicsitems/qdeclarativeloader_p.h108
-rw-r--r--src/declarative/graphicsitems/qdeclarativeloader_p_p.h91
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea.cpp978
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p.h218
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p_p.h145
-rw-r--r--src/declarative/graphicsitems/qdeclarativepainteditem.cpp497
-rw-r--r--src/declarative/graphicsitems/qdeclarativepainteditem_p.h118
-rw-r--r--src/declarative/graphicsitems/qdeclarativepainteditem_p_p.h90
-rw-r--r--src/declarative/graphicsitems/qdeclarativepath.cpp922
-rw-r--r--src/declarative/graphicsitems/qdeclarativepath_p.h286
-rw-r--r--src/declarative/graphicsitems/qdeclarativepath_p_p.h82
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview.cpp1724
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview_p.h252
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview_p_p.h192
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea.cpp607
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea_p.h313
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea_p_p.h115
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners.cpp1392
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners_p.h239
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners_p_p.h173
-rw-r--r--src/declarative/graphicsitems/qdeclarativerectangle.cpp587
-rw-r--r--src/declarative/graphicsitems/qdeclarativerectangle_p.h188
-rw-r--r--src/declarative/graphicsitems/qdeclarativerectangle_p_p.h112
-rw-r--r--src/declarative/graphicsitems/qdeclarativerepeater.cpp447
-rw-r--r--src/declarative/graphicsitems/qdeclarativerepeater_p.h110
-rw-r--r--src/declarative/graphicsitems/qdeclarativerepeater_p_p.h82
-rw-r--r--src/declarative/graphicsitems/qdeclarativescalegrid.cpp213
-rw-r--r--src/declarative/graphicsitems/qdeclarativescalegrid_p_p.h134
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext.cpp1640
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext_p.h213
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext_p_p.h143
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit.cpp1889
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p.h307
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p_p.h138
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput.cpp2023
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p.h305
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p_p.h158
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextlayout.cpp388
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextlayout_p.h75
-rw-r--r--src/declarative/graphicsitems/qdeclarativetranslate.cpp125
-rw-r--r--src/declarative/graphicsitems/qdeclarativetranslate_p.h89
-rw-r--r--src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp1420
-rw-r--r--src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h257
-rw-r--r--src/declarative/qml/parser/parser.pri21
-rw-r--r--src/declarative/qml/parser/qdeclarativejs.g3149
-rw-r--r--src/declarative/qml/parser/qdeclarativejsast.cpp956
-rw-r--r--src/declarative/qml/parser/qdeclarativejsast_p.h2546
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastfwd_p.h189
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastvisitor.cpp58
-rw-r--r--src/declarative/qml/parser/qdeclarativejsastvisitor_p.h335
-rw-r--r--src/declarative/qml/parser/qdeclarativejsengine_p.cpp212
-rw-r--r--src/declarative/qml/parser/qdeclarativejsengine_p.h167
-rw-r--r--src/declarative/qml/parser/qdeclarativejsglobal_p.h64
-rw-r--r--src/declarative/qml/parser/qdeclarativejsgrammar.cpp989
-rw-r--r--src/declarative/qml/parser/qdeclarativejsgrammar_p.h210
-rw-r--r--src/declarative/qml/parser/qdeclarativejslexer.cpp1258
-rw-r--r--src/declarative/qml/parser/qdeclarativejslexer_p.h249
-rw-r--r--src/declarative/qml/parser/qdeclarativejsmemorypool_p.h133
-rw-r--r--src/declarative/qml/parser/qdeclarativejsnodepool_p.h139
-rw-r--r--src/declarative/qml/parser/qdeclarativejsparser.cpp1904
-rw-r--r--src/declarative/qml/parser/qdeclarativejsparser_p.h246
-rw-r--r--src/declarative/qml/qbitfield_p.h165
-rw-r--r--src/declarative/qml/qdeclarative.h415
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp570
-rw-r--r--src/declarative/qml/qdeclarativebinding_p.h193
-rw-r--r--src/declarative/qml/qdeclarativebinding_p_p.h85
-rw-r--r--src/declarative/qml/qdeclarativeboundsignal.cpp306
-rw-r--r--src/declarative/qml/qdeclarativeboundsignal_p.h103
-rw-r--r--src/declarative/qml/qdeclarativecleanup.cpp87
-rw-r--r--src/declarative/qml/qdeclarativecleanup_p.h79
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings.cpp2906
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings_p.h116
-rw-r--r--src/declarative/qml/qdeclarativecompileddata.cpp255
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp3123
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h351
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp1078
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h132
-rw-r--r--src/declarative/qml/qdeclarativecomponent_p.h161
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp774
-rw-r--r--src/declarative/qml/qdeclarativecontext.h114
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h292
-rw-r--r--src/declarative/qml/qdeclarativecontextscriptclass.cpp335
-rw-r--r--src/declarative/qml/qdeclarativecontextscriptclass_p.h106
-rw-r--r--src/declarative/qml/qdeclarativecustomparser.cpp317
-rw-r--r--src/declarative/qml/qdeclarativecustomparser_p.h167
-rw-r--r--src/declarative/qml/qdeclarativecustomparser_p_p.h89
-rw-r--r--src/declarative/qml/qdeclarativedata_p.h191
-rw-r--r--src/declarative/qml/qdeclarativedirparser.cpp232
-rw-r--r--src/declarative/qml/qdeclarativedirparser_p.h129
-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.cpp2512
-rw-r--r--src/declarative/qml/qdeclarativeengine.h129
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h388
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug.cpp735
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug_p.h134
-rw-r--r--src/declarative/qml/qdeclarativeerror.cpp285
-rw-r--r--src/declarative/qml/qdeclarativeerror.h86
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp875
-rw-r--r--src/declarative/qml/qdeclarativeexpression.h119
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h233
-rw-r--r--src/declarative/qml/qdeclarativeextensioninterface.h68
-rw-r--r--src/declarative/qml/qdeclarativeextensionplugin.cpp171
-rw-r--r--src/declarative/qml/qdeclarativeextensionplugin.h76
-rw-r--r--src/declarative/qml/qdeclarativefastproperties.cpp101
-rw-r--r--src/declarative/qml/qdeclarativefastproperties_p.h75
-rw-r--r--src/declarative/qml/qdeclarativeglobal_p.h110
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass.cpp147
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass_p.h86
-rw-r--r--src/declarative/qml/qdeclarativeguard_p.h157
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.cpp247
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.h80
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp1079
-rw-r--r--src/declarative/qml/qdeclarativeimport_p.h142
-rw-r--r--src/declarative/qml/qdeclarativeinclude.cpp310
-rw-r--r--src/declarative/qml/qdeclarativeinclude_p.h115
-rw-r--r--src/declarative/qml/qdeclarativeinfo.cpp179
-rw-r--r--src/declarative/qml/qdeclarativeinfo.h105
-rw-r--r--src/declarative/qml/qdeclarativeinstruction.cpp230
-rw-r--r--src/declarative/qml/qdeclarativeinstruction_p.h359
-rw-r--r--src/declarative/qml/qdeclarativeintegercache.cpp96
-rw-r--r--src/declarative/qml/qdeclarativeintegercache_p.h112
-rw-r--r--src/declarative/qml/qdeclarativelist.cpp417
-rw-r--r--src/declarative/qml/qdeclarativelist.h152
-rw-r--r--src/declarative/qml/qdeclarativelist_p.h85
-rw-r--r--src/declarative/qml/qdeclarativelistscriptclass.cpp149
-rw-r--r--src/declarative/qml/qdeclarativelistscriptclass_p.h87
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp1536
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h174
-rw-r--r--src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp103
-rw-r--r--src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h66
-rw-r--r--src/declarative/qml/qdeclarativenotifier.cpp126
-rw-r--r--src/declarative/qml/qdeclarativenotifier_p.h261
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp1199
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass_p.h166
-rw-r--r--src/declarative/qml/qdeclarativeparser.cpp437
-rw-r--r--src/declarative/qml/qdeclarativeparser_p.h381
-rw-r--r--src/declarative/qml/qdeclarativeparserstatus.cpp107
-rw-r--r--src/declarative/qml/qdeclarativeparserstatus.h75
-rw-r--r--src/declarative/qml/qdeclarativeprivate.h249
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp1649
-rw-r--r--src/declarative/qml/qdeclarativeproperty.h143
-rw-r--r--src/declarative/qml/qdeclarativeproperty_p.h147
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp471
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h240
-rw-r--r--src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp79
-rw-r--r--src/declarative/qml/qdeclarativepropertyvalueinterceptor.h68
-rw-r--r--src/declarative/qml/qdeclarativepropertyvaluesource.cpp76
-rw-r--r--src/declarative/qml/qdeclarativepropertyvaluesource.h67
-rw-r--r--src/declarative/qml/qdeclarativeproxymetaobject.cpp124
-rw-r--r--src/declarative/qml/qdeclarativeproxymetaobject_p.h100
-rw-r--r--src/declarative/qml/qdeclarativerefcount.cpp70
-rw-r--r--src/declarative/qml/qdeclarativerefcount_p.h80
-rw-r--r--src/declarative/qml/qdeclarativerewrite.cpp273
-rw-r--r--src/declarative/qml/qdeclarativerewrite_p.h127
-rw-r--r--src/declarative/qml/qdeclarativescriptparser.cpp1206
-rw-r--r--src/declarative/qml/qdeclarativescriptparser_p.h148
-rw-r--r--src/declarative/qml/qdeclarativescriptstring.cpp166
-rw-r--r--src/declarative/qml/qdeclarativescriptstring.h87
-rw-r--r--src/declarative/qml/qdeclarativesqldatabase.cpp448
-rw-r--r--src/declarative/qml/qdeclarativesqldatabase_p.h67
-rw-r--r--src/declarative/qml/qdeclarativestringconverters.cpp278
-rw-r--r--src/declarative/qml/qdeclarativestringconverters_p.h91
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp1089
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h321
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp118
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h119
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp165
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass_p.h92
-rw-r--r--src/declarative/qml/qdeclarativetypenotavailable.cpp53
-rw-r--r--src/declarative/qml/qdeclarativetypenotavailable_p.h65
-rw-r--r--src/declarative/qml/qdeclarativevaluetype.cpp1011
-rw-r--r--src/declarative/qml/qdeclarativevaluetype_p.h556
-rw-r--r--src/declarative/qml/qdeclarativevaluetypescriptclass.cpp242
-rw-r--r--src/declarative/qml/qdeclarativevaluetypescriptclass_p.h87
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp1058
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h121
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp903
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject_p.h197
-rw-r--r--src/declarative/qml/qdeclarativewatcher.cpp187
-rw-r--r--src/declarative/qml/qdeclarativewatcher_p.h94
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript.cpp753
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript_p.h129
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp1740
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest_p.h71
-rw-r--r--src/declarative/qml/qmetaobjectbuilder.cpp2544
-rw-r--r--src/declarative/qml/qmetaobjectbuilder_p.h321
-rw-r--r--src/declarative/qml/qml.pri141
-rw-r--r--src/declarative/qml/qperformancetimer.cpp226
-rw-r--r--src/declarative/qml/qperformancetimer_p.h79
-rw-r--r--src/declarative/qml/qpodvector_p.h173
-rw-r--r--src/declarative/qml/rewriter/rewriter.pri4
-rw-r--r--src/declarative/qml/rewriter/textwriter.cpp217
-rw-r--r--src/declarative/qml/rewriter/textwriter_p.h101
-rw-r--r--src/declarative/util/qdeclarativeanimation.cpp2948
-rw-r--r--src/declarative/util/qdeclarativeanimation_p.h528
-rw-r--r--src/declarative/util/qdeclarativeanimation_p_p.h397
-rw-r--r--src/declarative/util/qdeclarativeapplication.cpp112
-rw-r--r--src/declarative/util/qdeclarativeapplication_p.h86
-rw-r--r--src/declarative/util/qdeclarativebehavior.cpp230
-rw-r--r--src/declarative/util/qdeclarativebehavior_p.h98
-rw-r--r--src/declarative/util/qdeclarativebind.cpp213
-rw-r--r--src/declarative/util/qdeclarativebind_p.h96
-rw-r--r--src/declarative/util/qdeclarativeconnections.cpp289
-rw-r--r--src/declarative/util/qdeclarativeconnections_p.h103
-rw-r--r--src/declarative/util/qdeclarativefontloader.cpp338
-rw-r--r--src/declarative/util/qdeclarativefontloader_p.h97
-rw-r--r--src/declarative/util/qdeclarativelistaccessor.cpp138
-rw-r--r--src/declarative/util/qdeclarativelistaccessor_p.h80
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp1627
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p.h158
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p_p.h281
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp278
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent_p.h163
-rw-r--r--src/declarative/util/qdeclarativenullablevalue_p_p.h81
-rw-r--r--src/declarative/util/qdeclarativeopenmetaobject.cpp380
-rw-r--r--src/declarative/util/qdeclarativeopenmetaobject_p.h129
-rw-r--r--src/declarative/util/qdeclarativepackage.cpp201
-rw-r--r--src/declarative/util/qdeclarativepackage_p.h98
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp1080
-rw-r--r--src/declarative/util/qdeclarativepixmapcache_p.h122
-rw-r--r--src/declarative/util/qdeclarativepropertychanges.cpp797
-rw-r--r--src/declarative/util/qdeclarativepropertychanges_p.h112
-rw-r--r--src/declarative/util/qdeclarativepropertymap.cpp296
-rw-r--r--src/declarative/util/qdeclarativepropertymap.h90
-rw-r--r--src/declarative/util/qdeclarativesmoothedanimation.cpp493
-rw-r--r--src/declarative/util/qdeclarativesmoothedanimation_p.h103
-rw-r--r--src/declarative/util/qdeclarativesmoothedanimation_p_p.h135
-rw-r--r--src/declarative/util/qdeclarativespringanimation.cpp462
-rw-r--r--src/declarative/util/qdeclarativespringanimation_p.h111
-rw-r--r--src/declarative/util/qdeclarativestate.cpp730
-rw-r--r--src/declarative/util/qdeclarativestate_p.h210
-rw-r--r--src/declarative/util/qdeclarativestate_p_p.h253
-rw-r--r--src/declarative/util/qdeclarativestategroup.cpp469
-rw-r--r--src/declarative/util/qdeclarativestategroup_p.h95
-rw-r--r--src/declarative/util/qdeclarativestateoperations.cpp1587
-rw-r--r--src/declarative/util/qdeclarativestateoperations_p.h299
-rw-r--r--src/declarative/util/qdeclarativestyledtext.cpp347
-rw-r--r--src/declarative/util/qdeclarativestyledtext_p.h69
-rw-r--r--src/declarative/util/qdeclarativesystempalette.cpp312
-rw-r--r--src/declarative/util/qdeclarativesystempalette_p.h122
-rw-r--r--src/declarative/util/qdeclarativetimeline.cpp947
-rw-r--r--src/declarative/util/qdeclarativetimeline_p_p.h200
-rw-r--r--src/declarative/util/qdeclarativetimer.cpp324
-rw-r--r--src/declarative/util/qdeclarativetimer_p.h115
-rw-r--r--src/declarative/util/qdeclarativetransition.cpp317
-rw-r--r--src/declarative/util/qdeclarativetransition_p.h106
-rw-r--r--src/declarative/util/qdeclarativetransitionmanager.cpp276
-rw-r--r--src/declarative/util/qdeclarativetransitionmanager_p_p.h85
-rw-r--r--src/declarative/util/qdeclarativeutilmodule.cpp174
-rw-r--r--src/declarative/util/qdeclarativeutilmodule_p.h63
-rw-r--r--src/declarative/util/qdeclarativeview.cpp734
-rw-r--r--src/declarative/util/qdeclarativeview.h118
-rw-r--r--src/declarative/util/qdeclarativexmllistmodel.cpp1050
-rw-r--r--src/declarative/util/qdeclarativexmllistmodel_p.h213
-rw-r--r--src/declarative/util/qlistmodelinterface.cpp105
-rw-r--r--src/declarative/util/qlistmodelinterface_p.h84
-rw-r--r--src/declarative/util/util.pri72
325 files changed, 130250 insertions, 0 deletions
diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt
new file mode 100644
index 0000000000..6e073305b5
--- /dev/null
+++ b/src/declarative/QmlChanges.txt
@@ -0,0 +1,364 @@
+=============================================================================
+The changes below are pre Qt 4.7.0 RC1
+
+TextInput
+ - copy(), cut() and paste() functions added
+Font.letterSpacing
+ - was percentage based. Now specified in pixels.
+Item
+ - wantsFocus renamed to activeFocus
+ - forceFocus() renamed to forceActiveFocus()
+ - focus now returns the scoped focus (i.e. focus read/write now manipulate
+ the same value)
+TextInput and TextEdit:
+ - focusOnPress renamed to activeFocusOnPress
+
+=============================================================================
+The changes below are pre Qt 4.7.0 beta 2
+
+QDeclarativeView
+ - initialSize() function added
+TextInput and TextEdit:
+ - openSoftwareInputPanel() and closeSoftwareInputPanel() functions added
+Flickable:
+ - overShoot is replaced by boundsBehavior enumeration
+ - flickingHorizontally and flickingVertically properties added
+ - movingHorizontally and movingVertically properties added
+ - flickDirection is renamed flickableDirection
+Component:
+ - isReady, isLoading, isError and isNull properties removed, use
+ status property instead
+ - errorsString() renamed to errorString()
+ListView:
+ - ListView.prevSection property changed to ListView.previousSection
+TextInput:
+ - xToPosition -> positionAt (to match TextEdit.positionAt)
+Image:
+ - pixmap property removed, use QDeclarativeImageProvider to serve pixmaps
+ instead
+
+QList<QObject*> models no longer provide properties in model object. The
+properties are now updated when the object changes. An object's property
+"foo" may now be accessed as "foo", modelData.foo" or model.modelData.foo"
+component.createObject has gained a mandatory "parent" argument
+TextEdit and TextInput now have a "selectByMouse" property that defaults to false.
+
+C++ API
+-------
+QDeclarativeExpression::value() has been renamed to
+QDeclarativeExpression::evaluate()
+
+The QDeclarativeExpression constructor has changed from
+ QDeclarativeExpression(context, expression, scope)
+to
+ QDeclarativeExpression(context, scope, expression, parent = 0)
+
+QDeclarativeImageProvider::request() has been renamed to
+QDeclarativeImageProvider::image() and the class can now provide
+both qimages and qpixmaps, and qimages can be served synchronously
+
+QML Viewer
+------------
+The standalone qml executable has been renamed back to Qml Viewer. Runtime warnings
+can be now accessed via the menu (Debugging->Show Warnings).
+
+=============================================================================
+The changes below are pre Qt 4.7.0 beta 1
+
+TextEdit: wrap property is replaced by wrapMode enumeration.
+Text: wrap property is replaced by wrapMode enumeration.
+Removed Q-prefix from validators (IntValidator, DoubleValidator, and RegExpValidator)
+PathView: offset property now uses range 0-1.0 rather than 0-100
+ListView, GridView::positionViewAtIndex() gained a 'mode' parameter
+Removed Qt.playSound (replaced by SoundEffect element)
+Removed Qt.closestAngle (use RotationAnimation instead)
+Removed NumberFormatter
+Removed DateTimeFormatter (use Qt.formatDateTime() instead)
+Using WebView now requires "import QtWebKit 1.0"
+Using Particles now requires "import Qt.labs.particles 1.0"
+AnchorAnimation must now be used to animate anchor changes (and not NumberAnimation)
+Removed ParentAction (use ParentAnimation instead)
+ScriptAction: renamed stateChangeScriptName -> scriptName
+Animation: replace repeat with loops (loops: Animation.Infinite gives the old repeat behavior)
+AnchorChanges: use natural form to specify anchors (anchors.left instead of left)
+AnchorChanges: removed reset property. (reset: "left" should now be anchors.left: undefined)
+PathView: snapPosition replaced by preferredHighlightBegin, preferredHighlightEnd
+createQmlObject: Moved to the Qt object, now use Qt.createQmlObject()
+createComponent: Moved to the Qt object, now use Qt.createComponent()
+
+C++ API
+-------
+QDeclarativeContext::addDefaultObject() has been replaced with
+QDeclarativeContext::setContextObject()
+
+Behavior and Animation syntax
+-----------------------------
+Previously animations and behaviors could be "assigned" to properties like this:
+ Item { x: Behavior {}; y: NumberAnimation {} }
+To make it more obvious that these are not regular value assignments a new "on"
+syntax has been introduced:
+ Item { Behavior on x {}; NumberAnimation on y {} }
+Only the syntax has changed, the behavior is identical.
+
+EaseFollow renamed to SmoothedFollow
+---------------------------------------
+This element shares the internal implementation with SmoothedAnimation,
+both providing the same easing function, but with SmoothedFollow it's
+easier to set a start value to animate intially and then start to follow,
+while SmoothedAnimation is still convenient for using inside Behaviors
+and Transitions.
+
+
+Add SmoothedAnimation element
+---------------------------------------
+SmoothedAnimation inherits from NumberAnimaton and as a
+consequence SmoothedAnimation can be used inside Behaviors,
+as PropertySourceValues or in state transitions, like any other animation.
+
+The old EaseFollow properties changed to comply with the other declarative
+animations ('source' changed to 'to'), so now 'to' changes are not
+automatically 'followed' anymore.
+
+If you want to follow an hypothetical rect1, you should do now:
+
+ Rectangle {
+ color: "green"
+ width: 60; height: 60;
+ x: rect1.x - 5; y: rect1.y - 5;
+ Behavior on x { SmoothedAnimation { velocity: 200 } }
+ Behavior on y { SmoothedAnimation { velocity: 200 } }
+ }
+
+instead of the old automatic source changed tracking:
+
+ Rectangle {
+ color: "green"
+ width: 60; height: 60;
+ EaseFollow on x { source: rect1.x - 5; velocity: 200 }
+ EaseFollow on y { source: rect1.y - 5; velocity: 200 }
+ }
+
+This is a syntax and behavior change.
+
+
+Script element removed
+----------------------
+Inline Script{} blocks have been deprecated, and will soon be removed entirely.
+If you used Script to write inline javascript code, it can simply be removed.
+For example
+
+Item {
+ Script {
+ function doSomething() {}
+ }
+}
+
+becomes
+
+Item {
+ function doSomething() {}
+}
+
+If you used Script to include external JavaScript files, you can replace the
+Script element with an “import” line. For example
+
+MouseArea {
+ Script {
+ source: “foo.js”
+ }
+ onClicked: foo()
+}
+
+becomes
+
+import “foo.js” as Foo
+MouseArea {
+ onClicked: Foo.foo()
+}
+
+The “as” qualifier is mandatory for script imports (as opposed to type
+imports where it is optional).
+
+
+=============================================================================
+The changes below are pre Qt 4.7.0 alpha
+
+Flickable: renamed viewportWidth -> contentWidth
+Flickable: renamed viewportHeight -> contentHeight
+Flickable: renamed viewportX -> contentX
+Flickable: renamed viewportY -> contentY
+Removed Flickable.reportedVelocitySmoothing
+Renamed MouseRegion -> MouseArea
+Connection: syntax and rename:
+ Connection { sender: a; signal: foo(); script: xxx }
+ Connection { sender: a; signal: bar(); script: yyy }
+ becomes:
+ Connections { target: a; onFoo: xxx; onBar: yyy }
+
+ListView::sectionExpression has been replaced by section.property, section.criteria
+
+ListModel
+---------
+- types are strictly checked (previously, everything was a string)
+ - foo: "bar" continues to work as before
+ - foo: bar is now invalid, use foo: "bar"
+ - foo: true is now a bool (not string "true")
+ - foo: false is now a bool (not string "false" == true!)
+
+PropertyAnimation
+------------------
+matchProperties and matchTargets have been renamed back to properties and targets.
+The semantics are explained in the PropertyAnimation::properties documentation
+and the animation overview documentation.
+
+Easing curves and their parameters are now specified via dot properties:
+* easing.type : enum
+* easing.amplitude : real
+* easing.overshoot : real
+* easing.period : real
+For example:
+PropertyAnimation { properties: "y"; easing.type: "InOutElastic"; easing.amplitude: 2.0; easing.period: 1.5 }
+
+C++ API
+-------
+QML_DEFINE_... definition macros, previously global macros, are replaced by
+qmlRegisterType registration functions, which must be called explicitly.
+C++ API users should also consider using the QmlExtensionPlugin (previously
+named QmlModulePlugin) as a cleaner mechanism for publishing libraries of QML
+types, or the upcoming application plugin features of the qmlviewer /
+qmlruntime / qml.
+
+QmlView
+-------
+The API of QmlView has been narrowed and its role as a convenience class
+reinforced.
+- remove addItem()
+- remove clearItems() - use 'delete root()'
+- remove reset()
+- resizeContent -> enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView }
+- remove setQml(), qml()
+- rename setUrl(), ur() to setSource(), source()
+- root() -> rootObject(), returns QGraphicsObject rather than QmlGraphicsItem
+- remove quit() signal -> use quit() signal of engine()
+- initialSize() signal removed
+- Added status() to determine status of the internal QmlComponent
+- removed execute() - setSource() will also execute the QML.
+
+
+=============================================================================
+The changes below are pre-4.6.0 release.
+
+QML API Review
+==============
+
+The QML API is being reviewed. This file documents the changes.
+Note that the changes are incremental, so a rename A->B for example may be followed
+by another subsequent rename B->C, if later reviews override earlier reviews.
+
+API Changes
+===========
+
+Renamed Elements:
+LineEdit -> TextInput
+VerticalLayout -> Column
+HorizontalLayout -> Row
+VerticalPositioner -> Column
+HorizontalPositioner -> Row
+GridLayout -> Grid
+GridPositioner -> Grid
+Rect -> Rectangle
+FocusRealm -> FocusScope
+FontFamily -> FontLoader
+Palette -> SystemPalette
+Bind -> Binding
+SetProperties -> PropertyChanges
+RunScript -> StateChangeScript
+SetAnchors -> AnchorChanges
+SetPropertyAction -> PropertyAction
+RunScriptAction -> ScriptAction
+ParentChangeAction -> ParentAction
+VisualModel -> VisualDataModel
+Follow -> SpringFollow
+
+Renamed properties:
+Item: contents -> childrenRect
+MouseRegion: xmin -> minimumX
+MouseRegion: xmax -> maximumX
+MouseRegion: ymin -> minimumY
+MouseRegion: ymin -> maximumY
+Text elements: hAlign -> horizontalAlignment
+Text elements: vAlign -> verticalAlignment
+Text elements: highlightColor -> selectionColor
+Text elements: highlightedTextColor -> selectedTextColor
+Text elements: preserveSelection -> persistentSelection
+State: operations -> changes
+Transition: operations -> animations
+Transition: fromState -> from
+Transition: toState -> to
+Follow: followValue -> value
+Flickable: xPosition -> viewportX
+Flickable: yPosition -> viewportY
+Flickable: xVelocity -> horizontalVelocity
+Flickable: yVelocity -> verticalVelocity
+Flickable: velocityDecay -> reportedVelocitySmoothing
+Flickable: locked -> interactive (note reversal of meaning)
+Flickable: pageXPosition -> visibleArea.xPosition
+Flickable: pageYPosition -> visibleArea.yPosition
+Flickable: pageWidth -> visibleArea.widthRatio
+Flickable: pageHeight -> visibleArea.heightRatio
+WebView: idealWidth -> preferredWidth
+WebView: idealHeight -> preferredHeight
+WebView: status -> statusText
+WebView: mouseX -> clickX (parameter to onDoubleClick)
+WebView: mouseY -> clickY (parameter to onDoubleClick)
+WebView: cacheSize -> pixelCacheSize
+Repeater: component -> delegate
+Repeater: dataSource -> model
+ListView: current -> currentItem
+GridView: current -> currentItem
+ListView: wrap -> keyNavigationWraps
+ListView: autoHighlight -> highlightFollowsCurrentItem
+GridView: wrap -> keyNavigationWraps
+GridView: autoHighlight -> highlightFollowsCurrentItem
+Animation: targets -> matchTargets
+Animation: properties -> matchProperties
+
+Additions:
+MouseRegion: add "acceptedButtons" property
+MouseRegion: add "hoverEnabled" property
+MouseRegion: add "pressedButtons" property
+Timer: add start() and stop() slots
+WebView: add newWindowComponent and newWindowParent properties
+Loader: add status() and progress() properties
+Loader: add sourceComponent property
+Loader: add resizeMode property
+ListView: preferredHighlightBegin, preferredHighlightEnd
+ListView: strictlyEnforceHighlightRange
+Particles: Added emissionRate, emissionVariance and burst()
+
+Deletions:
+Column/VerticalPositioner: lost "margins" property
+Row/HorizontalPositioner: lost "margins" property
+Grid/Positioner/Layout: lost "margins" property
+WebView: lost "interactive" property (always true now)
+Flickable: removed "dragMode" property
+ComponentInstance: removed. Replaced by Loader.sourceComponent
+ListView: removed currentItemMode. Replaced by highligh range.
+ListView: removed snapPos.
+Particles: removed streamIn. Replaced by emissionRate
+
+Other Changes:
+ids must be lowercase: Text { id: foo }, not Text { id: Foo }
+Drag: axis becomes an enum with values "XAxis", "YAxis", "XandYAxis"
+Image: scaleGrid property removed. New item called BorderImage instead.
+KeyActions: changed to a Keys attached property on any item.
+KeyProxy: changed to a Keys.forwardTo property on any item.
+Script: now an intrinsic type in the language
+ - cannot be assigned to properties
+ - good: Item { Script { ... } }
+ - bad: Item { resources: Script { ... } }
+Script: delay-loaded of the QML file until their source has been loaded (this only effects QML files loaded across the network.)
+Scope: declared properties shadow a property of the same name (was previously the reverse)
+ScriptAction and StateChangeScript: the script property now takes script rather than a string containing script (script: doSomething() rather than script: "doSomething()")
+QmlGraphicsItem::transformOrigin default changed from TopLeft to Center
+Animations used as PropertySourceValues are set to 'running: true' as default
diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri
new file mode 100644
index 0000000000..75287b4563
--- /dev/null
+++ b/src/declarative/debugger/debugger.pri
@@ -0,0 +1,23 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qdeclarativedebuggerstatus.cpp \
+ $$PWD/qpacketprotocol.cpp \
+ $$PWD/qdeclarativedebugservice.cpp \
+ $$PWD/qdeclarativedebugclient.cpp \
+ $$PWD/qdeclarativedebug.cpp \
+ $$PWD/qdeclarativedebugtrace.cpp \
+ $$PWD/qdeclarativedebughelper.cpp \
+ $$PWD/qdeclarativedebugserver.cpp
+
+HEADERS += \
+ $$PWD/qdeclarativedebuggerstatus_p.h \
+ $$PWD/qpacketprotocol_p.h \
+ $$PWD/qdeclarativedebugservice_p.h \
+ $$PWD/qdeclarativedebugservice_p_p.h \
+ $$PWD/qdeclarativedebugclient_p.h \
+ $$PWD/qdeclarativedebug_p.h \
+ $$PWD/qdeclarativedebugtrace_p.h \
+ $$PWD/qdeclarativedebughelper_p.h \
+ $$PWD/qdeclarativedebugserver_p.h \
+ debugger/qdeclarativedebugserverconnection_p.h
diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp
new file mode 100644
index 0000000000..62eb8fea3e
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebug.cpp
@@ -0,0 +1,1021 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativedebug_p.h"
+
+#include "private/qdeclarativedebugclient_p.h"
+
+#include <qdeclarativeenginedebug_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngineDebugClient : public QDeclarativeDebugClient
+{
+public:
+ QDeclarativeEngineDebugClient(QDeclarativeDebugConnection *client, QDeclarativeEngineDebugPrivate *p);
+
+protected:
+ virtual void statusChanged(Status status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ QDeclarativeEngineDebugPrivate *priv;
+ friend class QDeclarativeEngineDebugPrivate;
+};
+
+class QDeclarativeEngineDebugPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeEngineDebug)
+public:
+ QDeclarativeEngineDebugPrivate(QDeclarativeDebugConnection *);
+ ~QDeclarativeEngineDebugPrivate();
+
+ void statusChanged(QDeclarativeEngineDebug::Status status);
+ void message(const QByteArray &);
+
+ QDeclarativeEngineDebugClient *client;
+ int nextId;
+ int getId();
+
+ void decode(QDataStream &, QDeclarativeDebugContextReference &);
+ void decode(QDataStream &, QDeclarativeDebugObjectReference &, bool simple);
+
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugEnginesQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugRootContextQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugObjectQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugExpressionQuery *);
+
+ QHash<int, QDeclarativeDebugEnginesQuery *> enginesQuery;
+ QHash<int, QDeclarativeDebugRootContextQuery *> rootContextQuery;
+ QHash<int, QDeclarativeDebugObjectQuery *> objectQuery;
+ QHash<int, QDeclarativeDebugExpressionQuery *> expressionQuery;
+
+ QHash<int, QDeclarativeDebugWatch *> watched;
+};
+
+QDeclarativeEngineDebugClient::QDeclarativeEngineDebugClient(QDeclarativeDebugConnection *client,
+ QDeclarativeEngineDebugPrivate *p)
+: QDeclarativeDebugClient(QLatin1String("QDeclarativeEngine"), client), priv(p)
+{
+}
+
+void QDeclarativeEngineDebugClient::statusChanged(Status status)
+{
+ if (priv)
+ priv->statusChanged(static_cast<QDeclarativeEngineDebug::Status>(status));
+}
+
+void QDeclarativeEngineDebugClient::messageReceived(const QByteArray &data)
+{
+ if (priv)
+ priv->message(data);
+}
+
+QDeclarativeEngineDebugPrivate::QDeclarativeEngineDebugPrivate(QDeclarativeDebugConnection *c)
+: client(new QDeclarativeEngineDebugClient(c, this)), nextId(0)
+{
+}
+
+QDeclarativeEngineDebugPrivate::~QDeclarativeEngineDebugPrivate()
+{
+ if (client)
+ client->priv = 0;
+}
+
+int QDeclarativeEngineDebugPrivate::getId()
+{
+ return nextId++;
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugEnginesQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->enginesQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c,
+ QDeclarativeDebugRootContextQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->rootContextQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugObjectQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->objectQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugExpressionQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->expressionQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugObjectReference &o,
+ bool simple)
+{
+ QDeclarativeEngineDebugServer::QDeclarativeObjectData data;
+ ds >> data;
+ o.m_debugId = data.objectId;
+ o.m_class = data.objectType;
+ o.m_idString = data.idString;
+ o.m_name = data.objectName;
+ o.m_source.m_url = data.url;
+ o.m_source.m_lineNumber = data.lineNumber;
+ o.m_source.m_columnNumber = data.columnNumber;
+ o.m_contextDebugId = data.contextId;
+
+ if (simple)
+ return;
+
+ int childCount;
+ bool recur;
+ ds >> childCount >> recur;
+
+ for (int ii = 0; ii < childCount; ++ii) {
+ o.m_children.append(QDeclarativeDebugObjectReference());
+ decode(ds, o.m_children.last(), !recur);
+ }
+
+ int propCount;
+ ds >> propCount;
+
+ for (int ii = 0; ii < propCount; ++ii) {
+ QDeclarativeEngineDebugServer::QDeclarativeObjectProperty data;
+ ds >> data;
+ QDeclarativeDebugPropertyReference prop;
+ prop.m_objectDebugId = o.m_debugId;
+ prop.m_name = data.name;
+ prop.m_binding = data.binding;
+ prop.m_hasNotifySignal = data.hasNotifySignal;
+ prop.m_valueTypeName = data.valueTypeName;
+ switch (data.type) {
+ case QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Basic:
+ case QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::List:
+ case QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::SignalProperty:
+ {
+ prop.m_value = data.value;
+ break;
+ }
+ case QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Object:
+ {
+ QDeclarativeDebugObjectReference obj;
+ obj.m_debugId = prop.m_value.toInt();
+ prop.m_value = QVariant::fromValue(obj);
+ break;
+ }
+ case QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Unknown:
+ break;
+ }
+ o.m_properties << prop;
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugContextReference &c)
+{
+ ds >> c.m_name >> c.m_debugId;
+
+ int contextCount;
+ ds >> contextCount;
+
+ for (int ii = 0; ii < contextCount; ++ii) {
+ c.m_contexts.append(QDeclarativeDebugContextReference());
+ decode(ds, c.m_contexts.last());
+ }
+
+ int objectCount;
+ ds >> objectCount;
+
+ for (int ii = 0; ii < objectCount; ++ii) {
+ QDeclarativeDebugObjectReference obj;
+ decode(ds, obj, true);
+
+ obj.m_contextDebugId = c.m_debugId;
+ c.m_objects << obj;
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::statusChanged(QDeclarativeEngineDebug::Status status)
+{
+ emit q_func()->statusChanged(status);
+}
+
+void QDeclarativeEngineDebugPrivate::message(const QByteArray &data)
+{
+ QDataStream ds(data);
+
+ QByteArray type;
+ ds >> type;
+
+ //qDebug() << "QDeclarativeEngineDebugPrivate::message()" << type;
+
+ if (type == "LIST_ENGINES_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugEnginesQuery *query = enginesQuery.value(queryId);
+ if (!query)
+ return;
+ enginesQuery.remove(queryId);
+
+ int count;
+ ds >> count;
+
+ for (int ii = 0; ii < count; ++ii) {
+ QDeclarativeDebugEngineReference ref;
+ ds >> ref.m_name;
+ ds >> ref.m_debugId;
+ query->m_engines << ref;
+ }
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "LIST_OBJECTS_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugRootContextQuery *query = rootContextQuery.value(queryId);
+ if (!query)
+ return;
+ rootContextQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_context);
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "FETCH_OBJECT_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugObjectQuery *query = objectQuery.value(queryId);
+ if (!query)
+ return;
+ objectQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_object, false);
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "EVAL_EXPRESSION_R") {
+ int queryId;
+ QVariant result;
+ ds >> queryId >> result;
+
+ QDeclarativeDebugExpressionQuery *query = expressionQuery.value(queryId);
+ if (!query)
+ return;
+ expressionQuery.remove(queryId);
+
+ query->m_result = result;
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "WATCH_PROPERTY_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "WATCH_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "WATCH_EXPR_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "UPDATE_WATCH") {
+ int queryId;
+ int debugId;
+ QByteArray name;
+ QVariant value;
+ ds >> queryId >> debugId >> name >> value;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId, 0);
+ if (!watch)
+ return;
+ emit watch->valueChanged(name, value);
+ } else if (type == "OBJECT_CREATED") {
+ emit q_func()->newObjects();
+ }
+}
+
+QDeclarativeEngineDebug::QDeclarativeEngineDebug(QDeclarativeDebugConnection *client, QObject *parent)
+: QObject(*(new QDeclarativeEngineDebugPrivate(client)), parent)
+{
+}
+
+QDeclarativeEngineDebug::Status QDeclarativeEngineDebug::status() const
+{
+ Q_D(const QDeclarativeEngineDebug);
+
+ return static_cast<QDeclarativeEngineDebug::Status>(d->client->status());
+}
+
+QDeclarativeDebugPropertyWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugPropertyReference &property, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugPropertyWatch *watch = new QDeclarativeDebugPropertyWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = property.objectDebugId();
+ watch->m_name = property.name();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_PROPERTY") << queryId << property.objectDebugId() << property.name().toUtf8();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugContextReference &, const QString &, QObject *)
+{
+ qWarning("QDeclarativeEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+QDeclarativeDebugObjectExpressionWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugObjectReference &object, const QString &expr, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+ QDeclarativeDebugObjectExpressionWatch *watch = new QDeclarativeDebugObjectExpressionWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ watch->m_expr = expr;
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_EXPR_OBJECT") << queryId << object.debugId() << expr;
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugWatch *watch = new QDeclarativeDebugWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_OBJECT") << queryId << object.debugId();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugFileReference &, QObject *)
+{
+ qWarning("QDeclarativeEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+void QDeclarativeEngineDebug::removeWatch(QDeclarativeDebugWatch *watch)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (!watch || !watch->m_client)
+ return;
+
+ watch->m_client = 0;
+ watch->setState(QDeclarativeDebugWatch::Inactive);
+
+ d->watched.remove(watch->queryId());
+
+ if (d->client && d->client->status() == QDeclarativeDebugClient::Enabled) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("NO_WATCH") << watch->queryId();
+ d->client->sendMessage(message);
+ }
+}
+
+QDeclarativeDebugEnginesQuery *QDeclarativeEngineDebug::queryAvailableEngines(QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugEnginesQuery *query = new QDeclarativeDebugEnginesQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->enginesQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_ENGINES") << queryId;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugRootContextQuery *QDeclarativeEngineDebug::queryRootContexts(const QDeclarativeDebugEngineReference &engine, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugRootContextQuery *query = new QDeclarativeDebugRootContextQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && engine.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->rootContextQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_OBJECTS") << queryId << engine.debugId();
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObject(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugObjectQuery *query = new QDeclarativeDebugObjectQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << false << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObjectRecursive(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugObjectQuery *query = new QDeclarativeDebugObjectQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << true << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugExpressionQuery *QDeclarativeEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugExpressionQuery *query = new QDeclarativeDebugExpressionQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ query->m_client = this;
+ query->m_expr = expr;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->expressionQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("EVAL_EXPRESSION") << queryId << objectDebugId << expr;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+bool QDeclarativeEngineDebug::setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression,
+ bool isLiteralValue)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_BINDING") << objectDebugId << propertyName << bindingExpression << isLiteralValue;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativeEngineDebug::resetBindingForObject(int objectDebugId, const QString &propertyName)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("RESET_BINDING") << objectDebugId << propertyName;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativeEngineDebug::setMethodBody(int objectDebugId, const QString &methodName,
+ const QString &methodBody)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_METHOD_BODY") << objectDebugId << methodName << methodBody;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent)
+: QObject(parent), m_state(Waiting), m_queryId(-1), m_client(0), m_objectDebugId(-1)
+{
+}
+
+QDeclarativeDebugWatch::~QDeclarativeDebugWatch()
+{
+}
+
+int QDeclarativeDebugWatch::queryId() const
+{
+ return m_queryId;
+}
+
+int QDeclarativeDebugWatch::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QDeclarativeDebugWatch::State QDeclarativeDebugWatch::state() const
+{
+ return m_state;
+}
+
+void QDeclarativeDebugWatch::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QDeclarativeDebugPropertyWatch::QDeclarativeDebugPropertyWatch(QObject *parent)
+ : QDeclarativeDebugWatch(parent)
+{
+}
+
+QString QDeclarativeDebugPropertyWatch::name() const
+{
+ return m_name;
+}
+
+
+QDeclarativeDebugObjectExpressionWatch::QDeclarativeDebugObjectExpressionWatch(QObject *parent)
+ : QDeclarativeDebugWatch(parent)
+{
+}
+
+QString QDeclarativeDebugObjectExpressionWatch::expression() const
+{
+ return m_expr;
+}
+
+
+QDeclarativeDebugQuery::QDeclarativeDebugQuery(QObject *parent)
+: QObject(parent), m_state(Waiting)
+{
+}
+
+QDeclarativeDebugQuery::State QDeclarativeDebugQuery::state() const
+{
+ return m_state;
+}
+
+bool QDeclarativeDebugQuery::isWaiting() const
+{
+ return m_state == Waiting;
+}
+
+void QDeclarativeDebugQuery::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QDeclarativeDebugEnginesQuery::QDeclarativeDebugEnginesQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugEnginesQuery::~QDeclarativeDebugEnginesQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QList<QDeclarativeDebugEngineReference> QDeclarativeDebugEnginesQuery::engines() const
+{
+ return m_engines;
+}
+
+QDeclarativeDebugRootContextQuery::QDeclarativeDebugRootContextQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugRootContextQuery::~QDeclarativeDebugRootContextQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QDeclarativeDebugContextReference QDeclarativeDebugRootContextQuery::rootContext() const
+{
+ return m_context;
+}
+
+QDeclarativeDebugObjectQuery::QDeclarativeDebugObjectQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugObjectQuery::~QDeclarativeDebugObjectQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QDeclarativeDebugObjectReference QDeclarativeDebugObjectQuery::object() const
+{
+ return m_object;
+}
+
+QDeclarativeDebugExpressionQuery::QDeclarativeDebugExpressionQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugExpressionQuery::~QDeclarativeDebugExpressionQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QVariant QDeclarativeDebugExpressionQuery::expression() const
+{
+ return m_expr;
+}
+
+QVariant QDeclarativeDebugExpressionQuery::result() const
+{
+ return m_result;
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference()
+: m_debugId(-1)
+{
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference(int debugId)
+: m_debugId(debugId)
+{
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference(const QDeclarativeDebugEngineReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name)
+{
+}
+
+QDeclarativeDebugEngineReference &
+QDeclarativeDebugEngineReference::operator=(const QDeclarativeDebugEngineReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name;
+ return *this;
+}
+
+int QDeclarativeDebugEngineReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugEngineReference::name() const
+{
+ return m_name;
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference()
+: m_debugId(-1), m_contextDebugId(-1)
+{
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference(int debugId)
+: m_debugId(debugId), m_contextDebugId(-1)
+{
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference(const QDeclarativeDebugObjectReference &o)
+: m_debugId(o.m_debugId), m_class(o.m_class), m_idString(o.m_idString),
+ m_name(o.m_name), m_source(o.m_source), m_contextDebugId(o.m_contextDebugId),
+ m_properties(o.m_properties), m_children(o.m_children)
+{
+}
+
+QDeclarativeDebugObjectReference &
+QDeclarativeDebugObjectReference::operator=(const QDeclarativeDebugObjectReference &o)
+{
+ m_debugId = o.m_debugId; m_class = o.m_class; m_idString = o.m_idString;
+ m_name = o.m_name; m_source = o.m_source; m_contextDebugId = o.m_contextDebugId;
+ m_properties = o.m_properties; m_children = o.m_children;
+ return *this;
+}
+
+int QDeclarativeDebugObjectReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugObjectReference::className() const
+{
+ return m_class;
+}
+
+QString QDeclarativeDebugObjectReference::idString() const
+{
+ return m_idString;
+}
+
+QString QDeclarativeDebugObjectReference::name() const
+{
+ return m_name;
+}
+
+QDeclarativeDebugFileReference QDeclarativeDebugObjectReference::source() const
+{
+ return m_source;
+}
+
+int QDeclarativeDebugObjectReference::contextDebugId() const
+{
+ return m_contextDebugId;
+}
+
+QList<QDeclarativeDebugPropertyReference> QDeclarativeDebugObjectReference::properties() const
+{
+ return m_properties;
+}
+
+QList<QDeclarativeDebugObjectReference> QDeclarativeDebugObjectReference::children() const
+{
+ return m_children;
+}
+
+QDeclarativeDebugContextReference::QDeclarativeDebugContextReference()
+: m_debugId(-1)
+{
+}
+
+QDeclarativeDebugContextReference::QDeclarativeDebugContextReference(const QDeclarativeDebugContextReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name), m_objects(o.m_objects), m_contexts(o.m_contexts)
+{
+}
+
+QDeclarativeDebugContextReference &QDeclarativeDebugContextReference::operator=(const QDeclarativeDebugContextReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name; m_objects = o.m_objects;
+ m_contexts = o.m_contexts;
+ return *this;
+}
+
+int QDeclarativeDebugContextReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugContextReference::name() const
+{
+ return m_name;
+}
+
+QList<QDeclarativeDebugObjectReference> QDeclarativeDebugContextReference::objects() const
+{
+ return m_objects;
+}
+
+QList<QDeclarativeDebugContextReference> QDeclarativeDebugContextReference::contexts() const
+{
+ return m_contexts;
+}
+
+QDeclarativeDebugFileReference::QDeclarativeDebugFileReference()
+: m_lineNumber(-1), m_columnNumber(-1)
+{
+}
+
+QDeclarativeDebugFileReference::QDeclarativeDebugFileReference(const QDeclarativeDebugFileReference &o)
+: m_url(o.m_url), m_lineNumber(o.m_lineNumber), m_columnNumber(o.m_columnNumber)
+{
+}
+
+QDeclarativeDebugFileReference &QDeclarativeDebugFileReference::operator=(const QDeclarativeDebugFileReference &o)
+{
+ m_url = o.m_url; m_lineNumber = o.m_lineNumber; m_columnNumber = o.m_columnNumber;
+ return *this;
+}
+
+QUrl QDeclarativeDebugFileReference::url() const
+{
+ return m_url;
+}
+
+void QDeclarativeDebugFileReference::setUrl(const QUrl &u)
+{
+ m_url = u;
+}
+
+int QDeclarativeDebugFileReference::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void QDeclarativeDebugFileReference::setLineNumber(int l)
+{
+ m_lineNumber = l;
+}
+
+int QDeclarativeDebugFileReference::columnNumber() const
+{
+ return m_columnNumber;
+}
+
+void QDeclarativeDebugFileReference::setColumnNumber(int c)
+{
+ m_columnNumber = c;
+}
+
+QDeclarativeDebugPropertyReference::QDeclarativeDebugPropertyReference()
+: m_objectDebugId(-1), m_hasNotifySignal(false)
+{
+}
+
+QDeclarativeDebugPropertyReference::QDeclarativeDebugPropertyReference(const QDeclarativeDebugPropertyReference &o)
+: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value),
+ m_valueTypeName(o.m_valueTypeName), m_binding(o.m_binding),
+ m_hasNotifySignal(o.m_hasNotifySignal)
+{
+}
+
+QDeclarativeDebugPropertyReference &QDeclarativeDebugPropertyReference::operator=(const QDeclarativeDebugPropertyReference &o)
+{
+ m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value;
+ m_valueTypeName = o.m_valueTypeName; m_binding = o.m_binding;
+ m_hasNotifySignal = o.m_hasNotifySignal;
+ return *this;
+}
+
+int QDeclarativeDebugPropertyReference::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QString QDeclarativeDebugPropertyReference::name() const
+{
+ return m_name;
+}
+
+QString QDeclarativeDebugPropertyReference::valueTypeName() const
+{
+ return m_valueTypeName;
+}
+
+QVariant QDeclarativeDebugPropertyReference::value() const
+{
+ return m_value;
+}
+
+QString QDeclarativeDebugPropertyReference::binding() const
+{
+ return m_binding;
+}
+
+bool QDeclarativeDebugPropertyReference::hasNotifySignal() const
+{
+ return m_hasNotifySignal;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/debugger/qdeclarativedebug_p.h b/src/declarative/debugger/qdeclarativedebug_p.h
new file mode 100644
index 0000000000..58c8234555
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebug_p.h
@@ -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$
+**
+****************************************************************************/
+#ifndef QDECLARATIVEDEBUG_H
+#define QDECLARATIVEDEBUG_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugConnection;
+class QDeclarativeDebugWatch;
+class QDeclarativeDebugPropertyWatch;
+class QDeclarativeDebugObjectExpressionWatch;
+class QDeclarativeDebugEnginesQuery;
+class QDeclarativeDebugRootContextQuery;
+class QDeclarativeDebugObjectQuery;
+class QDeclarativeDebugExpressionQuery;
+class QDeclarativeDebugPropertyReference;
+class QDeclarativeDebugContextReference;
+class QDeclarativeDebugObjectReference;
+class QDeclarativeDebugFileReference;
+class QDeclarativeDebugEngineReference;
+class QDeclarativeEngineDebugPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeEngineDebug : public QObject
+{
+Q_OBJECT
+public:
+ enum Status { NotConnected, Unavailable, Enabled };
+
+ explicit QDeclarativeEngineDebug(QDeclarativeDebugConnection *, QObject * = 0);
+
+ Status status() const;
+
+ QDeclarativeDebugPropertyWatch *addWatch(const QDeclarativeDebugPropertyReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugContextReference &, const QString &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectExpressionWatch *addWatch(const QDeclarativeDebugObjectReference &, const QString &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugFileReference &,
+ QObject *parent = 0);
+
+ void removeWatch(QDeclarativeDebugWatch *watch);
+
+ QDeclarativeDebugEnginesQuery *queryAvailableEngines(QObject *parent = 0);
+ QDeclarativeDebugRootContextQuery *queryRootContexts(const QDeclarativeDebugEngineReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectQuery *queryObject(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectQuery *queryObjectRecursive(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId,
+ const QString &expr,
+ QObject *parent = 0);
+ bool setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression, bool isLiteralValue);
+ bool resetBindingForObject(int objectDebugId, const QString &propertyName);
+ bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody);
+
+Q_SIGNALS:
+ void newObjects();
+ void statusChanged(Status status);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeEngineDebug)
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugWatch : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Active, Inactive, Dead };
+
+ QDeclarativeDebugWatch(QObject *);
+ ~QDeclarativeDebugWatch();
+
+ int queryId() const;
+ int objectDebugId() const;
+ State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QDeclarativeDebugWatch::State);
+ //void objectChanged(int, const QDeclarativeDebugObjectReference &);
+ //void valueChanged(int, const QVariant &);
+
+ // Server sends value as string if it is a user-type variant
+ void valueChanged(const QByteArray &name, const QVariant &value);
+
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+ int m_queryId;
+ QDeclarativeEngineDebug *m_client;
+ int m_objectDebugId;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugPropertyWatch : public QDeclarativeDebugWatch
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugPropertyWatch(QObject *parent);
+
+ QString name() const;
+
+private:
+ friend class QDeclarativeEngineDebug;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectExpressionWatch : public QDeclarativeDebugWatch
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugObjectExpressionWatch(QObject *parent);
+
+ QString expression() const;
+
+private:
+ friend class QDeclarativeEngineDebug;
+ QString m_expr;
+ int m_debugId;
+};
+
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugQuery : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Error, Completed };
+
+ State state() const;
+ bool isWaiting() const;
+
+// bool waitUntilCompleted();
+
+Q_SIGNALS:
+ void stateChanged(QDeclarativeDebugQuery::State);
+
+protected:
+ QDeclarativeDebugQuery(QObject *);
+
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugFileReference
+{
+public:
+ QDeclarativeDebugFileReference();
+ QDeclarativeDebugFileReference(const QDeclarativeDebugFileReference &);
+ QDeclarativeDebugFileReference &operator=(const QDeclarativeDebugFileReference &);
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ int lineNumber() const;
+ void setLineNumber(int);
+ int columnNumber() const;
+ void setColumnNumber(int);
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ QUrl m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugEngineReference
+{
+public:
+ QDeclarativeDebugEngineReference();
+ QDeclarativeDebugEngineReference(int);
+ QDeclarativeDebugEngineReference(const QDeclarativeDebugEngineReference &);
+ QDeclarativeDebugEngineReference &operator=(const QDeclarativeDebugEngineReference &);
+
+ int debugId() const;
+ QString name() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectReference
+{
+public:
+ QDeclarativeDebugObjectReference();
+ QDeclarativeDebugObjectReference(int);
+ QDeclarativeDebugObjectReference(const QDeclarativeDebugObjectReference &);
+ QDeclarativeDebugObjectReference &operator=(const QDeclarativeDebugObjectReference &);
+
+ int debugId() const;
+ QString className() const;
+ QString idString() const;
+ QString name() const;
+
+ QDeclarativeDebugFileReference source() const;
+ int contextDebugId() const;
+
+ QList<QDeclarativeDebugPropertyReference> properties() const;
+ QList<QDeclarativeDebugObjectReference> children() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_class;
+ QString m_idString;
+ QString m_name;
+ QDeclarativeDebugFileReference m_source;
+ int m_contextDebugId;
+ QList<QDeclarativeDebugPropertyReference> m_properties;
+ QList<QDeclarativeDebugObjectReference> m_children;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugContextReference
+{
+public:
+ QDeclarativeDebugContextReference();
+ QDeclarativeDebugContextReference(const QDeclarativeDebugContextReference &);
+ QDeclarativeDebugContextReference &operator=(const QDeclarativeDebugContextReference &);
+
+ int debugId() const;
+ QString name() const;
+
+ QList<QDeclarativeDebugObjectReference> objects() const;
+ QList<QDeclarativeDebugContextReference> contexts() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+ QList<QDeclarativeDebugObjectReference> m_objects;
+ QList<QDeclarativeDebugContextReference> m_contexts;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugPropertyReference
+{
+public:
+ QDeclarativeDebugPropertyReference();
+ QDeclarativeDebugPropertyReference(const QDeclarativeDebugPropertyReference &);
+ QDeclarativeDebugPropertyReference &operator=(const QDeclarativeDebugPropertyReference &);
+
+ int objectDebugId() const;
+ QString name() const;
+ QVariant value() const;
+ QString valueTypeName() const;
+ QString binding() const;
+ bool hasNotifySignal() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_objectDebugId;
+ QString m_name;
+ QVariant m_value;
+ QString m_valueTypeName;
+ QString m_binding;
+ bool m_hasNotifySignal;
+};
+
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugEnginesQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugEnginesQuery();
+ QList<QDeclarativeDebugEngineReference> engines() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugEnginesQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QList<QDeclarativeDebugEngineReference> m_engines;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugRootContextQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugRootContextQuery();
+ QDeclarativeDebugContextReference rootContext() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugRootContextQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QDeclarativeDebugContextReference m_context;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugObjectQuery();
+ QDeclarativeDebugObjectReference object() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugObjectQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QDeclarativeDebugObjectReference m_object;
+
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugExpressionQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugExpressionQuery();
+ QVariant expression() const;
+ QVariant result() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugExpressionQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QVariant m_expr;
+ QVariant m_result;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeDebugEngineReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugObjectReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugContextReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugPropertyReference)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUG_H
diff --git a/src/declarative/debugger/qdeclarativedebugclient.cpp b/src/declarative/debugger/qdeclarativedebugclient.cpp
new file mode 100644
index 0000000000..036dee1f2c
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugclient.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativedebugclient_p.h"
+
+#include "private/qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+const int protocolVersion = 1;
+const QString serverId = QLatin1String("QDeclarativeDebugServer");
+const QString clientId = QLatin1String("QDeclarativeDebugClient");
+
+class QDeclarativeDebugClientPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugClient)
+public:
+ QDeclarativeDebugClientPrivate();
+
+ QString name;
+ QDeclarativeDebugConnection *connection;
+};
+
+class QDeclarativeDebugConnectionPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c);
+ QDeclarativeDebugConnection *q;
+ QPacketProtocol *protocol;
+
+ bool gotHello;
+ QStringList serverPlugins;
+ QHash<QString, QDeclarativeDebugClient *> plugins;
+
+ void advertisePlugins();
+
+public Q_SLOTS:
+ void connected();
+ void readyRead();
+};
+
+QDeclarativeDebugConnectionPrivate::QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c)
+: QObject(c), q(c), protocol(0), gotHello(false)
+{
+ protocol = new QPacketProtocol(q, this);
+ QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
+ QObject::connect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+void QDeclarativeDebugConnectionPrivate::advertisePlugins()
+{
+ if (!q->isConnected())
+ return;
+
+ QPacket pack;
+ pack << serverId << 1 << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QDeclarativeDebugConnectionPrivate::connected()
+{
+ QPacket pack;
+ pack << serverId << 0 << protocolVersion << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QDeclarativeDebugConnectionPrivate::readyRead()
+{
+ if (!gotHello) {
+ QPacket pack = protocol->read();
+ QString name;
+
+ pack >> name;
+
+ bool validHello = false;
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+ if (op == 0) {
+ int version = -1;
+ pack >> version;
+ if (version == protocolVersion) {
+ pack >> serverPlugins;
+ validHello = true;
+ }
+ }
+ }
+
+ if (!validHello) {
+ qWarning("QDeclarativeDebugConnection: Invalid hello message");
+ QObject::disconnect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ return;
+ }
+
+ gotHello = true;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
+ if (serverPlugins.contains(iter.key()))
+ newStatus = QDeclarativeDebugClient::Enabled;
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+
+ while (protocol->packetsAvailable()) {
+ QPacket pack = protocol->read();
+ QString name;
+ pack >> name;
+
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QStringList oldServerPlugins = serverPlugins;
+ pack >> serverPlugins;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
+ if (serverPlugins.contains(pluginName))
+ newStatus = QDeclarativeDebugClient::Enabled;
+
+ if (oldServerPlugins.contains(pluginName)
+ != serverPlugins.contains(pluginName)) {
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+ } else {
+ qWarning() << "QDeclarativeDebugConnection: Unknown control message id" << op;
+ }
+ } else {
+ QByteArray message;
+ pack >> message;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter =
+ plugins.find(name);
+ if (iter == plugins.end()) {
+ qWarning() << "QDeclarativeDebugConnection: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent)
+: QTcpSocket(parent), d(new QDeclarativeDebugConnectionPrivate(this))
+{
+}
+
+QDeclarativeDebugConnection::~QDeclarativeDebugConnection()
+{
+ QHash<QString, QDeclarativeDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->d_func()->connection = 0;
+ iter.value()->statusChanged(QDeclarativeDebugClient::NotConnected);
+ }
+}
+
+bool QDeclarativeDebugConnection::isConnected() const
+{
+ return state() == ConnectedState;
+}
+
+QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate()
+: connection(0)
+{
+}
+
+QDeclarativeDebugClient::QDeclarativeDebugClient(const QString &name,
+ QDeclarativeDebugConnection *parent)
+: QObject(*(new QDeclarativeDebugClientPrivate), parent)
+{
+ Q_D(QDeclarativeDebugClient);
+ d->name = name;
+ d->connection = parent;
+
+ if (!d->connection)
+ return;
+
+ if (d->connection->d->plugins.contains(name)) {
+ qWarning() << "QDeclarativeDebugClient: Conflicting plugin name" << name;
+ d->connection = 0;
+ } else {
+ d->connection->d->plugins.insert(name, this);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QDeclarativeDebugClient::~QDeclarativeDebugClient()
+{
+ Q_D(const QDeclarativeDebugClient);
+ if (d->connection && d->connection->d) {
+ d->connection->d->plugins.remove(d->name);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QString QDeclarativeDebugClient::name() const
+{
+ Q_D(const QDeclarativeDebugClient);
+ return d->name;
+}
+
+QDeclarativeDebugClient::Status QDeclarativeDebugClient::status() const
+{
+ Q_D(const QDeclarativeDebugClient);
+ if (!d->connection
+ || !d->connection->isConnected()
+ || !d->connection->d->gotHello)
+ return NotConnected;
+
+ if (d->connection->d->serverPlugins.contains(d->name))
+ return Enabled;
+
+ return Unavailable;
+}
+
+void QDeclarativeDebugClient::sendMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugClient);
+
+ if (status() != Enabled)
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->connection->d->protocol->send(pack);
+ d->connection->d->q->flush();
+}
+
+void QDeclarativeDebugClient::statusChanged(Status)
+{
+}
+
+void QDeclarativeDebugClient::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativedebugclient.moc>
diff --git a/src/declarative/debugger/qdeclarativedebugclient_p.h b/src/declarative/debugger/qdeclarativedebugclient_p.h
new file mode 100644
index 0000000000..2f2665e605
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugclient_p.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 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 QDECLARATIVEDEBUGCLIENT_H
+#define QDECLARATIVEDEBUGCLIENT_H
+
+#include <QtNetwork/qtcpsocket.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugConnectionPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugConnection : public QTcpSocket
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QDeclarativeDebugConnection)
+public:
+ QDeclarativeDebugConnection(QObject * = 0);
+ ~QDeclarativeDebugConnection();
+
+ bool isConnected() const;
+private:
+ QDeclarativeDebugConnectionPrivate *d;
+ friend class QDeclarativeDebugClient;
+ friend class QDeclarativeDebugClientPrivate;
+};
+
+class QDeclarativeDebugClientPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugClient : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugClient)
+ Q_DISABLE_COPY(QDeclarativeDebugClient)
+
+public:
+ enum Status { NotConnected, Unavailable, Enabled };
+
+ QDeclarativeDebugClient(const QString &, QDeclarativeDebugConnection *parent);
+ ~QDeclarativeDebugClient();
+
+ QString name() const;
+
+ Status status() const;
+
+ void sendMessage(const QByteArray &);
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QDeclarativeDebugConnection;
+ friend class QDeclarativeDebugConnectionPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGCLIENT_H
diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus.cpp b/src/declarative/debugger/qdeclarativedebuggerstatus.cpp
new file mode 100644
index 0000000000..dc1e6e7e13
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebuggerstatus.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "private/qdeclarativedebuggerstatus_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeDebuggerStatus::~QDeclarativeDebuggerStatus()
+{
+}
+
+void QDeclarativeDebuggerStatus::setSelectedState(bool)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus_p.h b/src/declarative/debugger/qdeclarativedebuggerstatus_p.h
new file mode 100644
index 0000000000..cb79896f26
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebuggerstatus_p.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 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 QDECLARATIVEDEBUGGERSTATUS_P_H
+#define QDECLARATIVEDEBUGGERSTATUS_P_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebuggerStatus
+{
+public:
+ virtual ~QDeclarativeDebuggerStatus();
+
+ virtual void setSelectedState(bool);
+};
+Q_DECLARE_INTERFACE(QDeclarativeDebuggerStatus, "com.trolltech.qml.QDeclarativeDebuggerStatus")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLMDEBUGGERSTATUS_P_H
diff --git a/src/declarative/debugger/qdeclarativedebughelper.cpp b/src/declarative/debugger/qdeclarativedebughelper.cpp
new file mode 100644
index 0000000000..93f7423e4b
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebughelper.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 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 <QtScript/QScriptEngine>
+
+#include "private/qdeclarativedebughelper_p.h"
+
+#include <QtCore/QAbstractAnimation>
+#include <QtScript/QScriptEngine>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qabstractanimation_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QScriptEngine *QDeclarativeDebugHelper::getScriptEngine(QDeclarativeEngine *engine)
+{
+ return QDeclarativeEnginePrivate::getScriptEngine(engine);
+}
+
+void QDeclarativeDebugHelper::setAnimationSlowDownFactor(qreal factor)
+{
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setSlowModeEnabled(factor != 1.0);
+ timer->setSlowdownFactor(factor);
+}
+
+void QDeclarativeDebugHelper::enableDebugging() {
+#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL
+ if (!QDeclarativeEnginePrivate::qml_debugging_enabled) {
+ qWarning("Qml debugging is enabled. Only use this in a safe environment!");
+ }
+ QDeclarativeEnginePrivate::qml_debugging_enabled = true;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebughelper_p.h b/src/declarative/debugger/qdeclarativedebughelper_p.h
new file mode 100644
index 0000000000..34b4b59c8a
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebughelper_p.h
@@ -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 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 QDECLARATIVEDEBUGHELPER_P_H
+#define QDECLARATIVEDEBUGHELPER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QScriptEngine;
+class QDeclarativeEngine;
+
+// Helper methods to access private API through a stable interface
+// This is used in the qmljsdebugger library of QtCreator.
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
+{
+public:
+ static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static void setAnimationSlowDownFactor(qreal factor);
+
+ // Enables remote debugging functionality
+ // Only use this for debugging in a safe environment!
+ static void enableDebugging();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGHELPER_P_H
diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp
new file mode 100644
index 0000000000..6f46354a49
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserver.cpp
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativedebugserver_p.h"
+#include "private/qdeclarativedebugservice_p.h"
+#include "private/qdeclarativedebugservice_p_p.h"
+#include "private/qdeclarativeengine_p.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QStringList>
+
+#include <private/qobject_p.h>
+#include <private/qapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QDeclarativeDebug Protocol (Version 1):
+
+ handshake:
+ 1. Client sends
+ "QDeclarativeDebugServer" 0 version pluginNames
+ version: an int representing the highest protocol version the client knows
+ pluginNames: plugins available on client side
+ 2. Server sends
+ "QDeclarativeDebugClient" 0 version pluginNames
+ version: an int representing the highest protocol version the client & server know
+ pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
+ client plugin advertisement
+ 1. Client sends
+ "QDeclarativeDebugServer" 1 pluginNames
+ server plugin advertisement
+ 1. Server sends
+ "QDeclarativeDebugClient" 1 pluginNames
+ plugin communication:
+ Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
+ */
+
+const int protocolVersion = 1;
+
+
+class QDeclarativeDebugServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugServer)
+public:
+ QDeclarativeDebugServerPrivate();
+
+ void advertisePlugins();
+
+ QDeclarativeDebugServerConnection *connection;
+ QHash<QString, QDeclarativeDebugService *> plugins;
+ QStringList clientPlugins;
+ bool gotHello;
+
+ static QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
+};
+
+QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() :
+ connection(0),
+ gotHello(false)
+{
+}
+
+void QDeclarativeDebugServerPrivate::advertisePlugins()
+{
+ if (!gotHello)
+ return;
+
+ QByteArray message;
+ {
+ QDataStream out(&message, QIODevice::WriteOnly);
+ out << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys();
+ }
+ connection->send(message);
+}
+
+QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin(
+ const QString &pluginName)
+{
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists()) {
+ QStringList plugins(dir.entryList(QDir::Files));
+ foreach (const QString &pluginPath, plugins) {
+ if (QFileInfo(pluginPath).fileName().contains(pluginName))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+ }
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ QPluginLoader loader(pluginPath);
+ if (!loader.load()) {
+ continue;
+ }
+ QDeclarativeDebugServerConnection *connection = 0;
+ if (QObject *instance = loader.instance())
+ connection = qobject_cast<QDeclarativeDebugServerConnection*>(instance);
+
+ if (connection)
+ return connection;
+ loader.unload();
+ }
+ return 0;
+}
+
+bool QDeclarativeDebugServer::hasDebuggingClient() const
+{
+ Q_D(const QDeclarativeDebugServer);
+ return d->connection
+ && d->connection->isConnected()
+ && d->gotHello;
+}
+
+QDeclarativeDebugServer *QDeclarativeDebugServer::instance()
+{
+ static bool commandLineTested = false;
+ static QDeclarativeDebugServer *server = 0;
+
+ if (!commandLineTested) {
+ commandLineTested = true;
+
+ QApplicationPrivate *appD = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp));
+#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL
+ // ### remove port definition when protocol is changed
+ int port = 0;
+ bool block = false;
+ bool ok = false;
+
+ // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block]
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ if (!QDeclarativeEnginePrivate::qml_debugging_enabled) {
+ const QString message =
+ QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Debugging has not been enabled.").arg(
+ appD->qmljsDebugArgumentsString());
+ qWarning("%s", qPrintable(message));
+ return 0;
+ }
+
+ QString pluginName;
+ if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) {
+ int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(','));
+ port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok);
+ pluginName = QLatin1String("qmldbg_tcp");
+ } else if (appD->qmljsDebugArgumentsString().contains("ost")) {
+ pluginName = QLatin1String("qmldbg_ost");
+ ok = true;
+ }
+
+ block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
+
+ if (ok) {
+ server = new QDeclarativeDebugServer();
+
+ QDeclarativeDebugServerConnection *connection
+ = QDeclarativeDebugServerPrivate::loadConnectionPlugin(pluginName);
+ if (connection) {
+ server->d_func()->connection = connection;
+
+ connection->setServer(server);
+ connection->setPort(port, block);
+ } else {
+ qWarning() << QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString());
+ }
+
+ } else {
+ qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Format is -qmljsdebugger=port:<port>[,block]").arg(
+ appD->qmljsDebugArgumentsString()).toAscii().constData());
+ }
+ }
+#else
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "QtDeclarative is not configured for debugging.").arg(
+ appD->qmljsDebugArgumentsString()).toAscii().constData());
+ }
+#endif
+ }
+
+ return server;
+}
+
+QDeclarativeDebugServer::QDeclarativeDebugServer()
+: QObject(*(new QDeclarativeDebugServerPrivate))
+{
+}
+
+void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugServer);
+
+ QDataStream in(message);
+ if (!d->gotHello) {
+
+ QString name;
+ int op;
+ in >> name >> op;
+
+ if (name != QLatin1String("QDeclarativeDebugServer")
+ || op != 0) {
+ qWarning("QDeclarativeDebugServer: Invalid hello message");
+ d->connection->disconnect();
+ return;
+ }
+
+ int version;
+ in >> version >> d->clientPlugins;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(iter.key()))
+ newStatus = QDeclarativeDebugService::Enabled;
+ iter.value()->d_func()->status = newStatus;
+ iter.value()->statusChanged(newStatus);
+ }
+
+ QByteArray helloAnswer;
+ {
+ QDataStream out(&helloAnswer, QIODevice::WriteOnly);
+ out << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys();
+ }
+ d->connection->send(helloAnswer);
+
+ d->gotHello = true;
+ qWarning("QDeclarativeDebugServer: Connection established");
+ } else {
+
+ QString debugServer(QLatin1String("QDeclarativeDebugServer"));
+
+ QString name;
+ in >> name;
+
+ if (name == debugServer) {
+ int op = -1;
+ in >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QStringList oldClientPlugins = d->clientPlugins;
+ in >> d->clientPlugins;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(pluginName))
+ newStatus = QDeclarativeDebugService::Enabled;
+
+ if (oldClientPlugins.contains(pluginName)
+ != d->clientPlugins.contains(pluginName)) {
+ iter.value()->d_func()->status = newStatus;
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+ } else {
+ qWarning("QDeclarativeDebugServer: Invalid control message %d", op);
+ }
+ } else {
+ 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;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const
+{
+ const Q_D(QDeclarativeDebugServer);
+ return d->plugins.values();
+}
+
+QStringList QDeclarativeDebugServer::serviceNames() const
+{
+ const Q_D(QDeclarativeDebugServer);
+ return d->plugins.keys();
+}
+
+bool QDeclarativeDebugServer::addService(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+ if (!service || d->plugins.contains(service->name()))
+ return false;
+
+ d->plugins.insert(service->name(), service);
+ d->advertisePlugins();
+
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(service->name()))
+ newStatus = QDeclarativeDebugService::Enabled;
+ service->d_func()->status = newStatus;
+ service->statusChanged(newStatus);
+ return true;
+}
+
+bool QDeclarativeDebugServer::removeService(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+ if (!service || !d->plugins.contains(service->name()))
+ return false;
+
+ d->plugins.remove(service->name());
+ d->advertisePlugins();
+
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected;
+ service->d_func()->server = 0;
+ service->d_func()->status = newStatus;
+ service->statusChanged(newStatus);
+ return true;
+}
+
+void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service,
+ const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugServer);
+ QByteArray msg;
+ {
+ QDataStream out(&msg, QIODevice::WriteOnly);
+ out << service->name() << message;
+ }
+ d->connection->send(msg);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h
new file mode 100644
index 0000000000..68ea4d8531
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserver_p.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 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 QDECLARATIVEDEBUGSERVER_H
+#define QDECLARATIVEDEBUGSERVER_H
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativedebugserverconnection_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugService;
+
+class QDeclarativeDebugServerPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugServer)
+ Q_DISABLE_COPY(QDeclarativeDebugServer)
+public:
+ static QDeclarativeDebugServer *instance();
+
+ void setConnection(QDeclarativeDebugServerConnection *connection);
+
+ bool hasDebuggingClient() const;
+
+ QList<QDeclarativeDebugService*> services() const;
+ QStringList serviceNames() const;
+
+ bool addService(QDeclarativeDebugService *service);
+ bool removeService(QDeclarativeDebugService *service);
+
+ void sendMessage(QDeclarativeDebugService *service, const QByteArray &message);
+ void receiveMessage(const QByteArray &message);
+
+private:
+ friend class QDeclarativeDebugService;
+ friend class QDeclarativeDebugServicePrivate;
+ QDeclarativeDebugServer();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_H
diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
new file mode 100644
index 0000000000..0c2bdb4ef2
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
@@ -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 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 QDECLARATIVEDEBUGSERVERCONNECTION_H
+#define QDECLARATIVEDEBUGSERVERCONNECTION_H
+
+#include <QtDeclarative/private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServer;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugServerConnection
+{
+public:
+ QDeclarativeDebugServerConnection() {}
+ virtual ~QDeclarativeDebugServerConnection() {}
+
+ virtual void setServer(QDeclarativeDebugServer *server) = 0;
+ virtual void setPort(int port, bool bock) = 0;
+ virtual bool isConnected() const = 0;
+ virtual void send(const QByteArray &message) = 0;
+ virtual void disconnect() = 0;
+};
+
+Q_DECLARE_INTERFACE(QDeclarativeDebugServerConnection, "com.trolltech.Qt.QDeclarativeDebugServerConnection/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVERCONNECTION_H
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp
new file mode 100644
index 0000000000..1b39f1c269
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice.cpp
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativedebugservice_p.h"
+#include "private/qdeclarativedebugservice_p_p.h"
+#include "private/qdeclarativedebugserver_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeDebugServicePrivate::QDeclarativeDebugServicePrivate()
+: server(0)
+{
+}
+
+QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject *parent)
+: QObject(*(new QDeclarativeDebugServicePrivate), parent)
+{
+ Q_D(QDeclarativeDebugService);
+ d->name = name;
+ d->server = QDeclarativeDebugServer::instance();
+ d->status = QDeclarativeDebugService::NotConnected;
+
+ if (!d->server)
+ return;
+
+ if (d->server->serviceNames().contains(name)) {
+ qWarning() << "QDeclarativeDebugService: Conflicting plugin name" << name;
+ d->server = 0;
+ } else {
+ d->server->addService(this);
+ }
+}
+
+QDeclarativeDebugService::~QDeclarativeDebugService()
+{
+ Q_D(const QDeclarativeDebugService);
+ if (d->server) {
+ d->server->removeService(this);
+ }
+}
+
+QString QDeclarativeDebugService::name() const
+{
+ Q_D(const QDeclarativeDebugService);
+ return d->name;
+}
+
+QDeclarativeDebugService::Status QDeclarativeDebugService::status() const
+{
+ Q_D(const QDeclarativeDebugService);
+ return d->status;
+}
+
+namespace {
+
+ struct ObjectReference
+ {
+ QPointer<QObject> object;
+ int id;
+ };
+
+ struct ObjectReferenceHash
+ {
+ ObjectReferenceHash() : nextId(0) {}
+
+ QHash<QObject *, ObjectReference> objects;
+ QHash<int, QObject *> ids;
+
+ int nextId;
+ };
+
+}
+Q_GLOBAL_STATIC(ObjectReferenceHash, objectReferenceHash);
+
+
+/*!
+ Returns a unique id for \a object. Calling this method multiple times
+ for the same object will return the same id.
+*/
+int QDeclarativeDebugService::idForObject(QObject *object)
+{
+ if (!object)
+ return -1;
+
+ ObjectReferenceHash *hash = objectReferenceHash();
+ QHash<QObject *, ObjectReference>::Iterator iter =
+ hash->objects.find(object);
+
+ if (iter == hash->objects.end()) {
+ int id = hash->nextId++;
+
+ hash->ids.insert(id, object);
+ iter = hash->objects.insert(object, ObjectReference());
+ iter->object = object;
+ iter->id = id;
+ } else if (iter->object != object) {
+ int id = hash->nextId++;
+
+ hash->ids.remove(iter->id);
+
+ hash->ids.insert(id, object);
+ iter->object = object;
+ iter->id = id;
+ }
+ return iter->id;
+}
+
+/*!
+ Returns the object for unique \a id. If the object has not previously been
+ assigned an id, through idForObject(), then 0 is returned. If the object
+ has been destroyed, 0 is returned.
+*/
+QObject *QDeclarativeDebugService::objectForId(int id)
+{
+ ObjectReferenceHash *hash = objectReferenceHash();
+
+ QHash<int, QObject *>::Iterator iter = hash->ids.find(id);
+ if (iter == hash->ids.end())
+ return 0;
+
+
+ QHash<QObject *, ObjectReference>::Iterator objIter =
+ hash->objects.find(*iter);
+ Q_ASSERT(objIter != hash->objects.end());
+
+ if (objIter->object == 0) {
+ hash->ids.erase(iter);
+ hash->objects.erase(objIter);
+ return 0;
+ } else {
+ return *iter;
+ }
+}
+
+bool QDeclarativeDebugService::isDebuggingEnabled()
+{
+ return QDeclarativeDebugServer::instance() != 0;
+}
+
+bool QDeclarativeDebugService::hasDebuggingClient()
+{
+ return QDeclarativeDebugServer::instance() != 0
+ && QDeclarativeDebugServer::instance()->hasDebuggingClient();
+}
+
+QString QDeclarativeDebugService::objectToString(QObject *obj)
+{
+ if(!obj)
+ return QLatin1String("NULL");
+
+ QString objectName = obj->objectName();
+ if(objectName.isEmpty())
+ objectName = QLatin1String("<unnamed>");
+
+ QString rv = QString::fromUtf8(obj->metaObject()->className()) +
+ QLatin1String(": ") + objectName;
+
+ return rv;
+}
+
+void QDeclarativeDebugService::sendMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugService);
+
+ if (status() != Enabled)
+ return;
+
+ d->server->sendMessage(this, message);
+}
+
+void QDeclarativeDebugService::statusChanged(Status)
+{
+}
+
+void QDeclarativeDebugService::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h
new file mode 100644
index 0000000000..5e30350abf
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEDEBUGSERVICE_H
+#define QDECLARATIVEDEBUGSERVICE_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServicePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugService : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugService)
+ Q_DISABLE_COPY(QDeclarativeDebugService)
+
+public:
+ explicit QDeclarativeDebugService(const QString &, QObject *parent = 0);
+ ~QDeclarativeDebugService();
+
+ QString name() const;
+
+ enum Status { NotConnected, Unavailable, Enabled };
+ Status status() const;
+
+ void sendMessage(const QByteArray &);
+
+ static int idForObject(QObject *);
+ static QObject *objectForId(int);
+
+ static QString objectToString(QObject *obj);
+
+ static bool isDebuggingEnabled();
+ static bool hasDebuggingClient();
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QDeclarativeDebugServer;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_H
+
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p_p.h b/src/declarative/debugger/qdeclarativedebugservice_p_p.h
new file mode 100644
index 0000000000..d0423f79f8
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice_p_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEDEBUGSERVICE_P_H
+#define QDECLARATIVEDEBUGSERVICE_P_H
+
+#include <QtCore/qglobal.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServer;
+
+class QDeclarativeDebugServicePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugService)
+public:
+ QDeclarativeDebugServicePrivate();
+
+ QString name;
+ QDeclarativeDebugServer *server;
+ QDeclarativeDebugService::Status status;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_P_H
diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp
new file mode 100644
index 0000000000..6f28736f52
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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 "qdeclarativedebugtrace_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qtimer.h>
+
+Q_GLOBAL_STATIC(QDeclarativeDebugTrace, traceInstance);
+
+// convert to a QByteArray that can be sent to the debug client
+// use of QDataStream can skew results if m_deferredSend == false
+// (see tst_qperformancetimer::trace() benchmark)
+QByteArray QDeclarativeDebugData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << time << messageType << detailType;
+ if (messageType == (int)QDeclarativeDebugTrace::RangeData)
+ ds << detailData;
+ if (messageType == (int)QDeclarativeDebugTrace::RangeLocation)
+ ds << detailData << line;
+ return data;
+}
+
+QDeclarativeDebugTrace::QDeclarativeDebugTrace()
+: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")),
+ m_enabled(false), m_deferredSend(true)
+{
+ m_timer.start();
+}
+
+void QDeclarativeDebugTrace::addEvent(EventType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->addEventImpl(t);
+}
+
+void QDeclarativeDebugTrace::startRange(RangeType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->startRangeImpl(t);
+}
+
+void QDeclarativeDebugTrace::rangeData(RangeType t, const QString &data)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeDataImpl(t, data);
+}
+
+void QDeclarativeDebugTrace::rangeData(RangeType t, const QUrl &data)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeDataImpl(t, data);
+}
+
+void QDeclarativeDebugTrace::rangeLocation(RangeType t, const QString &fileName, int line)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeLocationImpl(t, fileName, line);
+}
+
+void QDeclarativeDebugTrace::rangeLocation(RangeType t, const QUrl &fileName, int line)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeLocationImpl(t, fileName, line);
+}
+
+void QDeclarativeDebugTrace::endRange(RangeType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->endRangeImpl(t);
+}
+
+void QDeclarativeDebugTrace::addEventImpl(EventType event)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData ed = {m_timer.elapsed(), (int)Event, (int)event, QString(), -1};
+ processMessage(ed);
+}
+
+void QDeclarativeDebugTrace::startRangeImpl(RangeType range)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeStart, (int)range, QString(), -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData, -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QUrl &rData)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeLocationImpl(RangeType range, const QString &fileName, int line)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeLocation, (int)range, fileName, line};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeLocationImpl(RangeType range, const QUrl &fileName, int line)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::endRangeImpl(RangeType range)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeEnd, (int)range, QString(), -1};
+ processMessage(rd);
+}
+
+/*
+ Either send the message directly, or queue up
+ a list of messages to send later (via sendMessages)
+*/
+void QDeclarativeDebugTrace::processMessage(const QDeclarativeDebugData &message)
+{
+ if (m_deferredSend)
+ m_data.append(message);
+ else
+ sendMessage(message.toByteArray());
+}
+
+/*
+ Send the messages queued up by processMessage
+*/
+void QDeclarativeDebugTrace::sendMessages()
+{
+ if (m_deferredSend) {
+ //### this is a suboptimal way to send batched messages
+ for (int i = 0; i < m_data.count(); ++i)
+ sendMessage(m_data.at(i).toByteArray());
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (qint64)-1 << (int)Complete;
+ sendMessage(data);
+ }
+}
+
+void QDeclarativeDebugTrace::messageReceived(const QByteArray &message)
+{
+ QByteArray rwData = message;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ stream >> m_enabled;
+
+ if (!m_enabled)
+ sendMessages();
+}
diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h
new file mode 100644
index 0000000000..ae0653ee71
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEDEBUGTRACE_P_H
+#define QDECLARATIVEDEBUGTRACE_P_H
+
+#include <private/qdeclarativedebugservice_p.h>
+#include <private/qperformancetimer_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeDebugData
+{
+ qint64 time;
+ int messageType;
+ int detailType;
+
+ //###
+ QString detailData; //used by RangeData and RangeLocation
+ int line; //used by RangeLocation
+
+ QByteArray toByteArray() const;
+};
+
+class QUrl;
+class Q_AUTOTEST_EXPORT QDeclarativeDebugTrace : public QDeclarativeDebugService
+{
+public:
+ enum Message {
+ Event,
+ RangeStart,
+ RangeData,
+ RangeLocation,
+ RangeEnd,
+ Complete,
+
+ MaximumMessage
+ };
+
+ enum EventType {
+ FramePaint,
+ Mouse,
+ Key,
+
+ MaximumEventType
+ };
+
+ enum RangeType {
+ Painting,
+ Compiling,
+ Creating,
+ Binding, //running a binding
+ HandlingSignal, //running a signal handler
+
+ MaximumRangeType
+ };
+
+ static void addEvent(EventType);
+
+ static void startRange(RangeType);
+ static void rangeData(RangeType, const QString &);
+ static void rangeData(RangeType, const QUrl &);
+ static void rangeLocation(RangeType, const QString &, int);
+ static void rangeLocation(RangeType, const QUrl &, int);
+ static void endRange(RangeType);
+
+ QDeclarativeDebugTrace();
+protected:
+ virtual void messageReceived(const QByteArray &);
+private:
+ void addEventImpl(EventType);
+ void startRangeImpl(RangeType);
+ void rangeDataImpl(RangeType, const QString &);
+ void rangeDataImpl(RangeType, const QUrl &);
+ void rangeLocationImpl(RangeType, const QString &, int);
+ void rangeLocationImpl(RangeType, const QUrl &, int);
+ void endRangeImpl(RangeType);
+ void processMessage(const QDeclarativeDebugData &);
+ void sendMessages();
+ QPerformanceTimer m_timer;
+ bool m_enabled;
+ bool m_deferredSend;
+ QList<QDeclarativeDebugData> m_data;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGTRACE_P_H
+
diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp
new file mode 100644
index 0000000000..15a14cf9f4
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol.cpp
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qpacketprotocol_p.h"
+
+#include <QBuffer>
+
+QT_BEGIN_NAMESPACE
+
+#define MAX_PACKET_SIZE 0x7FFFFFFF
+
+/*!
+ \class QPacketProtocol
+ \internal
+
+ \brief The QPacketProtocol class encapsulates communicating discrete packets
+ across fragmented IO channels, such as TCP sockets.
+
+ QPacketProtocol makes it simple to send arbitrary sized data "packets" across
+ fragmented transports such as TCP and UDP.
+
+ As transmission boundaries are not respected, sending packets over protocols
+ like TCP frequently involves "stitching" them back together at the receiver.
+ QPacketProtocol makes this easier by performing this task for you. Packet
+ data sent using QPacketProtocol is prepended with a 4-byte size header
+ allowing the receiving QPacketProtocol to buffer the packet internally until
+ it has all been received. QPacketProtocol does not perform any sanity
+ checking on the size or on the data, so this class should only be used in
+ prototyping or trusted situations where DOS attacks are unlikely.
+
+ QPacketProtocol does not perform any communications itself. Instead it can
+ operate on any QIODevice that supports the QIODevice::readyRead() signal. A
+ logical "packet" is encapsulated by the companion QPacket class. The
+ following example shows two ways to send data using QPacketProtocol. The
+ transmitted data is equivalent in both.
+
+ \code
+ QTcpSocket socket;
+ // ... connect socket ...
+
+ QPacketProtocol protocol(&socket);
+
+ // Send packet the quick way
+ protocol.send() << "Hello world" << 123;
+
+ // Send packet the longer way
+ QPacket packet;
+ packet << "Hello world" << 123;
+ protocol.send(packet);
+ \endcode
+
+ Likewise, the following shows how to read data from QPacketProtocol, assuming
+ that the QPacketProtocol::readyRead() signal has been emitted.
+
+ \code
+ // ... QPacketProtocol::readyRead() is emitted ...
+
+ int a;
+ QByteArray b;
+
+ // Receive packet the quick way
+ protocol.read() >> a >> b;
+
+ // Receive packet the longer way
+ QPacket packet = protocol.read();
+ p >> a >> b;
+ \endcode
+
+ \ingroup io
+ \sa QPacket
+*/
+
+class QPacketProtocolPrivate : public QObject
+{
+Q_OBJECT
+public:
+ QPacketProtocolPrivate(QPacketProtocol * parent, QIODevice * _dev)
+ : QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
+ dev(_dev)
+ {
+ Q_ASSERT(4 == sizeof(qint32));
+
+ QObject::connect(this, SIGNAL(readyRead()),
+ parent, SIGNAL(readyRead()));
+ QObject::connect(this, SIGNAL(packetWritten()),
+ parent, SIGNAL(packetWritten()));
+ QObject::connect(this, SIGNAL(invalidPacket()),
+ parent, SIGNAL(invalidPacket()));
+ QObject::connect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()), Qt::QueuedConnection);
+ QObject::connect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ }
+
+Q_SIGNALS:
+ void readyRead();
+ void packetWritten();
+ void invalidPacket();
+
+public Q_SLOTS:
+ void aboutToClose()
+ {
+ inProgress.clear();
+ sendingPackets.clear();
+ inProgressSize = -1;
+ }
+
+ void bytesWritten(qint64 bytes)
+ {
+ Q_ASSERT(!sendingPackets.isEmpty());
+
+ while(bytes) {
+ if(sendingPackets.at(0) > bytes) {
+ sendingPackets[0] -= bytes;
+ bytes = 0;
+ } else {
+ bytes -= sendingPackets.at(0);
+ sendingPackets.removeFirst();
+ emit packetWritten();
+ }
+ }
+ }
+
+ void readyToRead()
+ {
+ if(-1 == inProgressSize) {
+ // We need a size header of sizeof(qint32)
+ if(sizeof(qint32) > (uint)dev->bytesAvailable())
+ return;
+
+ // Read size header
+ int read = dev->read((char *)&inProgressSize, sizeof(qint32));
+ Q_ASSERT(read == sizeof(qint32));
+ Q_UNUSED(read);
+
+ // Check sizing constraints
+ if(inProgressSize > maxPacketSize) {
+ QObject::disconnect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()));
+ QObject::disconnect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::disconnect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ dev = 0;
+ emit invalidPacket();
+ return;
+ }
+
+ inProgressSize -= sizeof(qint32);
+
+ // Need to get trailing data
+ readyToRead();
+ } else {
+ inProgress.append(dev->read(inProgressSize - inProgress.size()));
+
+ if(inProgressSize == inProgress.size()) {
+ // Packet has arrived!
+ packets.append(inProgress);
+ inProgressSize = -1;
+ inProgress.clear();
+
+ emit readyRead();
+
+ // Need to get trailing data
+ readyToRead();
+ }
+ }
+ }
+
+public:
+ QList<qint64> sendingPackets;
+ QList<QByteArray> packets;
+ QByteArray inProgress;
+ qint32 inProgressSize;
+ qint32 maxPacketSize;
+ QIODevice * dev;
+};
+
+/*!
+ Construct a QPacketProtocol instance that works on \a dev with the
+ specified \a parent.
+ */
+QPacketProtocol::QPacketProtocol(QIODevice * dev, QObject * parent)
+: QObject(parent), d(new QPacketProtocolPrivate(this, dev))
+{
+ Q_ASSERT(dev);
+}
+
+/*!
+ Destroys the QPacketProtocol instance.
+ */
+QPacketProtocol::~QPacketProtocol()
+{
+}
+
+/*!
+ Returns the maximum packet size allowed. By default this is
+ 2,147,483,647 bytes.
+
+ If a packet claiming to be larger than the maximum packet size is received,
+ the QPacketProtocol::invalidPacket() signal is emitted.
+
+ \sa QPacketProtocol::setMaximumPacketSize()
+ */
+qint32 QPacketProtocol::maximumPacketSize() const
+{
+ return d->maxPacketSize;
+}
+
+/*!
+ Sets the maximum allowable packet size to \a max.
+
+ \sa QPacketProtocol::maximumPacketSize()
+ */
+qint32 QPacketProtocol::setMaximumPacketSize(qint32 max)
+{
+ if(max > (signed)sizeof(qint32))
+ d->maxPacketSize = max;
+ return d->maxPacketSize;
+}
+
+/*!
+ Returns a streamable object that is transmitted on destruction. For example
+
+ \code
+ protocol.send() << "Hello world" << 123;
+ \endcode
+
+ will send a packet containing "Hello world" and 123. To construct more
+ complex packets, explicitly construct a QPacket instance.
+ */
+QPacketAutoSend QPacketProtocol::send()
+{
+ return QPacketAutoSend(this);
+}
+
+/*!
+ \fn void QPacketProtocol::send(const QPacket & packet)
+
+ Transmit the \a packet.
+ */
+void QPacketProtocol::send(const QPacket & p)
+{
+ if(p.b.isEmpty())
+ return; // We don't send empty packets
+
+ qint64 sendSize = p.b.size() + sizeof(qint32);
+
+ d->sendingPackets.append(sendSize);
+ qint32 sendSize32 = sendSize;
+ qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32));
+ Q_ASSERT(writeBytes == sizeof(qint32));
+ writeBytes = d->dev->write(p.b);
+ Q_ASSERT(writeBytes == p.b.size());
+}
+
+/*!
+ Returns the number of received packets yet to be read.
+ */
+qint64 QPacketProtocol::packetsAvailable() const
+{
+ return d->packets.count();
+}
+
+/*!
+ Discard any unread packets.
+ */
+void QPacketProtocol::clear()
+{
+ d->packets.clear();
+}
+
+/*!
+ Return the next unread packet, or an invalid QPacket instance if no packets
+ are available. This method does NOT block.
+ */
+QPacket QPacketProtocol::read()
+{
+ if(0 == d->packets.count())
+ return QPacket();
+
+ QPacket rv(d->packets.at(0));
+ d->packets.removeFirst();
+ return rv;
+}
+
+/*!
+ Return the QIODevice passed to the QPacketProtocol constructor.
+*/
+QIODevice * QPacketProtocol::device()
+{
+ return d->dev;
+}
+
+/*!
+ \fn void QPacketProtocol::readyRead()
+
+ Emitted whenever a new packet is received. Applications may use
+ QPacketProtocol::read() to retrieve this packet.
+ */
+
+/*!
+ \fn void QPacketProtocol::invalidPacket()
+
+ A packet larger than the maximum allowable packet size was received. The
+ packet will be discarded and, as it indicates corruption in the protocol, no
+ further packets will be received.
+ */
+
+/*!
+ \fn void QPacketProtocol::packetWritten()
+
+ Emitted each time a packet is completing written to the device. This signal
+ may be used for communications flow control.
+ */
+
+/*!
+ \class QPacket
+ \internal
+
+ \brief The QPacket class encapsulates an unfragmentable packet of data to be
+ transmitted by QPacketProtocol.
+
+ The QPacket class works together with QPacketProtocol to make it simple to
+ send arbitrary sized data "packets" across fragmented transports such as TCP
+ and UDP.
+
+ QPacket provides a QDataStream interface to an unfragmentable packet.
+ Applications should construct a QPacket, propagate it with data and then
+ transmit it over a QPacketProtocol instance. For example:
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket myPacket;
+ myPacket << "Hello world!" << 123;
+ protocol.send(myPacket);
+ \endcode
+
+ As long as both ends of the connection are using the QPacketProtocol class,
+ the data within this packet will be delivered unfragmented at the other end,
+ ready for extraction.
+
+ \code
+ QByteArray greeting;
+ int count;
+
+ QPacket myPacket = protocol.read();
+
+ myPacket >> greeting >> count;
+ \endcode
+
+ Only packets returned from QPacketProtocol::read() may be read from. QPacket
+ instances constructed by directly by applications are for transmission only
+ and are considered "write only". Attempting to read data from them will
+ result in undefined behavior.
+
+ \ingroup io
+ \sa QPacketProtocol
+ */
+
+/*!
+ Constructs an empty write-only packet.
+ */
+QPacket::QPacket()
+: QDataStream(), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::WriteOnly);
+ setDevice(buf);
+ setVersion(QDataStream::Qt_4_7);
+}
+
+/*!
+ Destroys the QPacket instance.
+ */
+QPacket::~QPacket()
+{
+ if(buf) {
+ delete buf;
+ buf = 0;
+ }
+}
+
+/*!
+ Creates a copy of \a other. The initial stream positions are shared, but the
+ two packets are otherwise independent.
+ */
+QPacket::QPacket(const QPacket & other)
+: QDataStream(), b(other.b), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(other.buf->openMode());
+ setDevice(buf);
+}
+
+/*!
+ \internal
+ */
+QPacket::QPacket(const QByteArray & ba)
+: QDataStream(), b(ba), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::ReadOnly);
+ setDevice(buf);
+}
+
+/*!
+ Returns true if this packet is empty - that is, contains no data.
+ */
+bool QPacket::isEmpty() const
+{
+ return b.isEmpty();
+}
+
+/*!
+ Returns raw packet data.
+ */
+QByteArray QPacket::data() const
+{
+ return b;
+}
+
+/*!
+ Clears data in the packet. This is useful for reusing one writable packet.
+ For example
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket packet;
+
+ packet << "Hello world!" << 123;
+ protocol.send(packet);
+
+ packet.clear();
+ packet << "Goodbyte world!" << 789;
+ protocol.send(packet);
+ \endcode
+ */
+void QPacket::clear()
+{
+ QBuffer::OpenMode oldMode = buf->openMode();
+ buf->close();
+ b.clear();
+ buf->setBuffer(&b); // reset QBuffer internals with new size of b.
+ buf->open(oldMode);
+}
+
+/*!
+ \class QPacketAutoSend
+ \internal
+
+ \internal
+ */
+QPacketAutoSend::QPacketAutoSend(QPacketProtocol * _p)
+: QPacket(), p(_p)
+{
+}
+
+QPacketAutoSend::~QPacketAutoSend()
+{
+ if(!b.isEmpty())
+ p->send(*this);
+}
+
+QT_END_NAMESPACE
+
+#include <qpacketprotocol.moc>
diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h
new file mode 100644
index 0000000000..accb8efa67
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol_p.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 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 QPACKETPROTOCOL_H
+#define QPACKETPROTOCOL_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatastream.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QIODevice;
+class QBuffer;
+class QPacket;
+class QPacketAutoSend;
+class QPacketProtocolPrivate;
+
+class Q_DECLARATIVE_EXPORT QPacketProtocol : public QObject
+{
+Q_OBJECT
+public:
+ explicit QPacketProtocol(QIODevice * dev, QObject * parent = 0);
+ virtual ~QPacketProtocol();
+
+ qint32 maximumPacketSize() const;
+ qint32 setMaximumPacketSize(qint32);
+
+ QPacketAutoSend send();
+ void send(const QPacket &);
+
+ qint64 packetsAvailable() const;
+ QPacket read();
+
+ void clear();
+
+ QIODevice * device();
+
+Q_SIGNALS:
+ void readyRead();
+ void invalidPacket();
+ void packetWritten();
+
+private:
+ QPacketProtocolPrivate * d;
+};
+
+
+class Q_DECLARATIVE_EXPORT QPacket : public QDataStream
+{
+public:
+ QPacket();
+ QPacket(const QPacket &);
+ virtual ~QPacket();
+
+ void clear();
+ bool isEmpty() const;
+ QByteArray data() const;
+
+protected:
+ friend class QPacketProtocol;
+ QPacket(const QByteArray & ba);
+ QByteArray b;
+ QBuffer * buf;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QPacketAutoSend : public QPacket
+{
+public:
+ virtual ~QPacketAutoSend();
+
+private:
+ friend class QPacketProtocol;
+ QPacketAutoSend(QPacketProtocol *);
+ QPacketProtocol * p;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro
new file mode 100644
index 0000000000..b74b18c090
--- /dev/null
+++ b/src/declarative/declarative.pro
@@ -0,0 +1,43 @@
+TARGET = QtDeclarative
+QPRO_PWD = $$PWD
+QT = core gui script network
+contains(QT_CONFIG, svg): QT += svg
+DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING
+win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
+
+unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui
+
+exists("qdeclarative_enable_gcov") {
+ QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
+ LIBS += -lgcov
+}
+
+include(../qbase.pri)
+
+#INCLUDEPATH -= $$QMAKE_INCDIR_QT/$$TARGET
+#DESTDIR=.
+
+#modules
+include(util/util.pri)
+include(graphicsitems/graphicsitems.pri)
+include(qml/qml.pri)
+include(debugger/debugger.pri)
+
+symbian: {
+ TARGET.UID3=0x2001E623
+ LIBS += -lefsrv
+
+ contains(QT_CONFIG, freetype) {
+ DEFINES += QT_NO_FONTCONFIG
+ INCLUDEPATH += \
+ ../3rdparty/freetype/src \
+ ../3rdparty/freetype/include
+ }
+}
+
+linux-g++-maemo:DEFINES += QDECLARATIVEVIEW_NOBACKGROUND
+
+DEFINES += QT_NO_OPENTYPE
+INCLUDEPATH += ../3rdparty/harfbuzz/src
+
diff --git a/src/declarative/graphicsitems/graphicsitems.pri b/src/declarative/graphicsitems/graphicsitems.pri
new file mode 100644
index 0000000000..9904274023
--- /dev/null
+++ b/src/declarative/graphicsitems/graphicsitems.pri
@@ -0,0 +1,94 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qdeclarativeitemsmodule_p.h \
+ $$PWD/qdeclarativeanchors_p.h \
+ $$PWD/qdeclarativeanchors_p_p.h \
+ $$PWD/qdeclarativeevents_p_p.h \
+ $$PWD/qdeclarativeflickable_p.h \
+ $$PWD/qdeclarativeflickable_p_p.h \
+ $$PWD/qdeclarativeflipable_p.h \
+ $$PWD/qdeclarativegridview_p.h \
+ $$PWD/qdeclarativeimage_p.h \
+ $$PWD/qdeclarativeimagebase_p.h \
+ $$PWD/qdeclarativeborderimage_p.h \
+ $$PWD/qdeclarativepainteditem_p.h \
+ $$PWD/qdeclarativepainteditem_p_p.h \
+ $$PWD/qdeclarativeimage_p_p.h \
+ $$PWD/qdeclarativeborderimage_p_p.h \
+ $$PWD/qdeclarativeimagebase_p_p.h \
+ $$PWD/qdeclarativeanimatedimage_p.h \
+ $$PWD/qdeclarativeanimatedimage_p_p.h \
+ $$PWD/qdeclarativeitem.h \
+ $$PWD/qdeclarativeitem_p.h \
+ $$PWD/qdeclarativefocuspanel_p.h \
+ $$PWD/qdeclarativefocusscope_p.h \
+ $$PWD/qdeclarativepositioners_p.h \
+ $$PWD/qdeclarativepositioners_p_p.h \
+ $$PWD/qdeclarativeloader_p.h \
+ $$PWD/qdeclarativeloader_p_p.h \
+ $$PWD/qdeclarativemousearea_p.h \
+ $$PWD/qdeclarativemousearea_p_p.h \
+ $$PWD/qdeclarativepath_p.h \
+ $$PWD/qdeclarativepath_p_p.h \
+ $$PWD/qdeclarativepathview_p.h \
+ $$PWD/qdeclarativepathview_p_p.h \
+ $$PWD/qdeclarativerectangle_p.h \
+ $$PWD/qdeclarativerectangle_p_p.h \
+ $$PWD/qdeclarativerepeater_p.h \
+ $$PWD/qdeclarativerepeater_p_p.h \
+ $$PWD/qdeclarativescalegrid_p_p.h \
+ $$PWD/qdeclarativetranslate_p.h \
+ $$PWD/qdeclarativetextinput_p.h \
+ $$PWD/qdeclarativetextinput_p_p.h \
+ $$PWD/qdeclarativetextedit_p.h \
+ $$PWD/qdeclarativetextedit_p_p.h \
+ $$PWD/qdeclarativetext_p.h \
+ $$PWD/qdeclarativetext_p_p.h \
+ $$PWD/qdeclarativevisualitemmodel_p.h \
+ $$PWD/qdeclarativelistview_p.h \
+ $$PWD/qdeclarativelayoutitem_p.h \
+ $$PWD/qdeclarativeitemchangelistener_p.h \
+ $$PWD/qdeclarativegraphicswidget_p.h \
+ $$PWD/qdeclarativetextlayout_p.h \
+ $$PWD/qdeclarativepincharea_p.h \
+ $$PWD/qdeclarativepincharea_p_p.h \
+ $$PWD/qdeclarativeimplicitsizeitem_p.h \
+ $$PWD/qdeclarativeimplicitsizeitem_p_p.h
+
+
+SOURCES += \
+ $$PWD/qdeclarativeitemsmodule.cpp \
+ $$PWD/qdeclarativeanchors.cpp \
+ $$PWD/qdeclarativeevents.cpp \
+ $$PWD/qdeclarativeflickable.cpp \
+ $$PWD/qdeclarativeflipable.cpp \
+ $$PWD/qdeclarativegridview.cpp \
+ $$PWD/qdeclarativeimage.cpp \
+ $$PWD/qdeclarativeborderimage.cpp \
+ $$PWD/qdeclarativeimagebase.cpp \
+ $$PWD/qdeclarativeanimatedimage.cpp \
+ $$PWD/qdeclarativepainteditem.cpp \
+ $$PWD/qdeclarativeitem.cpp \
+ $$PWD/qdeclarativefocuspanel.cpp \
+ $$PWD/qdeclarativefocusscope.cpp \
+ $$PWD/qdeclarativepositioners.cpp \
+ $$PWD/qdeclarativeloader.cpp \
+ $$PWD/qdeclarativemousearea.cpp \
+ $$PWD/qdeclarativepath.cpp \
+ $$PWD/qdeclarativepathview.cpp \
+ $$PWD/qdeclarativerectangle.cpp \
+ $$PWD/qdeclarativerepeater.cpp \
+ $$PWD/qdeclarativescalegrid.cpp \
+ $$PWD/qdeclarativetranslate.cpp \
+ $$PWD/qdeclarativetextinput.cpp \
+ $$PWD/qdeclarativetext.cpp \
+ $$PWD/qdeclarativetextedit.cpp \
+ $$PWD/qdeclarativevisualitemmodel.cpp \
+ $$PWD/qdeclarativelistview.cpp \
+ $$PWD/qdeclarativelayoutitem.cpp \
+ $$PWD/qdeclarativegraphicswidget.cpp \
+ $$PWD/qdeclarativetextlayout.cpp \
+ $$PWD/qdeclarativepincharea.cpp \
+ $$PWD/qdeclarativeimplicitsizeitem.cpp
+
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors.cpp b/src/declarative/graphicsitems/qdeclarativeanchors.cpp
new file mode 100644
index 0000000000..5ff6d2c7ee
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanchors.cpp
@@ -0,0 +1,1165 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeanchors_p_p.h"
+
+#include "qdeclarativeitem.h"
+#include "private/qdeclarativeitem_p.h"
+
+#include <qdeclarativeinfo.h>
+
+#include <QDebug>
+
+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(QGraphicsItem *i)
+{
+ QGraphicsItemPrivate *item = QGraphicsItemPrivate::get(i);
+
+ qreal width = item->width();
+ int iw = width;
+ if (iw % 2)
+ return (width + 1) / 2;
+ else
+ return width / 2;
+}
+
+static qreal vcenter(QGraphicsItem *i)
+{
+ QGraphicsItemPrivate *item = QGraphicsItemPrivate::get(i);
+
+ 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(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(item);
+ switch(anchorLine) {
+ case QDeclarativeAnchorLine::Left:
+ ret = item->x();
+ break;
+ case QDeclarativeAnchorLine::Right:
+ ret = item->x() + d->width();
+ break;
+ case QDeclarativeAnchorLine::Top:
+ ret = item->y();
+ break;
+ case QDeclarativeAnchorLine::Bottom:
+ ret = item->y() + d->height();
+ break;
+ case QDeclarativeAnchorLine::HCenter:
+ ret = item->x() + hcenter(item);
+ break;
+ case QDeclarativeAnchorLine::VCenter:
+ ret = item->y() + vcenter(item);
+ break;
+ case QDeclarativeAnchorLine::Baseline:
+ if (d->isDeclarativeItem)
+ ret = item->y() + static_cast<QDeclarativeItem*>(item)->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+//position when origin is 0,0
+static qreal adjustedPosition(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(item);
+ switch(anchorLine) {
+ case QDeclarativeAnchorLine::Left:
+ ret = 0.0;
+ break;
+ case QDeclarativeAnchorLine::Right:
+ ret = d->width();
+ break;
+ case QDeclarativeAnchorLine::Top:
+ ret = 0.0;
+ break;
+ case QDeclarativeAnchorLine::Bottom:
+ ret = d->height();
+ break;
+ case QDeclarativeAnchorLine::HCenter:
+ ret = hcenter(item);
+ break;
+ case QDeclarativeAnchorLine::VCenter:
+ ret = vcenter(item);
+ break;
+ case QDeclarativeAnchorLine::Baseline:
+ if (d->isDeclarativeItem)
+ ret = static_cast<QDeclarativeItem*>(item)->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+QDeclarativeAnchors::QDeclarativeAnchors(QObject *parent)
+ : QObject(*new QDeclarativeAnchorsPrivate(0), parent)
+{
+ qFatal("QDeclarativeAnchors::QDeclarativeAnchors(QObject*) called");
+}
+
+QDeclarativeAnchors::QDeclarativeAnchors(QGraphicsObject *item, QObject *parent)
+ : QObject(*new QDeclarativeAnchorsPrivate(item), parent)
+{
+}
+
+QDeclarativeAnchors::~QDeclarativeAnchors()
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchorsPrivate::fillChanged()
+{
+ Q_Q(QDeclarativeAnchors);
+ 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));
+ }
+ QGraphicsItemPrivate *fillPrivate = QGraphicsItemPrivate::get(fill);
+ setItemSize(QSizeF(fillPrivate->width()-leftMargin-rightMargin, fillPrivate->height()-topMargin-bottomMargin));
+
+ --updatingFill;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QDeclarativeAnchors::tr("Possible anchor loop detected on fill.");
+ }
+
+}
+
+void QDeclarativeAnchorsPrivate::centerInChanged()
+{
+ Q_Q(QDeclarativeAnchors);
+ 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) << QDeclarativeAnchors::tr("Possible anchor loop detected on centerIn.");
+ }
+}
+
+void QDeclarativeAnchorsPrivate::clearItem(QGraphicsObject *item)
+{
+ if (!item)
+ return;
+ if (fill == item)
+ fill = 0;
+ if (centerIn == item)
+ centerIn = 0;
+ if (left.item == item) {
+ left.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::LeftAnchor;
+ }
+ if (right.item == item) {
+ right.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::RightAnchor;
+ }
+ if (top.item == item) {
+ top.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::TopAnchor;
+ }
+ if (bottom.item == item) {
+ bottom.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::BottomAnchor;
+ }
+ if (vCenter.item == item) {
+ vCenter.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::VCenterAnchor;
+ }
+ if (hCenter.item == item) {
+ hCenter.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::HCenterAnchor;
+ }
+ if (baseline.item == item) {
+ baseline.item = 0;
+ usedAnchors &= ~QDeclarativeAnchors::BaselineAnchor;
+ }
+}
+
+void QDeclarativeAnchorsPrivate::addDepend(QGraphicsObject *item)
+{
+ if (!item)
+ return;
+ QGraphicsItemPrivate * itemPrivate = QGraphicsItemPrivate::get(item);
+ if (itemPrivate->isDeclarativeItem) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(item));
+ p->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ } else if(itemPrivate->isWidget) {
+ Q_Q(QDeclarativeAnchors);
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ QObject::connect(widget, SIGNAL(destroyed(QObject*)), q, SLOT(_q_widgetDestroyed(QObject*)));
+ QObject::connect(widget, SIGNAL(geometryChanged()), q, SLOT(_q_widgetGeometryChanged()));
+ }
+}
+
+void QDeclarativeAnchorsPrivate::remDepend(QGraphicsObject *item)
+{
+ if (!item)
+ return;
+ QGraphicsItemPrivate * itemPrivate = QGraphicsItemPrivate::get(item);
+ if (itemPrivate->isDeclarativeItem) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(itemPrivate);
+ p->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ } else if(itemPrivate->isWidget) {
+ Q_Q(QDeclarativeAnchors);
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
+ QObject::disconnect(widget, SIGNAL(destroyed(QObject*)), q, SLOT(_q_widgetDestroyed(QObject*)));
+ QObject::disconnect(widget, SIGNAL(geometryChanged()), q, SLOT(_q_widgetGeometryChanged()));
+ }
+}
+
+bool QDeclarativeAnchorsPrivate::isItemComplete() const
+{
+ return componentComplete;
+}
+
+void QDeclarativeAnchors::classBegin()
+{
+ Q_D(QDeclarativeAnchors);
+ d->componentComplete = false;
+}
+
+void QDeclarativeAnchors::componentComplete()
+{
+ Q_D(QDeclarativeAnchors);
+ d->componentComplete = true;
+}
+
+bool QDeclarativeAnchors::mirrored()
+{
+ Q_D(QDeclarativeAnchors);
+ QGraphicsItemPrivate * itemPrivate = QGraphicsItemPrivate::get(d->item);
+ return itemPrivate->isDeclarativeItem ? static_cast<QDeclarativeItemPrivate *>(itemPrivate)->effectiveLayoutMirror : false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemHeight(qreal v)
+{
+ updatingMe = true;
+ QGraphicsItemPrivate::get(item)->setHeight(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemWidth(qreal v)
+{
+ updatingMe = true;
+ QGraphicsItemPrivate::get(item)->setWidth(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemX(qreal v)
+{
+ updatingMe = true;
+ item->setX(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemY(qreal v)
+{
+ updatingMe = true;
+ item->setY(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemPos(const QPointF &v)
+{
+ updatingMe = true;
+ item->setPos(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::setItemSize(const QSizeF &v)
+{
+ updatingMe = true;
+ if(QGraphicsItemPrivate::get(item)->isWidget)
+ static_cast<QGraphicsWidget *>(item)->resize(v);
+ else if (QGraphicsItemPrivate::get(item)->isDeclarativeItem)
+ static_cast<QDeclarativeItem *>(item)->setSize(v);
+ updatingMe = false;
+}
+
+void QDeclarativeAnchorsPrivate::updateMe()
+{
+ if (updatingMe) {
+ updatingMe = false;
+ return;
+ }
+
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QDeclarativeAnchorsPrivate::updateOnComplete()
+{
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QDeclarativeAnchorsPrivate::_q_widgetDestroyed(QObject *obj)
+{
+ clearItem(qobject_cast<QGraphicsObject*>(obj));
+}
+
+void QDeclarativeAnchorsPrivate::_q_widgetGeometryChanged()
+{
+ fillChanged();
+ centerInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QDeclarativeAnchorsPrivate::itemGeometryChanged(QDeclarativeItem *, 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();
+}
+
+QGraphicsObject *QDeclarativeAnchors::fill() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->fill;
+}
+
+void QDeclarativeAnchors::setFill(QGraphicsObject *f)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetFill()
+{
+ setFill(0);
+}
+
+QGraphicsObject *QDeclarativeAnchors::centerIn() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->centerIn;
+}
+
+void QDeclarativeAnchors::setCenterIn(QGraphicsObject* c)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+bool QDeclarativeAnchorsPrivate::calcStretch(const QDeclarativeAnchorLine &edge1,
+ const QDeclarativeAnchorLine &edge2,
+ qreal offset1,
+ qreal offset2,
+ QDeclarativeAnchorLine::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->parentObject(), line)
+ + position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsSibling && edge1IsParent) {
+ stretch = (position(item->parentObject(), line) + position(edge2.item, edge2.anchorLine) + offset2)
+ - (position(edge1.item, edge1.anchorLine) + offset1);
+ } else
+ invalid = true;
+
+ return invalid;
+}
+
+void QDeclarativeAnchorsPrivate::updateVerticalAnchors()
+{
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingVerticalAnchor < 2) {
+ ++updatingVerticalAnchor;
+ QGraphicsItemPrivate *itemPrivate = QGraphicsItemPrivate::get(item);
+ if (usedAnchors & QDeclarativeAnchors::TopAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal height = 0.0;
+ if (usedAnchors & QDeclarativeAnchors::BottomAnchor) {
+ invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QDeclarativeAnchorLine::Top, height);
+ } else if (usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
+ invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QDeclarativeAnchorLine::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 & QDeclarativeAnchors::BottomAnchor) {
+ //Handle stretching (top + bottom case is handled above)
+ if (usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
+ qreal height = 0.0;
+ bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
+ QDeclarativeAnchorLine::Top, height);
+ if (!invalid)
+ setItemHeight(height*2);
+ }
+
+ //Handle bottom
+ if (bottom.item == item->parentItem()) {
+ setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - itemPrivate->height() - bottomMargin);
+ } else if (bottom.item->parentItem() == item->parentItem()) {
+ setItemY(position(bottom.item, bottom.anchorLine) - itemPrivate->height() - bottomMargin);
+ }
+ } else if (usedAnchors & QDeclarativeAnchors::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 & QDeclarativeAnchors::BaselineAnchor) {
+ //Handle baseline
+ if (baseline.item == item->parentItem()) {
+ if (itemPrivate->isDeclarativeItem)
+ setItemY(adjustedPosition(baseline.item, baseline.anchorLine)
+ - static_cast<QDeclarativeItem *>(item)->baselineOffset() + baselineOffset);
+ } else if (baseline.item->parentItem() == item->parentItem()) {
+ if (itemPrivate->isDeclarativeItem)
+ setItemY(position(baseline.item, baseline.anchorLine)
+ - static_cast<QDeclarativeItem *>(item)->baselineOffset() + baselineOffset);
+ }
+ }
+ --updatingVerticalAnchor;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << QDeclarativeAnchors::tr("Possible anchor loop detected on vertical anchor.");
+ }
+}
+
+inline QDeclarativeAnchorLine::AnchorLine reverseAnchorLine(QDeclarativeAnchorLine::AnchorLine anchorLine) {
+ if (anchorLine == QDeclarativeAnchorLine::Left) {
+ return QDeclarativeAnchorLine::Right;
+ } else if (anchorLine == QDeclarativeAnchorLine::Right) {
+ return QDeclarativeAnchorLine::Left;
+ } else {
+ return anchorLine;
+ }
+}
+
+void QDeclarativeAnchorsPrivate::updateHorizontalAnchors()
+{
+ Q_Q(QDeclarativeAnchors);
+ if (fill || centerIn || !isItemComplete())
+ return;
+
+ if (updatingHorizontalAnchor < 3) {
+ ++updatingHorizontalAnchor;
+ qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
+ QDeclarativeAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
+ QDeclarativeAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
+ if (q->mirrored()) {
+ effectiveLeftAnchor = QDeclarativeAnchors::RightAnchor;
+ effectiveRightAnchor = QDeclarativeAnchors::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 = QDeclarativeAnchors::LeftAnchor;
+ effectiveRightAnchor = QDeclarativeAnchors::RightAnchor;
+ effectiveLeft = left;
+ effectiveRight = right;
+ effectiveHorizontalCenter = hCenter;
+ effectiveLeftMargin = leftMargin;
+ effectiveRightMargin = rightMargin;
+ effectiveHorizontalCenterOffset = hCenterOffset;
+ }
+
+ QGraphicsItemPrivate *itemPrivate = QGraphicsItemPrivate::get(item);
+ if (usedAnchors & effectiveLeftAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ qreal width = 0.0;
+ if (usedAnchors & effectiveRightAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QDeclarativeAnchorLine::Left, width);
+ } else if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QDeclarativeAnchorLine::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 & QDeclarativeAnchors::HCenterAnchor) {
+ qreal width = 0.0;
+ bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
+ QDeclarativeAnchorLine::Left, width);
+ if (!invalid)
+ setItemWidth(width*2);
+ }
+
+ //Handle right
+ if (effectiveRight.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin);
+ } else if (effectiveRight.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin);
+ }
+ } else if (usedAnchors & QDeclarativeAnchors::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) << QDeclarativeAnchors::tr("Possible anchor loop detected on horizontal anchor.");
+ }
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::top() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->top;
+}
+
+void QDeclarativeAnchors::setTop(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetTop()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~TopAnchor;
+ d->remDepend(d->top.item);
+ d->top = QDeclarativeAnchorLine();
+ emit topChanged();
+ d->updateVerticalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::bottom() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->bottom;
+}
+
+void QDeclarativeAnchors::setBottom(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetBottom()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~BottomAnchor;
+ d->remDepend(d->bottom.item);
+ d->bottom = QDeclarativeAnchorLine();
+ emit bottomChanged();
+ d->updateVerticalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::verticalCenter() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->vCenter;
+}
+
+void QDeclarativeAnchors::setVerticalCenter(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetVerticalCenter()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~VCenterAnchor;
+ d->remDepend(d->vCenter.item);
+ d->vCenter = QDeclarativeAnchorLine();
+ emit verticalCenterChanged();
+ d->updateVerticalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::baseline() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->baseline;
+}
+
+void QDeclarativeAnchors::setBaseline(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetBaseline()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~BaselineAnchor;
+ d->remDepend(d->baseline.item);
+ d->baseline = QDeclarativeAnchorLine();
+ emit baselineChanged();
+ d->updateVerticalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::left() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->left;
+}
+
+void QDeclarativeAnchors::setLeft(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetLeft()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~LeftAnchor;
+ d->remDepend(d->left.item);
+ d->left = QDeclarativeAnchorLine();
+ emit leftChanged();
+ d->updateHorizontalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::right() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->right;
+}
+
+void QDeclarativeAnchors::setRight(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetRight()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~RightAnchor;
+ d->remDepend(d->right.item);
+ d->right = QDeclarativeAnchorLine();
+ emit rightChanged();
+ d->updateHorizontalAnchors();
+}
+
+QDeclarativeAnchorLine QDeclarativeAnchors::horizontalCenter() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->hCenter;
+}
+
+void QDeclarativeAnchors::setHorizontalCenter(const QDeclarativeAnchorLine &edge)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::resetHorizontalCenter()
+{
+ Q_D(QDeclarativeAnchors);
+ d->usedAnchors &= ~HCenterAnchor;
+ d->remDepend(d->hCenter.item);
+ d->hCenter = QDeclarativeAnchorLine();
+ emit horizontalCenterChanged();
+ d->updateHorizontalAnchors();
+}
+
+qreal QDeclarativeAnchors::leftMargin() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->leftMargin;
+}
+
+void QDeclarativeAnchors::setLeftMargin(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->leftMargin == offset)
+ return;
+ d->leftMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit leftMarginChanged();
+}
+
+qreal QDeclarativeAnchors::rightMargin() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->rightMargin;
+}
+
+void QDeclarativeAnchors::setRightMargin(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->rightMargin == offset)
+ return;
+ d->rightMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit rightMarginChanged();
+}
+
+qreal QDeclarativeAnchors::margins() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->margins;
+}
+
+void QDeclarativeAnchors::setMargins(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ 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 QDeclarativeAnchors::horizontalCenterOffset() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->hCenterOffset;
+}
+
+void QDeclarativeAnchors::setHorizontalCenterOffset(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->hCenterOffset == offset)
+ return;
+ d->hCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateHorizontalAnchors();
+ emit horizontalCenterOffsetChanged();
+}
+
+qreal QDeclarativeAnchors::topMargin() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->topMargin;
+}
+
+void QDeclarativeAnchors::setTopMargin(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->topMargin == offset)
+ return;
+ d->topMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit topMarginChanged();
+}
+
+qreal QDeclarativeAnchors::bottomMargin() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->bottomMargin;
+}
+
+void QDeclarativeAnchors::setBottomMargin(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->bottomMargin == offset)
+ return;
+ d->bottomMargin = offset;
+ if(d->fill)
+ d->fillChanged();
+ else
+ d->updateVerticalAnchors();
+ emit bottomMarginChanged();
+}
+
+qreal QDeclarativeAnchors::verticalCenterOffset() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->vCenterOffset;
+}
+
+void QDeclarativeAnchors::setVerticalCenterOffset(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->vCenterOffset == offset)
+ return;
+ d->vCenterOffset = offset;
+ if(d->centerIn)
+ d->centerInChanged();
+ else
+ d->updateVerticalAnchors();
+ emit verticalCenterOffsetChanged();
+}
+
+qreal QDeclarativeAnchors::baselineOffset() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->baselineOffset;
+}
+
+void QDeclarativeAnchors::setBaselineOffset(qreal offset)
+{
+ Q_D(QDeclarativeAnchors);
+ if (d->baselineOffset == offset)
+ return;
+ d->baselineOffset = offset;
+ d->updateVerticalAnchors();
+ emit baselineOffsetChanged();
+}
+
+QDeclarativeAnchors::Anchors QDeclarativeAnchors::usedAnchors() const
+{
+ Q_D(const QDeclarativeAnchors);
+ return d->usedAnchors;
+}
+
+bool QDeclarativeAnchorsPrivate::checkHValid() const
+{
+ if (usedAnchors & QDeclarativeAnchors::LeftAnchor &&
+ usedAnchors & QDeclarativeAnchors::RightAnchor &&
+ usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot specify left, right, and hcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QDeclarativeAnchorsPrivate::checkHAnchorValid(QDeclarativeAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QDeclarativeAnchorLine::Vertical_Mask) {
+ qmlInfo(item) << QDeclarativeAnchors::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) << QDeclarativeAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QDeclarativeAnchorsPrivate::checkVValid() const
+{
+ if (usedAnchors & QDeclarativeAnchors::TopAnchor &&
+ usedAnchors & QDeclarativeAnchors::BottomAnchor &&
+ usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot specify top, bottom, and vcenter anchors.");
+ return false;
+ } else if (usedAnchors & QDeclarativeAnchors::BaselineAnchor &&
+ (usedAnchors & QDeclarativeAnchors::TopAnchor ||
+ usedAnchors & QDeclarativeAnchors::BottomAnchor ||
+ usedAnchors & QDeclarativeAnchors::VCenterAnchor)) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QDeclarativeAnchorsPrivate::checkVAnchorValid(QDeclarativeAnchorLine anchor) const
+{
+ if (!anchor.item) {
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot anchor to a null item.");
+ return false;
+ } else if (anchor.anchorLine & QDeclarativeAnchorLine::Horizontal_Mask) {
+ qmlInfo(item) << QDeclarativeAnchors::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) << QDeclarativeAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
+ return false;
+ } else if (anchor.item == item){
+ qmlInfo(item) << QDeclarativeAnchors::tr("Cannot anchor item to self.");
+ return false;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qdeclarativeanchors_p.cpp>
+
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p.h
new file mode 100644
index 0000000000..388d6b9c34
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanchors_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEANCHORS_H
+#define QDECLARATIVEANCHORS_H
+
+#include "qdeclarativeitem.h"
+
+#include <qdeclarative.h>
+
+#include <QtCore/QObject>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeAnchorsPrivate;
+class QDeclarativeAnchorLine;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAnchors : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeAnchorLine left READ left WRITE setLeft RESET resetLeft NOTIFY leftChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine right READ right WRITE setRight RESET resetRight NOTIFY rightChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter NOTIFY horizontalCenterChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine top READ top WRITE setTop RESET resetTop NOTIFY topChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom NOTIFY bottomChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter NOTIFY verticalCenterChanged)
+ Q_PROPERTY(QDeclarativeAnchorLine 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(QGraphicsObject *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged)
+ Q_PROPERTY(QGraphicsObject *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
+ Q_PROPERTY(bool mirrored READ mirrored NOTIFY mirroredChanged REVISION 1)
+
+public:
+ QDeclarativeAnchors(QObject *parent=0);
+ QDeclarativeAnchors(QGraphicsObject *item, QObject *parent=0);
+ virtual ~QDeclarativeAnchors();
+
+ 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)
+
+ QDeclarativeAnchorLine left() const;
+ void setLeft(const QDeclarativeAnchorLine &edge);
+ void resetLeft();
+
+ QDeclarativeAnchorLine right() const;
+ void setRight(const QDeclarativeAnchorLine &edge);
+ void resetRight();
+
+ QDeclarativeAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QDeclarativeAnchorLine &edge);
+ void resetHorizontalCenter();
+
+ QDeclarativeAnchorLine top() const;
+ void setTop(const QDeclarativeAnchorLine &edge);
+ void resetTop();
+
+ QDeclarativeAnchorLine bottom() const;
+ void setBottom(const QDeclarativeAnchorLine &edge);
+ void resetBottom();
+
+ QDeclarativeAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QDeclarativeAnchorLine &edge);
+ void resetVerticalCenter();
+
+ QDeclarativeAnchorLine baseline() const;
+ void setBaseline(const QDeclarativeAnchorLine &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);
+
+ QGraphicsObject *fill() const;
+ void setFill(QGraphicsObject *);
+ void resetFill();
+
+ QGraphicsObject *centerIn() const;
+ void setCenterIn(QGraphicsObject *);
+ void resetCenterIn();
+
+ Anchors usedAnchors() const;
+
+ void classBegin();
+ void componentComplete();
+
+ bool mirrored();
+
+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();
+ Q_REVISION(1) void mirroredChanged();
+
+private:
+ friend class QDeclarativeItem;
+ friend class QDeclarativeItemPrivate;
+ friend class QDeclarativeGraphicsWidget;
+ Q_DISABLE_COPY(QDeclarativeAnchors)
+ Q_DECLARE_PRIVATE(QDeclarativeAnchors)
+ Q_PRIVATE_SLOT(d_func(), void _q_widgetGeometryChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_widgetDestroyed(QObject *obj))
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeAnchors::Anchors)
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeAnchors)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h
new file mode 100644
index 0000000000..d8d2f15bb6
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEANCHORS_P_H
+#define QDECLARATIVEANCHORS_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/qdeclarativeanchors_p.h"
+#include "private/qdeclarativeitemchangelistener_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAnchorLine
+{
+public:
+ QDeclarativeAnchorLine() : 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
+ };
+
+ QGraphicsObject *item;
+ AnchorLine anchorLine;
+};
+
+inline bool operator==(const QDeclarativeAnchorLine& a, const QDeclarativeAnchorLine& b)
+{
+ return a.item == b.item && a.anchorLine == b.anchorLine;
+}
+
+class QDeclarativeAnchorsPrivate : public QObjectPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnchors)
+public:
+ QDeclarativeAnchorsPrivate(QGraphicsObject *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(QGraphicsObject *);
+
+ void addDepend(QGraphicsObject *);
+ void remDepend(QGraphicsObject *);
+ 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();
+
+ // QDeclarativeItemGeometryListener interface
+ void itemGeometryChanged(QDeclarativeItem *, const QRectF &, const QRectF &);
+ void _q_widgetDestroyed(QObject *);
+ void _q_widgetGeometryChanged();
+ QDeclarativeAnchorsPrivate *anchorPrivate() { return this; }
+
+ bool checkHValid() const;
+ bool checkVValid() const;
+ bool checkHAnchorValid(QDeclarativeAnchorLine anchor) const;
+ bool checkVAnchorValid(QDeclarativeAnchorLine anchor) const;
+ bool calcStretch(const QDeclarativeAnchorLine &edge1, const QDeclarativeAnchorLine &edge2, qreal offset1, qreal offset2, QDeclarativeAnchorLine::AnchorLine line, qreal &stretch);
+
+ bool isMirrored() const;
+ void updateHorizontalAnchors();
+ void updateVerticalAnchors();
+ void fillChanged();
+ void centerInChanged();
+
+ QGraphicsObject *item;
+ QDeclarativeAnchors::Anchors usedAnchors;
+
+ QGraphicsObject *fill;
+ QGraphicsObject *centerIn;
+
+ QDeclarativeAnchorLine left;
+ QDeclarativeAnchorLine right;
+ QDeclarativeAnchorLine top;
+ QDeclarativeAnchorLine bottom;
+ QDeclarativeAnchorLine vCenter;
+ QDeclarativeAnchorLine hCenter;
+ QDeclarativeAnchorLine baseline;
+
+ qreal leftMargin;
+ qreal rightMargin;
+ qreal topMargin;
+ qreal bottomMargin;
+ qreal margins;
+ qreal vCenterOffset;
+ qreal hCenterOffset;
+ qreal baselineOffset;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeAnchorLine)
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp
new file mode 100644
index 0000000000..8cc81656e4
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeanimatedimage_p.h"
+#include "private/qdeclarativeanimatedimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <QMovie>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass AnimatedImage QDeclarativeAnimatedImage
+ \inherits Image
+ \since 4.7
+ \ingroup basic-visual-elements
+
+ The AnimatedImage element extends the features of the \l Image element, providing
+ a way to play animations stored as images containing a series of frames,
+ such as those stored in GIF files.
+
+ Information about the current frame and totla length of the animation can be
+ obtained using the \l currentFrame and \l frameCount properties. You can
+ start, pause and stop the animation by changing the values of the \l playing
+ and \l paused properties.
+
+ The full list of supported formats can be determined with QMovie::supportedFormats().
+
+ \section1 Example Usage
+
+ \beginfloatleft
+ \image animatedimageitem.gif
+ \endfloat
+
+ The following QML shows how to display an animated image and obtain information
+ about its state, such as the current frame and total number of frames.
+ The result is an animated image with a simple progress indicator underneath it.
+
+ \clearfloat
+ \snippet doc/src/snippets/declarative/animatedimage.qml document
+
+ \sa BorderImage, Image
+*/
+
+/*!
+ \qmlproperty bool AnimatedImage::cache
+ \since Quick 1.1
+
+ Specifies whether the image should be cached. The default value is
+ true. Setting \a cache to false is useful when dealing with large images,
+ to make sure that they aren't cached at the expense of small 'ui element' images.
+*/
+
+/*!
+ \qmlproperty bool AnimatedImage::mirror
+ \since Quick 1.1
+
+ This property holds whether the image should be horizontally inverted
+ (effectively displaying a mirrored image).
+
+ The default value is false.
+*/
+
+QDeclarativeAnimatedImage::QDeclarativeAnimatedImage(QDeclarativeItem *parent)
+ : QDeclarativeImage(*(new QDeclarativeAnimatedImagePrivate), parent)
+{
+}
+
+QDeclarativeAnimatedImage::~QDeclarativeAnimatedImage()
+{
+ Q_D(QDeclarativeAnimatedImage);
+ delete d->_movie;
+}
+
+/*!
+ \qmlproperty bool AnimatedImage::paused
+ This property holds whether the animated image is paused.
+
+ By default, this property is false. Set it to true when you want to pause
+ the animation.
+*/
+bool QDeclarativeAnimatedImage::isPaused() const
+{
+ Q_D(const QDeclarativeAnimatedImage);
+ if(!d->_movie)
+ return false;
+ return d->_movie->state()==QMovie::Paused;
+}
+
+void QDeclarativeAnimatedImage::setPaused(bool pause)
+{
+ Q_D(QDeclarativeAnimatedImage);
+ if(pause == d->paused)
+ return;
+ d->paused = pause;
+ if(!d->_movie)
+ return;
+ d->_movie->setPaused(pause);
+}
+/*!
+ \qmlproperty bool AnimatedImage::playing
+ This property holds whether the animated image is playing.
+
+ By default, this property is true, meaning that the animation
+ will start playing immediately.
+*/
+bool QDeclarativeAnimatedImage::isPlaying() const
+{
+ Q_D(const QDeclarativeAnimatedImage);
+ if (!d->_movie)
+ return false;
+ return d->_movie->state()!=QMovie::NotRunning;
+}
+
+void QDeclarativeAnimatedImage::setPlaying(bool play)
+{
+ Q_D(QDeclarativeAnimatedImage);
+ if(play == d->playing)
+ return;
+ d->playing = play;
+ if (!d->_movie)
+ return;
+ if (play)
+ d->_movie->start();
+ else
+ d->_movie->stop();
+}
+
+/*!
+ \qmlproperty int AnimatedImage::currentFrame
+ \qmlproperty int AnimatedImage::frameCount
+
+ currentFrame is the frame that is currently visible. By monitoring this property
+ for changes, you can animate other items at the same time as the image.
+
+ frameCount is the number of frames in the animation. For some animation formats,
+ frameCount is unknown and has a value of zero.
+*/
+int QDeclarativeAnimatedImage::currentFrame() const
+{
+ Q_D(const QDeclarativeAnimatedImage);
+ if (!d->_movie)
+ return d->preset_currentframe;
+ return d->_movie->currentFrameNumber();
+}
+
+void QDeclarativeAnimatedImage::setCurrentFrame(int frame)
+{
+ Q_D(QDeclarativeAnimatedImage);
+ if (!d->_movie) {
+ d->preset_currentframe = frame;
+ return;
+ }
+ d->_movie->jumpToFrame(frame);
+}
+
+int QDeclarativeAnimatedImage::frameCount() const
+{
+ Q_D(const QDeclarativeAnimatedImage);
+ if (!d->_movie)
+ return 0;
+ return d->_movie->frameCount();
+}
+
+void QDeclarativeAnimatedImage::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeAnimatedImage);
+ 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 QDeclarativeAnimatedImage::load()
+{
+ Q_D(QDeclarativeAnimatedImage);
+
+ QDeclarativeImageBase::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 QDeclarativeAnimatedImage::movieRequestFinished()
+{
+ Q_D(QDeclarativeAnimatedImage);
+
+ 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 QDeclarativeAnimatedImage::movieUpdate()
+{
+ Q_D(QDeclarativeAnimatedImage);
+ d->setPixmap(d->_movie->currentPixmap());
+ emit frameChanged();
+}
+
+void QDeclarativeAnimatedImage::playingStatusChanged()
+{
+ Q_D(QDeclarativeAnimatedImage);
+ 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 QDeclarativeAnimatedImage::componentComplete()
+{
+ Q_D(QDeclarativeAnimatedImage);
+ QDeclarativeItem::componentComplete(); // NOT QDeclarativeImage
+ 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/graphicsitems/qdeclarativeanimatedimage_p.h b/src/declarative/graphicsitems/qdeclarativeanimatedimage_p.h
new file mode 100644
index 0000000000..e2ed70b02e
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage_p.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 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 QDECLARATIVEANIMATEDIMAGE_H
+#define QDECLARATIVEANIMATEDIMAGE_H
+
+#include "private/qdeclarativeimage_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMovie;
+class QDeclarativeAnimatedImagePrivate;
+
+class Q_AUTOTEST_EXPORT QDeclarativeAnimatedImage : public QDeclarativeImage
+{
+ 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:
+ QDeclarativeAnimatedImage(QDeclarativeItem *parent=0);
+ ~QDeclarativeAnimatedImage();
+
+ 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 QDeclarativeImage'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(QDeclarativeAnimatedImage)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeAnimatedImage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeAnimatedImage)
+
+QT_END_HEADER
+
+#endif // QT_NO_MOVIE
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeanimatedimage_p_p.h b/src/declarative/graphicsitems/qdeclarativeanimatedimage_p_p.h
new file mode 100644
index 0000000000..eea92bbcb9
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage_p_p.h
@@ -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 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 QDECLARATIVEANIMATEDIMAGE_P_H
+#define QDECLARATIVEANIMATEDIMAGE_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/qdeclarativeimage_p_p.h"
+
+#ifndef QT_NO_MOVIE
+
+QT_BEGIN_NAMESPACE
+
+class QMovie;
+class QNetworkReply;
+
+class QDeclarativeAnimatedImagePrivate : public QDeclarativeImagePrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnimatedImage)
+
+public:
+ QDeclarativeAnimatedImagePrivate()
+ : 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 // QDECLARATIVEANIMATEDIMAGE_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp
new file mode 100644
index 0000000000..45a03a0432
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp
@@ -0,0 +1,619 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeborderimage_p.h"
+#include "private/qdeclarativeborderimage_p_p.h"
+
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QFile>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass BorderImage QDeclarativeBorderImage
+ \brief The BorderImage element provides an image that can be used as a border.
+ \inherits Item
+ \since 4.7
+ \ingroup qml-basic-visual-elements
+
+ The BorderImage element is used to create borders out of images by scaling or tiling
+ parts of each image.
+
+ A BorderImage element breaks a source image, specified using the \l url property,
+ into 9 regions, as shown below:
+
+ \image declarative-scalegrid.png
+
+ When the image is scaled, regions of the source image are scaled or tiled to
+ create the displayed border image in the following way:
+
+ \list
+ \i The corners (regions 1, 3, 7, and 9) are not scaled at all.
+ \i Regions 2 and 8 are scaled according to
+ \l{BorderImage::horizontalTileMode}{horizontalTileMode}.
+ \i Regions 4 and 6 are scaled according to
+ \l{BorderImage::verticalTileMode}{verticalTileMode}.
+ \i The middle (region 5) is scaled according to both
+ \l{BorderImage::horizontalTileMode}{horizontalTileMode} and
+ \l{BorderImage::verticalTileMode}{verticalTileMode}.
+ \endlist
+
+ The regions of the image are defined using the \l border property group, which
+ describes the distance from each edge of the source image to use as a border.
+
+ \section1 Example Usage
+
+ The following examples show the effects of the different modes on an image.
+ Guide lines are overlaid onto the image to show the different regions of the
+ image as described above.
+
+ \beginfloatleft
+ \image qml-borderimage-normal-image.png
+ \endfloat
+
+ An unscaled image is displayed using an Image element. The \l border property is
+ used to determine the parts of the image that will lie inside the unscaled corner
+ areas and the parts that will be stretched horizontally and vertically.
+
+ \snippet doc/src/snippets/declarative/borderimage/normal-image.qml normal image
+
+ \clearfloat
+ \beginfloatleft
+ \image qml-borderimage-scaled.png
+ \endfloat
+
+ A BorderImage element is used to display the image, and it is given a size that is
+ larger than the original image. Since the \l horizontalTileMode property is set to
+ \l{BorderImage::horizontalTileMode}{BorderImage.Stretch}, the parts of image in
+ regions 2 and 8 are stretched horizontally. Since the \l verticalTileMode property
+ is set to \l{BorderImage::verticalTileMode}{BorderImage.Stretch}, the parts of image
+ in regions 4 and 6 are stretched vertically.
+
+ \snippet doc/src/snippets/declarative/borderimage/borderimage-scaled.qml scaled border image
+
+ \clearfloat
+ \beginfloatleft
+ \image qml-borderimage-tiled.png
+ \endfloat
+
+ Again, a large BorderImage element is used to display the image. With the
+ \l horizontalTileMode property set to \l{BorderImage::horizontalTileMode}{BorderImage.Repeat},
+ the parts of image in regions 2 and 8 are tiled so that they fill the space at the
+ top and bottom of the element. Similarly, the \l verticalTileMode property is set to
+ \l{BorderImage::verticalTileMode}{BorderImage.Repeat}, the parts of image in regions
+ 4 and 6 are tiled so that they fill the space at the left and right of the element.
+
+ \snippet doc/src/snippets/declarative/borderimage/borderimage-tiled.qml tiled border image
+
+ \clearfloat
+ In some situations, the width of regions 2 and 8 may not be an exact multiple of the width
+ of the corresponding regions in the source image. Similarly, the height of regions 4 and 6
+ may not be an exact multiple of the height of the corresponding regions. It can be useful
+ to use \l{BorderImage::horizontalTileMode}{BorderImage.Round} instead of
+ \l{BorderImage::horizontalTileMode}{BorderImage.Repeat} in cases like these.
+
+ The \l{declarative/imageelements/borderimage}{BorderImage example} shows how a BorderImage
+ can be used to simulate a shadow effect on a rectangular item.
+
+ \section1 Quality and Performance
+
+ By default, any scaled regions of the image are rendered without smoothing to improve
+ rendering speed. Setting the \l smooth property improves rendering quality of scaled
+ regions, but may slow down rendering.
+
+ The source image may not be loaded instantaneously, depending on its original location.
+ Loading progress can be monitored with the \l progress property.
+
+ \sa Image, AnimatedImage
+ */
+
+/*!
+ \qmlproperty bool BorderImage::asynchronous
+
+ Specifies that images on the local filesystem should be loaded
+ asynchronously in a separate thread. The default value is
+ false, causing the user interface thread to block while the
+ image is loaded. Setting \a asynchronous to true is useful where
+ maintaining a responsive user interface is more desirable
+ than having images immediately visible.
+
+ Note that this property is only valid for images read from the
+ local filesystem. Images loaded via a network resource (e.g. HTTP)
+ are always loaded asynchonously.
+*/
+QDeclarativeBorderImage::QDeclarativeBorderImage(QDeclarativeItem *parent)
+ : QDeclarativeImageBase(*(new QDeclarativeBorderImagePrivate), parent)
+{
+}
+
+QDeclarativeBorderImage::~QDeclarativeBorderImage()
+{
+ Q_D(QDeclarativeBorderImage);
+ if (d->sciReply)
+ d->sciReply->deleteLater();
+}
+/*!
+ \qmlproperty enumeration BorderImage::status
+
+ This property describes the status of image loading. It can be one of:
+
+ \list
+ \o BorderImage.Null - no image has been set
+ \o BorderImage.Ready - the image has been loaded
+ \o BorderImage.Loading - the image is currently being loaded
+ \o BorderImage.Error - an error occurred while loading the image
+ \endlist
+
+ \sa progress
+*/
+
+/*!
+ \qmlproperty real BorderImage::progress
+
+ This property holds the progress of image loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+
+/*!
+ \qmlproperty bool BorderImage::smooth
+
+ Set this property if you want the image to be smoothly filtered when scaled or
+ transformed. Smooth filtering gives better visual quality, but is slower. If
+ the image is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ By default, this property is set to false.
+
+ \note Generally scaling artifacts are only visible if the image is stationary on
+ the screen. A common pattern when animating an image is to disable smooth
+ filtering at the beginning of the animation and enable it at the conclusion.
+*/
+
+/*!
+ \qmlproperty bool BorderImage::cache
+ \since Quick 1.1
+
+ Specifies whether the image should be cached. The default value is
+ true. Setting \a cache to false is useful when dealing with large images,
+ to make sure that they aren't cached at the expense of small 'ui element' images.
+*/
+
+/*!
+ \qmlproperty bool BorderImage::mirror
+ \since Quick 1.1
+
+ This property holds whether the image should be horizontally inverted
+ (effectively displaying a mirrored image).
+
+ The default value is false.
+*/
+
+/*!
+ \qmlproperty url BorderImage::source
+
+ This property holds the URL that refers to the source image.
+
+ BorderImage can handle any image format supported by Qt, loaded from any
+ URL scheme supported by Qt.
+
+ It can also handle .sci files, which are a QML-specific format. A .sci
+ file uses a simple text-based format that specifies the borders, the
+ image file and the tile rules.
+
+ The following .sci file sets the borders to 10 on each side for the
+ image \c picture.png:
+
+ \qml
+ BorderImage {
+ border.left: 10
+ border.top: 10
+ border.bottom: 10
+ border.right: 10
+ source: "picture.png"
+ }
+ \endqml
+
+ The URL may be absolute, or relative to the URL of the component.
+
+ \sa QDeclarativeImageProvider
+*/
+
+/*!
+ \qmlproperty QSize BorderImage::sourceSize
+
+ This property holds the actual width and height of the loaded image.
+
+ In BorderImage, this property is read-only.
+
+ \sa Image::sourceSize
+*/
+void QDeclarativeBorderImage::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeBorderImage);
+ //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 QDeclarativeBorderImage::load()
+{
+ Q_D(QDeclarativeBorderImage);
+ 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(QDeclarativeGridScaledImage(&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 =
+ QDeclarativeBorderImage::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);
+ requestFinished();
+ update();
+ }
+ }
+ }
+
+ emit statusChanged(d->status);
+}
+
+/*!
+ \qmlproperty int BorderImage::border.left
+ \qmlproperty int BorderImage::border.right
+ \qmlproperty int BorderImage::border.top
+ \qmlproperty int BorderImage::border.bottom
+
+ The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections,
+ as shown below:
+
+ \image declarative-scalegrid.png
+
+ Each border line (left, right, top, and bottom) specifies an offset in pixels
+ from the respective edge of the source image. By default, each border line has
+ a value of 0.
+
+ For example, the following definition sets the bottom line 10 pixels up from
+ the bottom of the image:
+
+ \qml
+ BorderImage {
+ border.bottom: 10
+ // ...
+ }
+ \endqml
+
+ The border lines can also be specified using a
+ \l {BorderImage::source}{.sci file}.
+*/
+
+QDeclarativeScaleGrid *QDeclarativeBorderImage::border()
+{
+ Q_D(QDeclarativeBorderImage);
+ return d->getScaleGrid();
+}
+
+/*!
+ \qmlproperty enumeration BorderImage::horizontalTileMode
+ \qmlproperty enumeration BorderImage::verticalTileMode
+
+ This property describes how to repeat or stretch the middle parts of the border image.
+
+ \list
+ \o BorderImage.Stretch - Scales the image to fit to the available area.
+ \o BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
+ \o BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
+ \endlist
+
+ The default tile mode for each property is BorderImage.Stretch.
+*/
+QDeclarativeBorderImage::TileMode QDeclarativeBorderImage::horizontalTileMode() const
+{
+ Q_D(const QDeclarativeBorderImage);
+ return d->horizontalTileMode;
+}
+
+void QDeclarativeBorderImage::setHorizontalTileMode(TileMode t)
+{
+ Q_D(QDeclarativeBorderImage);
+ if (t != d->horizontalTileMode) {
+ d->horizontalTileMode = t;
+ emit horizontalTileModeChanged();
+ update();
+ }
+}
+
+QDeclarativeBorderImage::TileMode QDeclarativeBorderImage::verticalTileMode() const
+{
+ Q_D(const QDeclarativeBorderImage);
+ return d->verticalTileMode;
+}
+
+void QDeclarativeBorderImage::setVerticalTileMode(TileMode t)
+{
+ Q_D(QDeclarativeBorderImage);
+ if (t != d->verticalTileMode) {
+ d->verticalTileMode = t;
+ emit verticalTileModeChanged();
+ update();
+ }
+}
+
+void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledImage& sci)
+{
+ Q_D(QDeclarativeBorderImage);
+ if (!sci.isValid()) {
+ d->status = Error;
+ emit statusChanged(d->status);
+ } else {
+ QDeclarativeScaleGrid *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 =
+ QDeclarativeBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QDeclarativeBorderImage::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 QDeclarativeBorderImage::requestFinished()
+{
+ Q_D(QDeclarativeBorderImage);
+
+ 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 QDeclarativeBorderImage::sciRequestFinished()
+{
+ Q_D(QDeclarativeBorderImage);
+
+ 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 {
+ QDeclarativeGridScaledImage sci(d->sciReply);
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ setGridScaledImage(sci);
+ }
+}
+
+void QDeclarativeBorderImage::doUpdate()
+{
+ update();
+}
+
+void QDeclarativeBorderImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ Q_D(QDeclarativeBorderImage);
+ if (d->pix.isNull() || d->width() <= 0.0 || d->height() <= 0.0)
+ return;
+
+ bool oldAA = p->testRenderHint(QPainter::Antialiasing);
+ bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
+ QTransform oldTransform;
+ if (d->smooth)
+ p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
+ if (d->mirror) {
+ oldTransform = p->transform();
+ QTransform mirror;
+ mirror.translate(d->width(), 0).scale(-1, 1.0);
+ p->setWorldTransform(mirror * oldTransform);
+ }
+
+ const QDeclarativeScaleGrid *border = d->getScaleGrid();
+ int left = border->left();
+ int right = border->right();
+ qreal borderWidth = left + right;
+ if (borderWidth > 0.0 && d->width() < borderWidth) {
+ qreal diff = borderWidth - d->width() - 1;
+ left -= qRound(diff * qreal(left) / borderWidth);
+ right -= qRound(diff * qreal(right) / borderWidth);
+ }
+ int top = border->top();
+ int bottom = border->bottom();
+ qreal borderHeight = top + bottom;
+ if (borderHeight > 0.0 && d->height() < borderHeight) {
+ qreal diff = borderHeight - d->height() - 1;
+ top -= qRound(diff * qreal(top) / borderHeight);
+ bottom -= qRound(diff * qreal(bottom) / borderHeight);
+ }
+ QMargins margins(left, top, right, bottom);
+ QTileRules rules((Qt::TileRule)d->horizontalTileMode, (Qt::TileRule)d->verticalTileMode);
+ qDrawBorderPixmap(p, QRect(0, 0, (int)d->width(), (int)d->height()), margins, d->pix, d->pix.rect(), margins, rules);
+ if (d->smooth) {
+ p->setRenderHint(QPainter::Antialiasing, oldAA);
+ p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
+ }
+ if (d->mirror)
+ p->setWorldTransform(oldTransform);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h
new file mode 100644
index 0000000000..f4c6594d27
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h
@@ -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 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 QDECLARATIVEBORDERIMAGE_H
+#define QDECLARATIVEBORDERIMAGE_H
+
+#include "private/qdeclarativeimagebase_p.h"
+
+#include <QtNetwork/qnetworkreply.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeScaleGrid;
+class QDeclarativeGridScaledImage;
+class QDeclarativeBorderImagePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeBorderImage : public QDeclarativeImageBase
+{
+ Q_OBJECT
+ Q_ENUMS(TileMode)
+
+ Q_PROPERTY(QDeclarativeScaleGrid *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:
+ QDeclarativeBorderImage(QDeclarativeItem *parent=0);
+ ~QDeclarativeBorderImage();
+
+ QDeclarativeScaleGrid *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 paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+ void setSource(const QUrl &url);
+
+Q_SIGNALS:
+ void horizontalTileModeChanged();
+ void verticalTileModeChanged();
+ void sourceSizeChanged();
+
+protected:
+ virtual void load();
+
+private:
+ void setGridScaledImage(const QDeclarativeGridScaledImage& sci);
+
+private Q_SLOTS:
+ void doUpdate();
+ void requestFinished();
+ void sciRequestFinished();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeBorderImage)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeBorderImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QDeclarativeBorderImage)
+QT_END_HEADER
+
+#endif // QDECLARATIVEBORDERIMAGE_H
diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h
new file mode 100644
index 0000000000..e36045db2b
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.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 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 QDECLARATIVEBORDERIMAGE_P_H
+#define QDECLARATIVEBORDERIMAGE_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/qdeclarativeimagebase_p_p.h"
+#include "private/qdeclarativescalegrid_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QDeclarativeBorderImagePrivate : public QDeclarativeImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeBorderImage)
+
+public:
+ QDeclarativeBorderImagePrivate()
+ : border(0), sciReply(0),
+ horizontalTileMode(QDeclarativeBorderImage::Stretch),
+ verticalTileMode(QDeclarativeBorderImage::Stretch),
+ redirectCount(0)
+ {
+ }
+
+ ~QDeclarativeBorderImagePrivate()
+ {
+ }
+
+
+ QDeclarativeScaleGrid *getScaleGrid()
+ {
+ Q_Q(QDeclarativeBorderImage);
+ if (!border) {
+ border = new QDeclarativeScaleGrid(q);
+ static int borderChangedSignalIdx = -1;
+ static int doUpdateSlotIdx = -1;
+ if (borderChangedSignalIdx < 0)
+ borderChangedSignalIdx = QDeclarativeScaleGrid::staticMetaObject.indexOfSignal("borderChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QDeclarativeBorderImage::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(border, borderChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return border;
+ }
+
+ QDeclarativeScaleGrid *border;
+ QUrl sciurl;
+ QNetworkReply *sciReply;
+ QDeclarativeBorderImage::TileMode horizontalTileMode;
+ QDeclarativeBorderImage::TileMode verticalTileMode;
+ int redirectCount;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEBORDERIMAGE_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeevents.cpp b/src/declarative/graphicsitems/qdeclarativeevents.cpp
new file mode 100644
index 0000000000..53421ddd4a
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeevents.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeevents_p_p.h"
+
+QT_BEGIN_NAMESPACE
+/*!
+ \qmlclass KeyEvent QDeclarativeKeyEvent
+ \since 4.7
+ \ingroup qml-event-elements
+
+ \brief The KeyEvent object provides information about a key event.
+
+ For example, the following changes the Item's state property when the Enter
+ key is pressed:
+ \qml
+Item {
+ focus: true
+ Keys.onPressed: { if (event.key == Qt.Key_Enter) state = 'ShowDetails'; }
+}
+ \endqml
+*/
+
+/*!
+ \qmlproperty int KeyEvent::key
+
+ This property holds the code of the key that was pressed or released.
+
+ See \l {Qt::Key}{Qt.Key} for the list of keyboard codes. These codes are
+ independent of the underlying window system. Note that this
+ function does not distinguish between capital and non-capital
+ letters, use the text() function (returning the Unicode text the
+ key generated) for this purpose.
+
+ A value of either 0 or \l {Qt::Key_unknown}{Qt.Key_Unknown} means that the event is not
+ the result of a known key; for example, it may be the result of
+ a compose sequence, a keyboard macro, or due to key event
+ compression.
+*/
+
+/*!
+ \qmlproperty string KeyEvent::text
+
+ This property holds the Unicode text that the key generated.
+ The text returned can be an empty string in cases where modifier keys,
+ such as Shift, Control, Alt, and Meta, are being pressed or released.
+ In such cases \c key will contain a valid value
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::isAutoRepeat
+
+ This property holds whether this event comes from an auto-repeating key.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::count
+
+ This property holds the number of keys involved in this event. If \l KeyEvent::text
+ is not empty, this is simply the length of the string.
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::accepted
+
+ Setting \a accepted to true prevents the key event from being
+ propagated to the item's parent.
+
+ Generally, if the item acts on the key event then it should be accepted
+ so that ancestor items do not also respond to the same event.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed immediately
+ before the event occurred.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.NoModifier - No modifier key is pressed.
+ \o Qt.ShiftModifier - A Shift key on the keyboard is pressed.
+ \o Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
+ \o Qt.AltModifier - An Alt key on the keyboard is pressed.
+ \o Qt.MetaModifier - A Meta key on the keyboard is pressed.
+ \o Qt.KeypadModifier - A keypad button is pressed.
+ \endlist
+
+ For example, to react to a Shift key + Enter key combination:
+ \qml
+ Item {
+ focus: true
+ Keys.onPressed: {
+ if ((event.key == Qt.Key_Enter) && (event.modifiers & Qt.ShiftModifier))
+ doSomething();
+ }
+ }
+ \endqml
+*/
+
+
+/*!
+ \qmlclass MouseEvent QDeclarativeMouseEvent
+ \since 4.7
+ \ingroup qml-event-elements
+
+ \brief The MouseEvent object provides information about a mouse event.
+
+ The position of the mouse can be found via the \l x and \l y properties.
+ The button that caused the event is available via the \l button property.
+
+ \sa MouseArea
+*/
+
+/*!
+ \internal
+ \class QDeclarativeMouseEvent
+*/
+
+/*!
+ \qmlproperty int MouseEvent::x
+ \qmlproperty int MouseEvent::y
+
+ These properties hold the coordinates of the position supplied by the mouse event.
+*/
+
+
+/*!
+ \qmlproperty bool MouseEvent::accepted
+
+ Setting \a accepted to true prevents the mouse event from being
+ propagated to items below this item.
+
+ Generally, if the item acts on the mouse event then it should be accepted
+ so that items lower in the stacking order do not also respond to the same event.
+*/
+
+/*!
+ \qmlproperty enumeration MouseEvent::button
+
+ This property holds the button that caused the event. It can be one of:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MiddleButton
+ \endlist
+*/
+
+/*!
+ \qmlproperty bool MouseEvent::wasHeld
+
+ This property is true if the mouse button has been held pressed longer the
+ threshold (800ms).
+*/
+
+/*!
+ \qmlproperty int MouseEvent::buttons
+
+ This property holds the mouse buttons pressed when the event was generated.
+ For mouse move events, this is all buttons that are pressed down. For mouse
+ press and double click events this includes the button that caused the event.
+ For mouse release events this excludes the button that caused the event.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MiddleButton
+ \endlist
+*/
+
+/*!
+ \qmlproperty int MouseEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed immediately
+ before the event occurred.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.NoModifier - No modifier key is pressed.
+ \o Qt.ShiftModifier - A Shift key on the keyboard is pressed.
+ \o Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
+ \o Qt.AltModifier - An Alt key on the keyboard is pressed.
+ \o Qt.MetaModifier - A Meta key on the keyboard is pressed.
+ \o Qt.KeypadModifier - A keypad button is pressed.
+ \endlist
+
+ For example, to react to a Shift key + Left mouse button click:
+ \qml
+ MouseArea {
+ onClicked: {
+ if ((mouse.button == Qt.LeftButton) && (mouse.modifiers & Qt.ShiftModifier))
+ doSomething();
+ }
+ }
+ \endqml
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeevents_p_p.h b/src/declarative/graphicsitems/qdeclarativeevents_p_p.h
new file mode 100644
index 0000000000..fc705cc412
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeevents_p_p.h
@@ -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 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 QDECLARATIVEEVENTS_P_H
+#define QDECLARATIVEEVENTS_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 QDeclarativeKeyEvent : 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:
+ QDeclarativeKeyEvent(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); }
+ QDeclarativeKeyEvent(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 QDeclarativeMouseEvent : 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:
+ QDeclarativeMouseEvent(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(QDeclarativeKeyEvent)
+QML_DECLARE_TYPE(QDeclarativeMouseEvent)
+
+#endif // QDECLARATIVEEVENTS_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
new file mode 100644
index 0000000000..3dd194bbc8
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
@@ -0,0 +1,1799 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeflickable_p.h"
+#include "private/qdeclarativeflickable_p_p.h"
+#include <qdeclarativeinfo.h>
+#include <QGraphicsSceneMouseEvent>
+#include <QPointer>
+#include <QTimer>
+#include "qplatformdefs.h"
+
+QT_BEGIN_NAMESPACE
+
+// The maximum number of pixels a flick can overshoot
+#ifndef QML_FLICK_OVERSHOOT
+#define QML_FLICK_OVERSHOOT 200
+#endif
+
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 1
+#endif
+
+// The default maximum velocity of a flick.
+#ifndef QML_FLICK_DEFAULTMAXVELOCITY
+#define QML_FLICK_DEFAULTMAXVELOCITY 2500
+#endif
+
+// The default deceleration of a flick.
+#ifndef QML_FLICK_DEFAULTDECELERATION
+#define QML_FLICK_DEFAULTDECELERATION 1750
+#endif
+
+// How much faster to decelerate when overshooting
+#ifndef QML_FLICK_OVERSHOOTFRICTION
+#define QML_FLICK_OVERSHOOTFRICTION 8
+#endif
+
+// 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;
+
+QDeclarativeFlickableVisibleArea::QDeclarativeFlickableVisibleArea(QDeclarativeFlickable *parent)
+ : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
+ , m_yPosition(0.), m_heightRatio(0.)
+{
+}
+
+qreal QDeclarativeFlickableVisibleArea::widthRatio() const
+{
+ return m_widthRatio;
+}
+
+qreal QDeclarativeFlickableVisibleArea::xPosition() const
+{
+ return m_xPosition;
+}
+
+qreal QDeclarativeFlickableVisibleArea::heightRatio() const
+{
+ return m_heightRatio;
+}
+
+qreal QDeclarativeFlickableVisibleArea::yPosition() const
+{
+ return m_yPosition;
+}
+
+void QDeclarativeFlickableVisibleArea::updateVisible()
+{
+ QDeclarativeFlickablePrivate *p = static_cast<QDeclarativeFlickablePrivate *>(QGraphicsItemPrivate::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);
+}
+
+
+QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate()
+ : contentItem(new QDeclarativeItem)
+ , hData(this, &QDeclarativeFlickablePrivate::setRoundedViewportX)
+ , vData(this, &QDeclarativeFlickablePrivate::setRoundedViewportY)
+ , flickingHorizontally(false), flickingVertically(false)
+ , hMoved(false), vMoved(false)
+ , movingHorizontally(false), movingVertically(false)
+ , stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
+ , deceleration(QML_FLICK_DEFAULTDECELERATION)
+ , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100)
+ , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400)
+ , fixupMode(Normal), vTime(0), visibleArea(0)
+ , flickableDirection(QDeclarativeFlickable::AutoFlickDirection)
+ , boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds)
+{
+}
+
+void QDeclarativeFlickablePrivate::init()
+{
+ Q_Q(QDeclarativeFlickable);
+ 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 = QDeclarativeFlickable::staticMetaObject.indexOfSlot("ticked()");
+ flickableMovementEndingIdx = QDeclarativeFlickable::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&timeline, timelineUpdatedIdx,
+ q, flickableTickedIdx, Qt::DirectConnection);
+ QMetaObject::connect(&timeline, timelineCompletedIdx,
+ q, flickableMovementEndingIdx, Qt::DirectConnection);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildEvents(true);
+ QDeclarativeItemPrivate *viewportPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(contentItem));
+ viewportPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ lastPosTime.invalidate();
+}
+
+/*
+ Returns the amount to overshoot by given a view size.
+ Will be up to the lesser of 1/3 of the view size or QML_FLICK_OVERSHOOT
+*/
+qreal QDeclarativeFlickablePrivate::overShootDistance(qreal size)
+{
+ if (maxVelocity <= 0)
+ return 0.0;
+
+ return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
+}
+
+void QDeclarativeFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
+{
+ if (v > maxVelocity)
+ v = maxVelocity;
+ else if (v < -maxVelocity)
+ v = -maxVelocity;
+ velocityBuffer.append(v);
+ if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER)
+ velocityBuffer.remove(0);
+}
+
+void QDeclarativeFlickablePrivate::AxisData::updateVelocity()
+{
+ if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
+ velocity = 0;
+ int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
+ for (int i = 0; i < count; ++i) {
+ qreal v = velocityBuffer.at(i);
+ velocity += v;
+ }
+ velocity /= count;
+ }
+}
+
+void QDeclarativeFlickablePrivate::itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeom, const QRectF &oldGeom)
+{
+ Q_Q(QDeclarativeFlickable);
+ if (item == contentItem) {
+ if (newGeom.x() != oldGeom.x())
+ emit q->contentXChanged();
+ if (newGeom.y() != oldGeom.y())
+ emit q->contentYChanged();
+ }
+}
+
+void QDeclarativeFlickablePrivate::flickX(qreal velocity)
+{
+ Q_Q(QDeclarativeFlickable);
+ flick(hData, q->minXExtent(), q->maxXExtent(), q->width(), fixupX_callback, velocity);
+}
+
+void QDeclarativeFlickablePrivate::flickY(qreal velocity)
+{
+ Q_Q(QDeclarativeFlickable);
+ flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity);
+}
+
+void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QDeclarativeFlickable);
+ qreal maxDistance = -1;
+ data.fixingUp = false;
+ // -ve velocity means list is moving up
+ if (velocity > 0) {
+ maxDistance = qAbs(minExtent - data.move.value());
+ data.flickTarget = minExtent;
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ 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);
+ if (boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds)
+ timeline.accel(data.move, v, deceleration);
+ else
+ 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 QDeclarativeFlickablePrivate::fixupY_callback(void *data)
+{
+ ((QDeclarativeFlickablePrivate *)data)->fixupY();
+}
+
+void QDeclarativeFlickablePrivate::fixupX_callback(void *data)
+{
+ ((QDeclarativeFlickablePrivate *)data)->fixupX();
+}
+
+void QDeclarativeFlickablePrivate::fixupX()
+{
+ Q_Q(QDeclarativeFlickable);
+ fixup(hData, q->minXExtent(), q->maxXExtent());
+}
+
+void QDeclarativeFlickablePrivate::fixupY()
+{
+ Q_Q(QDeclarativeFlickable);
+ fixup(vData, q->minYExtent(), q->maxYExtent());
+}
+
+void QDeclarativeFlickablePrivate::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;
+ }
+ }
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+ vTime = timeline.time();
+}
+
+void QDeclarativeFlickablePrivate::updateBeginningEnd()
+{
+ Q_Q(QDeclarativeFlickable);
+ 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();
+}
+
+/*!
+ \qmlclass Flickable QDeclarativeFlickable
+ \since 4.7
+ \ingroup qml-basic-interaction-elements
+
+ \brief The Flickable item provides a surface that can be "flicked".
+ \inherits Item
+
+ The Flickable item places its children on a surface that can be dragged
+ and flicked, causing the view onto the child items to scroll. This
+ behavior forms the basis of Items that are designed to show large numbers
+ of child items, such as \l ListView and \l GridView.
+
+ In traditional user interfaces, views can be scrolled using standard
+ controls, such as scroll bars and arrow buttons. In some situations, it
+ is also possible to drag the view directly by pressing and holding a
+ mouse button while moving the cursor. In touch-based user interfaces,
+ this dragging action is often complemented with a flicking action, where
+ scrolling continues after the user has stopped touching the view.
+
+ Flickable does not automatically clip its contents. If it is not used as
+ a full-screen item, you should consider setting the \l{Item::}{clip} property
+ to true.
+
+ \section1 Example Usage
+
+ \div {class="float-right"}
+ \inlineimage flickable.gif
+ \enddiv
+
+ The following example shows a small view onto a large image in which the
+ user can drag or flick the image in order to view different parts of it.
+
+ \snippet doc/src/snippets/declarative/flickable.qml document
+
+ \clearfloat
+
+ Items declared as children of a Flickable are automatically parented to the
+ Flickable's \l contentItem. This should be taken into account when
+ operating on the children of the Flickable; it is usually the children of
+ \c contentItem that are relevant. For example, the bound of Items added
+ to the Flickable will be available by \c contentItem.childrenRect
+
+ \section1 Limitations
+
+ \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
+ \c id. Use \c parent instead.
+*/
+
+/*!
+ \qmlsignal Flickable::onMovementStarted()
+
+ This handler is called when the view begins moving due to user
+ interaction.
+*/
+
+/*!
+ \qmlsignal Flickable::onMovementEnded()
+
+ This handler is called when the view stops moving due to user
+ interaction. If a flick was generated, this handler will
+ be triggered once the flick stops. If a flick was not
+ generated, the handler will be triggered when the
+ user stops dragging - i.e. a mouse or touch release.
+*/
+
+/*!
+ \qmlsignal Flickable::onFlickStarted()
+
+ This handler is called when the view is flicked. A flick
+ starts from the point that the mouse or touch is released,
+ while still in motion.
+*/
+
+/*!
+ \qmlsignal Flickable::onFlickEnded()
+
+ This handler is called when the view stops moving due to a flick.
+*/
+
+/*!
+ \qmlproperty real Flickable::visibleArea.xPosition
+ \qmlproperty real Flickable::visibleArea.widthRatio
+ \qmlproperty real Flickable::visibleArea.yPosition
+ \qmlproperty real Flickable::visibleArea.heightRatio
+
+ These properties describe the position and size of the currently viewed area.
+ The size is defined as the percentage of the full view currently visible,
+ scaled to 0.0 - 1.0. The page position is usually in the range 0.0 (beginning) to
+ 1.0 minus size ratio (end), i.e. \c yPosition is in the range 0.0 to 1.0-\c heightRatio.
+ However, it is possible for the contents to be dragged outside of the normal
+ range, resulting in the page positions also being outside the normal range.
+
+ These properties are typically used to draw a scrollbar. For example:
+
+ \snippet doc/src/snippets/declarative/flickableScrollbar.qml 0
+ \dots 8
+ \snippet doc/src/snippets/declarative/flickableScrollbar.qml 1
+
+ \sa {declarative/ui-components/scrollbar}{scrollbar example}
+*/
+
+QDeclarativeFlickable::QDeclarativeFlickable(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativeFlickablePrivate), parent)
+{
+ Q_D(QDeclarativeFlickable);
+ d->init();
+}
+
+QDeclarativeFlickable::QDeclarativeFlickable(QDeclarativeFlickablePrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativeItem(dd, parent)
+{
+ Q_D(QDeclarativeFlickable);
+ d->init();
+}
+
+QDeclarativeFlickable::~QDeclarativeFlickable()
+{
+}
+
+/*!
+ \qmlproperty real Flickable::contentX
+ \qmlproperty real Flickable::contentY
+
+ These properties hold the surface coordinate currently at the top-left
+ corner of the Flickable. For example, if you flick an image up 100 pixels,
+ \c contentY will be 100.
+*/
+qreal QDeclarativeFlickable::contentX() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return -d->contentItem->x();
+}
+
+void QDeclarativeFlickable::setContentX(qreal pos)
+{
+ Q_D(QDeclarativeFlickable);
+ 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 QDeclarativeFlickable::contentY() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return -d->contentItem->y();
+}
+
+void QDeclarativeFlickable::setContentY(qreal pos)
+{
+ Q_D(QDeclarativeFlickable);
+ d->timeline.reset(d->vData.move);
+ d->vTime = d->timeline.time();
+ movementYEnding();
+ if (-pos != d->vData.move.value()) {
+ d->vData.move.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+/*!
+ \qmlproperty bool Flickable::interactive
+
+ This property describes whether the user can interact with the Flickable.
+ A user cannot drag or flick a Flickable that is not interactive.
+
+ By default, this property is true.
+
+ This property is useful for temporarily disabling flicking. This allows
+ special interaction with Flickable's children; for example, you might want
+ to freeze a flickable map while scrolling through a pop-up dialog that
+ is a child of the Flickable.
+*/
+bool QDeclarativeFlickable::isInteractive() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->interactive;
+}
+
+void QDeclarativeFlickable::setInteractive(bool interactive)
+{
+ Q_D(QDeclarativeFlickable);
+ 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();
+ }
+}
+
+/*!
+ \qmlproperty real Flickable::horizontalVelocity
+ \qmlproperty real Flickable::verticalVelocity
+
+ The instantaneous velocity of movement along the x and y axes, in pixels/sec.
+
+ The reported velocity is smoothed to avoid erratic output.
+*/
+qreal QDeclarativeFlickable::horizontalVelocity() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->hData.smoothVelocity.value();
+}
+
+qreal QDeclarativeFlickable::verticalVelocity() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->vData.smoothVelocity.value();
+}
+
+/*!
+ \qmlproperty bool Flickable::atXBeginning
+ \qmlproperty bool Flickable::atXEnd
+ \qmlproperty bool Flickable::atYBeginning
+ \qmlproperty bool Flickable::atYEnd
+
+ These properties are true if the flickable view is positioned at the beginning,
+ or end respecively.
+*/
+bool QDeclarativeFlickable::isAtXEnd() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->hData.atEnd;
+}
+
+bool QDeclarativeFlickable::isAtXBeginning() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->hData.atBeginning;
+}
+
+bool QDeclarativeFlickable::isAtYEnd() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->vData.atEnd;
+}
+
+bool QDeclarativeFlickable::isAtYBeginning() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->vData.atBeginning;
+}
+
+void QDeclarativeFlickable::ticked()
+{
+ viewportMoved();
+}
+
+/*!
+ \qmlproperty Item Flickable::contentItem
+
+ The internal item that contains the Items to be moved in the Flickable.
+
+ Items declared as children of a Flickable are automatically parented to the Flickable's contentItem.
+
+ Items created dynamically need to be explicitly parented to the \e contentItem:
+ \code
+ Flickable {
+ id: myFlickable
+ function addItem(file) {
+ var component = Qt.createComponent(file)
+ component.createObject(myFlickable.contentItem);
+ }
+ }
+ \endcode
+*/
+QDeclarativeItem *QDeclarativeFlickable::contentItem()
+{
+ Q_D(QDeclarativeFlickable);
+ return d->contentItem;
+}
+
+QDeclarativeFlickableVisibleArea *QDeclarativeFlickable::visibleArea()
+{
+ Q_D(QDeclarativeFlickable);
+ if (!d->visibleArea)
+ d->visibleArea = new QDeclarativeFlickableVisibleArea(this);
+ return d->visibleArea;
+}
+
+/*!
+ \qmlproperty enumeration Flickable::flickableDirection
+
+ This property determines which directions the view can be flicked.
+
+ \list
+ \o Flickable.AutoFlickDirection (default) - allows flicking vertically if the
+ \e contentHeight is not equal to the \e height of the Flickable.
+ Allows flicking horizontally if the \e contentWidth is not equal
+ to the \e width of the Flickable.
+ \o Flickable.HorizontalFlick - allows flicking horizontally.
+ \o Flickable.VerticalFlick - allows flicking vertically.
+ \o Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
+ \endlist
+*/
+QDeclarativeFlickable::FlickableDirection QDeclarativeFlickable::flickableDirection() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->flickableDirection;
+}
+
+void QDeclarativeFlickable::setFlickableDirection(FlickableDirection direction)
+{
+ Q_D(QDeclarativeFlickable);
+ if (direction != d->flickableDirection) {
+ d->flickableDirection = direction;
+ emit flickableDirectionChanged();
+ }
+}
+
+void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativeFlickable);
+ 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.reset();
+ vData.reset();
+ hData.dragMinBound = q->minXExtent();
+ vData.dragMinBound = q->minYExtent();
+ hData.dragMaxBound = q->maxXExtent();
+ vData.dragMaxBound = q->maxYExtent();
+ fixupMode = Normal;
+ lastPos = QPoint();
+ QDeclarativeItemPrivate::start(lastPosTime);
+ pressPos = event->pos();
+ hData.pressPos = hData.move.value();
+ vData.pressPos = vData.move.value();
+ flickingHorizontally = false;
+ flickingVertically = false;
+ QDeclarativeItemPrivate::start(pressTime);
+ QDeclarativeItemPrivate::start(velocityTime);
+}
+
+void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativeFlickable);
+ 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() || QDeclarativeItemPrivate::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 == QDeclarativeFlickable::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() || QDeclarativeItemPrivate::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 == QDeclarativeFlickable::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 (rejectY) {
+ vData.velocityBuffer.clear();
+ vData.velocity = 0;
+ }
+ if (rejectX) {
+ hData.velocityBuffer.clear();
+ hData.velocity = 0;
+ }
+
+ if (hMoved || vMoved) {
+ q->movementStarting();
+ q->viewportMoved();
+ }
+
+ if (!lastPos.isNull()) {
+ qreal elapsed = qreal(QDeclarativeItemPrivate::elapsed(lastPosTime)) / 1000.;
+ if (elapsed <= 0)
+ return;
+ QDeclarativeItemPrivate::restart(lastPosTime);
+ qreal dy = event->pos().y()-lastPos.y();
+ if (q->yflick() && !rejectY)
+ vData.addVelocitySample(dy/elapsed, maxVelocity);
+ qreal dx = event->pos().x()-lastPos.x();
+ if (q->xflick() && !rejectX)
+ hData.addVelocitySample(dx/elapsed, maxVelocity);
+ }
+
+ lastPos = event->pos();
+}
+
+void QDeclarativeFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativeFlickable);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ pressed = false;
+ if (!lastPosTime.isValid())
+ return;
+
+ // if we drag then pause before release we should not cause a flick.
+ if (QDeclarativeItemPrivate::elapsed(lastPosTime) < 100) {
+ vData.updateVelocity();
+ hData.updateVelocity();
+ } else {
+ hData.velocity = 0.0;
+ vData.velocity = 0.0;
+ }
+
+ vTime = timeline.time();
+
+ qreal velocity = vData.velocity;
+ if (vData.atBeginning || vData.atEnd)
+ velocity /= 2;
+ if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
+ flickY(velocity);
+ else
+ fixupY();
+
+ velocity = hData.velocity;
+ if (hData.atBeginning || hData.atEnd)
+ velocity /= 2;
+ if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
+ flickX(velocity);
+ else
+ fixupX();
+
+ if (!timeline.isActive())
+ q->movementEnding();
+}
+
+void QDeclarativeFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ if (d->interactive) {
+ if (!d->pressed)
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QDeclarativeItem::mousePressEvent(event);
+ }
+}
+
+void QDeclarativeFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ event->accept();
+ } else {
+ QDeclarativeItem::mouseMoveEvent(event);
+ }
+}
+
+void QDeclarativeFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ if (d->interactive) {
+ d->clearDelayedPress();
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QDeclarativeItem::mouseReleaseEvent(event);
+ }
+}
+
+void QDeclarativeFlickable::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ if (!d->interactive) {
+ QDeclarativeItem::wheelEvent(event);
+ } else if (yflick() && event->orientation() == Qt::Vertical) {
+ bool valid = false;
+ if (event->delta() > 0 && contentY() > -minYExtent()) {
+ d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4));
+ valid = true;
+ } else if (event->delta() < 0 && contentY() < -maxYExtent()) {
+ d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
+ valid = true;
+ }
+ if (valid) {
+ d->flickingVertically = false;
+ d->flickY(d->vData.velocity);
+ if (d->flickingVertically) {
+ d->vMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ }
+ } else if (xflick() && event->orientation() == Qt::Horizontal) {
+ bool valid = false;
+ if (event->delta() > 0 && contentX() > -minXExtent()) {
+ d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4));
+ valid = true;
+ } else if (event->delta() < 0 && contentX() < -maxXExtent()) {
+ d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4));
+ valid = true;
+ }
+ if (valid) {
+ d->flickingHorizontally = false;
+ d->flickX(d->hData.velocity);
+ if (d->flickingHorizontally) {
+ d->hMoved = true;
+ movementStarting();
+ }
+ event->accept();
+ }
+ } else {
+ QDeclarativeItem::wheelEvent(event);
+ }
+}
+
+bool QDeclarativeFlickablePrivate::isOutermostPressDelay() const
+{
+ Q_Q(const QDeclarativeFlickable);
+ QDeclarativeItem *item = q->parentItem();
+ while (item) {
+ QDeclarativeFlickable *flick = qobject_cast<QDeclarativeFlickable*>(item);
+ if (flick && flick->pressDelay() > 0 && flick->isInteractive())
+ return false;
+ item = item->parentItem();
+ }
+
+ return true;
+}
+
+void QDeclarativeFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativeFlickable);
+ if (!q->scene() || pressDelay <= 0)
+ return;
+ if (!isOutermostPressDelay())
+ return;
+ delayedPressTarget = q->scene()->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 QDeclarativeFlickablePrivate::clearDelayedPress()
+{
+ if (delayedPressEvent) {
+ delayedPressTimer.stop();
+ delete delayedPressEvent;
+ delayedPressEvent = 0;
+ }
+}
+
+void QDeclarativeFlickablePrivate::setRoundedViewportX(qreal x)
+{
+ contentItem->setX(qRound(x));
+}
+
+void QDeclarativeFlickablePrivate::setRoundedViewportY(qreal y)
+{
+ contentItem->setY(qRound(y));
+}
+
+void QDeclarativeFlickable::timerEvent(QTimerEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ if (event->timerId() == d->delayedPressTimer.timerId()) {
+ d->delayedPressTimer.stop();
+ if (d->delayedPressEvent) {
+ QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->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 (scene()->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ //Use the event handler that will take care of finding the proper item to propagate the event
+ QApplication::postEvent(scene(), d->delayedPressEvent);
+ } else {
+ delete d->delayedPressEvent;
+ }
+ d->delayedPressEvent = 0;
+ }
+ }
+}
+
+qreal QDeclarativeFlickable::minYExtent() const
+{
+ return 0.0;
+}
+
+qreal QDeclarativeFlickable::minXExtent() const
+{
+ return 0.0;
+}
+
+/* returns -ve */
+qreal QDeclarativeFlickable::maxXExtent() const
+{
+ return width() - vWidth();
+}
+/* returns -ve */
+qreal QDeclarativeFlickable::maxYExtent() const
+{
+ return height() - vHeight();
+}
+
+void QDeclarativeFlickable::viewportMoved()
+{
+ Q_D(QDeclarativeFlickable);
+
+ qreal prevX = d->lastFlickablePosition.x();
+ qreal prevY = d->lastFlickablePosition.y();
+ d->velocityTimeline.clear();
+ if (d->pressed || d->calcVelocity) {
+ int elapsed = QDeclarativeItemPrivate::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);
+ }
+ }
+
+ if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically
+ && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent())
+ && qAbs(d->vData.smoothVelocity.value()) > 100) {
+ // Increase deceleration if we've passed a bound
+ d->vData.inOvershoot = true;
+ qreal maxDistance = d->overShootDistance(height());
+ d->timeline.reset(d->vData.move);
+ d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
+ d->timeline.callback(QDeclarativeTimeLineCallback(&d->vData.move, d->fixupY_callback, d));
+ }
+ if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally
+ && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent())
+ && qAbs(d->hData.smoothVelocity.value()) > 100) {
+ // Increase deceleration if we've passed a bound
+ d->hData.inOvershoot = true;
+ qreal maxDistance = d->overShootDistance(width());
+ d->timeline.reset(d->hData.move);
+ d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
+ d->timeline.callback(QDeclarativeTimeLineCallback(&d->hData.move, d->fixupX_callback, d));
+ }
+
+ d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value());
+
+ d->vTime = d->timeline.time();
+ d->updateBeginningEnd();
+}
+
+void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeFlickable);
+ QDeclarativeItem::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 = QDeclarativeFlickablePrivate::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 = QDeclarativeFlickablePrivate::Immediate;
+ d->fixupY();
+ }
+ }
+
+ if (changed)
+ d->updateBeginningEnd();
+}
+
+void QDeclarativeFlickable::cancelFlick()
+{
+ Q_D(QDeclarativeFlickable);
+ d->timeline.reset(d->hData.move);
+ d->timeline.reset(d->vData.move);
+ movementEnding();
+}
+
+void QDeclarativeFlickablePrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ QGraphicsObject *i = qobject_cast<QGraphicsObject *>(o);
+ if (i) {
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(i);
+ if (static_cast<QDeclarativeItemPrivate*>(d)->componentComplete) {
+ i->setParentItem(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem);
+ } else {
+ d->setParentItemHelper(static_cast<QDeclarativeFlickablePrivate*>(prop->data)->contentItem, 0, 0);
+ }
+ } else {
+ o->setParent(prop->object);
+ }
+}
+
+int QDeclarativeFlickablePrivate::data_count(QDeclarativeListProperty<QObject> *property)
+{
+ QDeclarativeItem *contentItem= static_cast<QDeclarativeFlickablePrivate*>(property->data)->contentItem;
+ return contentItem->childItems().count() + contentItem->children().count();
+}
+
+QObject *QDeclarativeFlickablePrivate::data_at(QDeclarativeListProperty<QObject> *property, int index)
+{
+ QDeclarativeItem *contentItem = static_cast<QDeclarativeFlickablePrivate*>(property->data)->contentItem;
+
+ int childItemCount = contentItem->childItems().count();
+
+ if (index < 0)
+ return 0;
+
+ if (index < childItemCount) {
+ return contentItem->childItems().at(index)->toGraphicsObject();
+ } else {
+ return contentItem->children().at(index - childItemCount);
+ }
+
+ return 0;
+}
+
+void QDeclarativeFlickablePrivate::data_clear(QDeclarativeListProperty<QObject> *property)
+{
+ QDeclarativeItem *contentItem = static_cast<QDeclarativeFlickablePrivate*>(property->data)->contentItem;
+
+ const QList<QGraphicsItem*> graphicsItems = contentItem->childItems();
+ for (int i = 0; i < graphicsItems.count(); i++)
+ contentItem->scene()->removeItem(graphicsItems[i]);
+
+ const QList<QObject*> objects = contentItem->children();
+ for (int i = 0; i < objects.count(); i++)
+ objects[i]->setParent(0);
+}
+
+QDeclarativeListProperty<QObject> QDeclarativeFlickable::flickableData()
+{
+ Q_D(QDeclarativeFlickable);
+ return QDeclarativeListProperty<QObject>(this, (void *)d, QDeclarativeFlickablePrivate::data_append,
+ QDeclarativeFlickablePrivate::data_count,
+ QDeclarativeFlickablePrivate::data_at,
+ QDeclarativeFlickablePrivate::data_clear);
+}
+
+QDeclarativeListProperty<QGraphicsObject> QDeclarativeFlickable::flickableChildren()
+{
+ Q_D(QDeclarativeFlickable);
+ return QGraphicsItemPrivate::get(d->contentItem)->childrenList();
+}
+
+/*!
+ \qmlproperty enumeration Flickable::boundsBehavior
+ This property holds whether the surface may be dragged
+ beyond the Fickable's boundaries, or overshoot the
+ Flickable's boundaries when flicked.
+
+ This enables the feeling that the edges of the view are soft,
+ rather than a hard physical boundary.
+
+ The \c boundsBehavior can be one of:
+
+ \list
+ \o Flickable.StopAtBounds - the contents can not be dragged beyond the boundary
+ of the flickable, and flicks will not overshoot.
+ \o Flickable.DragOverBounds - the contents can be dragged beyond the boundary
+ of the Flickable, but flicks will not overshoot.
+ \o Flickable.DragAndOvershootBounds (default) - the contents can be dragged
+ beyond the boundary of the Flickable, and can overshoot the
+ boundary when flicked.
+ \endlist
+*/
+QDeclarativeFlickable::BoundsBehavior QDeclarativeFlickable::boundsBehavior() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->boundsBehavior;
+}
+
+void QDeclarativeFlickable::setBoundsBehavior(BoundsBehavior b)
+{
+ Q_D(QDeclarativeFlickable);
+ if (b == d->boundsBehavior)
+ return;
+ d->boundsBehavior = b;
+ emit boundsBehaviorChanged();
+}
+
+/*!
+ \qmlproperty real Flickable::contentWidth
+ \qmlproperty real Flickable::contentHeight
+
+ The dimensions of the content (the surface controlled by Flickable).
+ This should typically be set to the combined size of the items placed in the
+ Flickable.
+
+ The following snippet shows how these properties are used to display
+ an image that is larger than the Flickable item itself:
+
+ \snippet doc/src/snippets/declarative/flickable.qml document
+
+ In some cases, the the content dimensions can be automatically set
+ using the \l {Item::childrenRect.width}{childrenRect.width}
+ and \l {Item::childrenRect.height}{childrenRect.height} properties.
+*/
+qreal QDeclarativeFlickable::contentWidth() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->hData.viewSize;
+}
+
+void QDeclarativeFlickable::setContentWidth(qreal w)
+{
+ Q_D(QDeclarativeFlickable);
+ 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 = QDeclarativeFlickablePrivate::Immediate;
+ d->fixupX();
+ } else if (!d->pressed && d->hData.fixingUp) {
+ d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged;
+ d->fixupX();
+ }
+ emit contentWidthChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QDeclarativeFlickable::contentHeight() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->vData.viewSize;
+}
+
+void QDeclarativeFlickable::setContentHeight(qreal h)
+{
+ Q_D(QDeclarativeFlickable);
+ 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 = QDeclarativeFlickablePrivate::Immediate;
+ d->fixupY();
+ } else if (!d->pressed && d->vData.fixingUp) {
+ d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged;
+ d->fixupY();
+ }
+ emit contentHeightChanged();
+ d->updateBeginningEnd();
+}
+
+/*!
+ \qmlmethod Flickable::resizeContent(real width, real height, QPointF center)
+ \preliminary
+ \since Quick 1.1
+
+ Resizes the content to \a width x \a height about \a center.
+
+ This does not scale the contents of the Flickable - it only resizes the \l contentWidth
+ and \l contentHeight.
+
+ Resizing the content may result in the content being positioned outside
+ the bounds of the Flickable. Calling \l returnToBounds() will
+ move the content back within legal bounds.
+*/
+void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center)
+{
+ Q_D(QDeclarativeFlickable);
+ if (w != d->hData.viewSize) {
+ qreal oldSize = d->hData.viewSize;
+ d->hData.viewSize = w;
+ d->contentItem->setWidth(w);
+ emit contentWidthChanged();
+ 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;
+ d->vData.viewSize = h;
+ d->contentItem->setHeight(h);
+ emit contentHeightChanged();
+ if (center.y() != 0) {
+ qreal pos = center.y() * h / oldSize;
+ setContentY(contentY() + pos - center.y());
+ }
+ }
+ d->updateBeginningEnd();
+}
+
+/*!
+ \qmlmethod Flickable::returnToBounds()
+ \preliminary
+ \since Quick 1.1
+
+ Ensures the content is within legal bounds.
+
+ This may be called to ensure that the content is within legal bounds
+ after manually positioning the content.
+*/
+void QDeclarativeFlickable::returnToBounds()
+{
+ Q_D(QDeclarativeFlickable);
+ d->fixupX();
+ d->fixupY();
+}
+
+qreal QDeclarativeFlickable::vWidth() const
+{
+ Q_D(const QDeclarativeFlickable);
+ if (d->hData.viewSize < 0)
+ return width();
+ else
+ return d->hData.viewSize;
+}
+
+qreal QDeclarativeFlickable::vHeight() const
+{
+ Q_D(const QDeclarativeFlickable);
+ if (d->vData.viewSize < 0)
+ return height();
+ else
+ return d->vData.viewSize;
+}
+
+bool QDeclarativeFlickable::xflick() const
+{
+ Q_D(const QDeclarativeFlickable);
+ if (d->flickableDirection == QDeclarativeFlickable::AutoFlickDirection)
+ return vWidth() != width();
+ return d->flickableDirection & QDeclarativeFlickable::HorizontalFlick;
+}
+
+bool QDeclarativeFlickable::yflick() const
+{
+ Q_D(const QDeclarativeFlickable);
+ if (d->flickableDirection == QDeclarativeFlickable::AutoFlickDirection)
+ return vHeight() != height();
+ return d->flickableDirection & QDeclarativeFlickable::VerticalFlick;
+}
+
+bool QDeclarativeFlickable::sceneEvent(QEvent *event)
+{
+ bool rv = QDeclarativeItem::sceneEvent(event);
+ if (event->type() == QEvent::UngrabMouse) {
+ Q_D(QDeclarativeFlickable);
+ 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);
+ }
+ }
+ return rv;
+}
+
+bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeFlickable);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
+
+ QGraphicsScene *s = scene();
+ QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
+ QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0;
+ bool disabledItem = grabberItem && !grabberItem->isEnabled();
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+ 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 (s->mouseGrabberItem() == d->delayedPressTarget)
+ d->delayedPressTarget->ungrabMouse();
+ //Use the event handler that will take care of finding the proper item to propagate the event
+ QApplication::sendEvent(scene(), d->delayedPressEvent);
+ d->clearDelayedPress();
+ // We send the release
+ scene()->sendEvent(s->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<QDeclarativeItem*>(s->mouseGrabberItem());
+ if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
+ d->clearDelayedPress();
+ grabMouse();
+ }
+
+ return stealThisEvent || d->delayedPressEvent || disabledItem;
+ } else if (d->lastPosTime.isValid()) {
+ d->lastPosTime.invalidate();
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->clearDelayedPress();
+ d->stealMouse = false;
+ d->pressed = false;
+ }
+
+ return false;
+}
+
+bool QDeclarativeFlickable::sceneEventFilter(QGraphicsItem *i, QEvent *e)
+{
+ Q_D(QDeclarativeFlickable);
+ if (!isVisible() || !d->interactive)
+ return QDeclarativeItem::sceneEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QDeclarativeItem::sceneEventFilter(i, e);
+}
+
+/*!
+ \qmlproperty real Flickable::maximumFlickVelocity
+ This property holds the maximum velocity that the user can flick the view in pixels/second.
+
+ The default value is platform dependent.
+*/
+qreal QDeclarativeFlickable::maximumFlickVelocity() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->maxVelocity;
+}
+
+void QDeclarativeFlickable::setMaximumFlickVelocity(qreal v)
+{
+ Q_D(QDeclarativeFlickable);
+ if (v == d->maxVelocity)
+ return;
+ d->maxVelocity = v;
+ emit maximumFlickVelocityChanged();
+}
+
+/*!
+ \qmlproperty real Flickable::flickDeceleration
+ This property holds the rate at which a flick will decelerate.
+
+ The default value is platform dependent.
+*/
+qreal QDeclarativeFlickable::flickDeceleration() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->deceleration;
+}
+
+void QDeclarativeFlickable::setFlickDeceleration(qreal deceleration)
+{
+ Q_D(QDeclarativeFlickable);
+ if (deceleration == d->deceleration)
+ return;
+ d->deceleration = deceleration;
+ emit flickDecelerationChanged();
+}
+
+bool QDeclarativeFlickable::isFlicking() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->flickingHorizontally || d->flickingVertically;
+}
+
+/*!
+ \qmlproperty bool Flickable::flicking
+ \qmlproperty bool Flickable::flickingHorizontally
+ \qmlproperty bool Flickable::flickingVertically
+
+ These properties describe whether the view is currently moving horizontally,
+ vertically or in either direction, due to the user flicking the view.
+*/
+bool QDeclarativeFlickable::isFlickingHorizontally() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->flickingHorizontally;
+}
+
+bool QDeclarativeFlickable::isFlickingVertically() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->flickingVertically;
+}
+
+/*!
+ \qmlproperty int Flickable::pressDelay
+
+ This property holds the time to delay (ms) delivering a press to
+ children of the Flickable. This can be useful where reacting
+ to a press before a flicking action has undesirable effects.
+
+ If the flickable is dragged/flicked before the delay times out
+ the press event will not be delivered. If the button is released
+ within the timeout, both the press and release will be delivered.
+
+ Note that for nested Flickables with pressDelay set, the pressDelay of
+ inner Flickables is overridden by the outermost Flickable.
+*/
+int QDeclarativeFlickable::pressDelay() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->pressDelay;
+}
+
+void QDeclarativeFlickable::setPressDelay(int delay)
+{
+ Q_D(QDeclarativeFlickable);
+ if (d->pressDelay == delay)
+ return;
+ d->pressDelay = delay;
+ emit pressDelayChanged();
+}
+
+
+bool QDeclarativeFlickable::isMoving() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->movingHorizontally || d->movingVertically;
+}
+
+/*!
+ \qmlproperty bool Flickable::moving
+ \qmlproperty bool Flickable::movingHorizontally
+ \qmlproperty bool Flickable::movingVertically
+
+ These properties describe whether the view is currently moving horizontally,
+ vertically or in either direction, due to the user either dragging or
+ flicking the view.
+*/
+bool QDeclarativeFlickable::isMovingHorizontally() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->movingHorizontally;
+}
+
+bool QDeclarativeFlickable::isMovingVertically() const
+{
+ Q_D(const QDeclarativeFlickable);
+ return d->movingVertically;
+}
+
+void QDeclarativeFlickable::movementStarting()
+{
+ Q_D(QDeclarativeFlickable);
+ 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 QDeclarativeFlickable::movementEnding()
+{
+ Q_D(QDeclarativeFlickable);
+ movementXEnding();
+ movementYEnding();
+ d->hData.smoothVelocity.setValue(0);
+ d->vData.smoothVelocity.setValue(0);
+}
+
+void QDeclarativeFlickable::movementXEnding()
+{
+ Q_D(QDeclarativeFlickable);
+ 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 QDeclarativeFlickable::movementYEnding()
+{
+ Q_D(QDeclarativeFlickable);
+ 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 QDeclarativeFlickablePrivate::updateVelocity()
+{
+ Q_Q(QDeclarativeFlickable);
+ emit q->horizontalVelocityChanged();
+ emit q->verticalVelocityChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p.h
new file mode 100644
index 0000000000..a14cc1c11b
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeflickable_p.h
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEFLICKABLE_H
+#define QDECLARATIVEFLICKABLE_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeFlickablePrivate;
+class QDeclarativeFlickableVisibleArea;
+class Q_AUTOTEST_EXPORT QDeclarativeFlickable : public QDeclarativeItem
+{
+ 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(QDeclarativeItem *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(QDeclarativeFlickableVisibleArea *visibleArea READ visibleArea CONSTANT)
+
+ Q_PROPERTY(QDeclarativeListProperty<QObject> flickableData READ flickableData)
+ Q_PROPERTY(QDeclarativeListProperty<QGraphicsObject> flickableChildren READ flickableChildren)
+ Q_CLASSINFO("DefaultProperty", "flickableData")
+
+ Q_ENUMS(FlickableDirection)
+ Q_ENUMS(BoundsBehavior)
+
+public:
+ QDeclarativeFlickable(QDeclarativeItem *parent=0);
+ ~QDeclarativeFlickable();
+
+ QDeclarativeListProperty<QObject> flickableData();
+ QDeclarativeListProperty<QGraphicsObject> 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;
+
+ QDeclarativeItem *contentItem();
+
+ enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 };
+ FlickableDirection flickableDirection() const;
+ void setFlickableDirection(FlickableDirection);
+
+ Q_INVOKABLE Q_REVISION(1) void resizeContent(qreal w, qreal h, QPointF center);
+ Q_INVOKABLE Q_REVISION(1) 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 sceneEventFilter(QGraphicsItem *, QEvent *);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void wheelEvent(QGraphicsSceneWheelEvent *event);
+ void timerEvent(QTimerEvent *event);
+
+ QDeclarativeFlickableVisibleArea *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);
+ bool sceneEvent(QEvent *event);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ bool xflick() const;
+ bool yflick() const;
+ void cancelFlick();
+
+protected:
+ QDeclarativeFlickable(QDeclarativeFlickablePrivate &dd, QDeclarativeItem *parent);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeFlickable)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeFlickable)
+ friend class QDeclarativeFlickableVisibleArea;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFlickable)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h
new file mode 100644
index 0000000000..1117abb8f9
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEFLICKABLE_P_H
+#define QDECLARATIVEFLICKABLE_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/qdeclarativeflickable_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativeitemchangelistener_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativetimeline_p_p.h>
+#include <qdeclarativeanimation_p_p.h>
+
+#include <qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+// Really slow flicks can be annoying.
+const qreal MinimumFlickVelocity = 75.0;
+
+class QDeclarativeFlickableVisibleArea;
+class QDeclarativeFlickablePrivate : public QDeclarativeItemPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativeFlickable)
+
+public:
+ QDeclarativeFlickablePrivate();
+ void init();
+
+ struct Velocity : public QDeclarativeTimeLineValue
+ {
+ Velocity(QDeclarativeFlickablePrivate *p)
+ : parent(p) {}
+ virtual void setValue(qreal v) {
+ if (v != value()) {
+ QDeclarativeTimeLineValue::setValue(v);
+ parent->updateVelocity();
+ }
+ }
+ QDeclarativeFlickablePrivate *parent;
+ };
+
+ struct AxisData {
+ AxisData(QDeclarativeFlickablePrivate *fp, void (QDeclarativeFlickablePrivate::*func)(qreal))
+ : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
+ , fixingUp(false), inOvershoot(false)
+ {}
+
+ void reset() {
+ velocityBuffer.clear();
+ dragStartOffset = 0;
+ fixingUp = false;
+ inOvershoot = false;
+ }
+
+ void addVelocitySample(qreal v, qreal maxVelocity);
+ void updateVelocity();
+
+ QDeclarativeTimeLineValueProxy<QDeclarativeFlickablePrivate> move;
+ qreal viewSize;
+ qreal pressPos;
+ qreal dragStartOffset;
+ qreal dragMinBound;
+ qreal dragMaxBound;
+ qreal velocity;
+ qreal flickTarget;
+ QDeclarativeFlickablePrivate::Velocity smoothVelocity;
+ QPODVector<qreal,10> velocityBuffer;
+ bool atEnd : 1;
+ bool atBeginning : 1;
+ bool fixingUp : 1;
+ bool inOvershoot : 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 size);
+
+ void itemGeometryChanged(QDeclarativeItem *, const QRectF &, const QRectF &);
+
+public:
+ QDeclarativeItem *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;
+ QGraphicsItem *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;
+ QDeclarativeFlickableVisibleArea *visibleArea;
+ QDeclarativeFlickable::FlickableDirection flickableDirection;
+ QDeclarativeFlickable::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 QDeclarativeFlickableVisibleArea : 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:
+ QDeclarativeFlickableVisibleArea(QDeclarativeFlickable *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:
+ QDeclarativeFlickable *flickable;
+ qreal m_xPosition;
+ qreal m_widthRatio;
+ qreal m_yPosition;
+ qreal m_heightRatio;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFlickableVisibleArea)
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeflipable.cpp b/src/declarative/graphicsitems/qdeclarativeflipable.cpp
new file mode 100644
index 0000000000..d23374b512
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeflipable.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeflipable_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+#include <qdeclarativeinfo.h>
+
+#include <QtGui/qgraphicstransform.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeFlipablePrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeFlipable)
+public:
+ QDeclarativeFlipablePrivate() : current(QDeclarativeFlipable::Front), front(0), back(0) {}
+
+ void updateSceneTransformFromParent();
+ void setBackTransform();
+
+ QDeclarativeFlipable::Side current;
+ QDeclarativeGuard<QGraphicsObject> front;
+ QDeclarativeGuard<QGraphicsObject> back;
+
+ bool wantBackXFlipped;
+ bool wantBackYFlipped;
+};
+
+/*!
+ \qmlclass Flipable QDeclarativeFlipable
+ \since 4.7
+ \ingroup qml-basic-interaction-elements
+ \brief The Flipable item provides a surface that can be flipped.
+ \inherits Item
+
+ Flipable is an item that can be visibly "flipped" between its front and
+ back sides, like a card. It is used together with \l Rotation, \l State
+ and \l Transition elements to produce a flipping effect.
+
+ The \l front and \l back properties are used to hold the items that are
+ shown respectively on the front and back sides of the flipable item.
+
+ \section1 Example Usage
+
+ The following example shows a Flipable item that flips whenever it is
+ clicked, rotating about the y-axis.
+
+ This flipable item has a \c flipped boolean property that is toggled
+ whenever the MouseArea within the flipable is clicked. When
+ \c flipped is true, the item changes to the "back" state; in this
+ state, the \c angle of the \l Rotation item is changed to 180
+ degrees to produce the flipping effect. When \c flipped is false, the
+ item reverts to the default state, in which the \c angle value is 0.
+
+ \snippet doc/src/snippets/declarative/flipable/flipable.qml 0
+
+ \image flipable.gif
+
+ The \l Transition creates the animation that changes the angle over
+ four seconds. When the item changes between its "back" and
+ default states, the NumberAnimation animates the angle between
+ its old and new values.
+
+ See \l {QML States} for details on state changes and the default
+ state, and \l {QML Animation and Transitions} for more information on how
+ animations work within transitions.
+
+ \sa {declarative/ui-components/flipable}{Flipable example}
+*/
+
+QDeclarativeFlipable::QDeclarativeFlipable(QDeclarativeItem *parent)
+: QDeclarativeItem(*(new QDeclarativeFlipablePrivate), parent)
+{
+}
+
+QDeclarativeFlipable::~QDeclarativeFlipable()
+{
+}
+
+/*!
+ \qmlproperty Item Flipable::front
+ \qmlproperty Item Flipable::back
+
+ The front and back sides of the flipable.
+*/
+
+QGraphicsObject *QDeclarativeFlipable::front()
+{
+ Q_D(const QDeclarativeFlipable);
+ return d->front;
+}
+
+void QDeclarativeFlipable::setFront(QGraphicsObject *front)
+{
+ Q_D(QDeclarativeFlipable);
+ 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();
+}
+
+QGraphicsObject *QDeclarativeFlipable::back()
+{
+ Q_D(const QDeclarativeFlipable);
+ return d->back;
+}
+
+void QDeclarativeFlipable::setBack(QGraphicsObject *back)
+{
+ Q_D(QDeclarativeFlipable);
+ if (d->back) {
+ qmlInfo(this) << tr("back is a write-once property");
+ return;
+ }
+ d->back = back;
+ d->back->setParentItem(this);
+ 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 QDeclarativeFlipable::retransformBack()
+{
+ Q_D(QDeclarativeFlipable);
+ if (d->current == QDeclarativeFlipable::Back && d->back)
+ d->setBackTransform();
+}
+
+/*!
+ \qmlproperty enumeration Flipable::side
+
+ The side of the Flipable currently visible. Possible values are \c
+ Flipable.Front and \c Flipable.Back.
+*/
+QDeclarativeFlipable::Side QDeclarativeFlipable::side() const
+{
+ Q_D(const QDeclarativeFlipable);
+ if (d->dirtySceneTransform)
+ const_cast<QDeclarativeFlipablePrivate *>(d)->ensureSceneTransform();
+
+ return d->current;
+}
+
+// determination on the currently visible side of the flipable
+// has to be done on the complete scene transform to give
+// correct results.
+void QDeclarativeFlipablePrivate::updateSceneTransformFromParent()
+{
+ Q_Q(QDeclarativeFlipable);
+
+ QDeclarativeItemPrivate::updateSceneTransformFromParent();
+ 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);
+ p1 = q->mapToParent(p1);
+ p2 = q->mapToParent(p2);
+ p3 = q->mapToParent(p3);
+
+ qreal cross = (scenep1.x() - scenep2.x()) * (scenep3.y() - scenep2.y()) -
+ (scenep1.y() - scenep2.y()) * (scenep3.x() - scenep2.x());
+
+ wantBackYFlipped = p1.x() >= p2.x();
+ wantBackXFlipped = p2.y() >= p3.y();
+
+ QDeclarativeFlipable::Side newSide;
+ if (cross > 0) {
+ newSide = QDeclarativeFlipable::Back;
+ } else {
+ newSide = QDeclarativeFlipable::Front;
+ }
+
+ if (newSide != current) {
+ current = newSide;
+ if (current == QDeclarativeFlipable::Back && back)
+ setBackTransform();
+ if (front)
+ front->setOpacity((current==QDeclarativeFlipable::Front)?1.:0.);
+ if (back)
+ back->setOpacity((current==QDeclarativeFlipable::Back)?1.:0.);
+ emit q->sideChanged();
+ }
+}
+
+/* Depends on the width/height of the back item, and so needs reevaulating
+ if those change.
+*/
+void QDeclarativeFlipablePrivate::setBackTransform()
+{
+ QTransform mat;
+ QGraphicsItemPrivate *dBack = QGraphicsItemPrivate::get(back);
+ mat.translate(dBack->width()/2,dBack->height()/2);
+ if (dBack->width() && wantBackYFlipped)
+ mat.rotate(180, Qt::YAxis);
+ if (dBack->height() && wantBackXFlipped)
+ mat.rotate(180, Qt::XAxis);
+ mat.translate(-dBack->width()/2,-dBack->height()/2);
+ back->setTransform(mat);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeflipable_p.h b/src/declarative/graphicsitems/qdeclarativeflipable_p.h
new file mode 100644
index 0000000000..4ea2ec0612
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeflipable_p.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 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 QDECLARATIVEFLIPABLE_H
+#define QDECLARATIVEFLIPABLE_H
+
+#include "qdeclarativeitem.h"
+
+#include <QtCore/QObject>
+#include <QtGui/QTransform>
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeFlipablePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeFlipable : public QDeclarativeItem
+{
+ Q_OBJECT
+
+ Q_ENUMS(Side)
+ Q_PROPERTY(QGraphicsObject *front READ front WRITE setFront NOTIFY frontChanged)
+ Q_PROPERTY(QGraphicsObject *back READ back WRITE setBack NOTIFY backChanged)
+ Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+ //### flipAxis
+ //### flipRotation
+public:
+ QDeclarativeFlipable(QDeclarativeItem *parent=0);
+ ~QDeclarativeFlipable();
+
+ QGraphicsObject *front();
+ void setFront(QGraphicsObject *);
+
+ QGraphicsObject *back();
+ void setBack(QGraphicsObject *);
+
+ enum Side { Front, Back };
+ Side side() const;
+
+Q_SIGNALS:
+ void frontChanged();
+ void backChanged();
+ void sideChanged();
+
+private Q_SLOTS:
+ void retransformBack();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeFlipable)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeFlipable)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFlipable)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFLIPABLE_H
diff --git a/src/declarative/graphicsitems/qdeclarativefocuspanel.cpp b/src/declarative/graphicsitems/qdeclarativefocuspanel.cpp
new file mode 100644
index 0000000000..a9ea6b9c8c
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativefocuspanel.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 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/qdeclarativefocuspanel_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+
+#include <QtGui/qgraphicsscene.h>
+#include <QEvent>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass FocusPanel QDeclarativeFocusPanel
+ \since 4.7
+ \ingroup qml-basic-interaction-elements
+
+ \brief The FocusPanel item explicitly creates a focus panel.
+ \inherits Item
+
+ Focus panels assist in keyboard focus handling when building QML
+ applications. All the details are covered in the
+ \l {qmlfocus}{keyboard focus documentation}.
+*/
+
+QDeclarativeFocusPanel::QDeclarativeFocusPanel(QDeclarativeItem *parent) :
+ QDeclarativeItem(parent)
+{
+ Q_D(QDeclarativeItem);
+ d->flags |= QGraphicsItem::ItemIsPanel;
+}
+
+QDeclarativeFocusPanel::~QDeclarativeFocusPanel()
+{
+}
+
+/*!
+ \qmlproperty bool FocusPanel::active
+
+ Sets whether the item is the active focus panel.
+*/
+
+bool QDeclarativeFocusPanel::sceneEvent(QEvent *event)
+{
+ if (event->type() == QEvent::WindowActivate ||
+ event->type() == QEvent::WindowDeactivate)
+ emit activeChanged();
+ return QDeclarativeItem::sceneEvent(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativefocuspanel_p.h b/src/declarative/graphicsitems/qdeclarativefocuspanel_p.h
new file mode 100644
index 0000000000..f6264c88a0
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativefocuspanel_p.h
@@ -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 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 QDECLARATIVEFOCUSPANEL_H
+#define QDECLARATIVEFOCUSPANEL_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QDeclarativeFocusPanel : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
+public:
+ QDeclarativeFocusPanel(QDeclarativeItem *parent=0);
+ virtual ~QDeclarativeFocusPanel();
+
+Q_SIGNALS:
+ void activeChanged();
+
+protected:
+ bool sceneEvent(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeFocusPanel)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFocusPanel)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFOCUSPANEL_H
diff --git a/src/declarative/graphicsitems/qdeclarativefocusscope.cpp b/src/declarative/graphicsitems/qdeclarativefocusscope.cpp
new file mode 100644
index 0000000000..7dbec452f5
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativefocusscope.cpp
@@ -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 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/qdeclarativefocusscope_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass FocusScope QDeclarativeFocusScope
+ \since 4.7
+ \ingroup qml-basic-interaction-elements
+
+ \brief The FocusScope object explicitly creates a focus scope.
+ \inherits Item
+
+ Focus scopes assist in keyboard focus handling when building reusable QML
+ components. All the details are covered in the
+ \l {qmlfocus}{keyboard focus documentation}.
+
+ \sa {declarative/keyinteraction/focus}{Keyboard focus example}
+*/
+
+QDeclarativeFocusScope::QDeclarativeFocusScope(QDeclarativeItem *parent) :
+ QDeclarativeItem(parent)
+{
+ Q_D(QDeclarativeItem);
+ d->flags |= QGraphicsItem::ItemIsFocusScope;
+}
+
+QDeclarativeFocusScope::~QDeclarativeFocusScope()
+{
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativefocusscope_p.h b/src/declarative/graphicsitems/qdeclarativefocusscope_p.h
new file mode 100644
index 0000000000..5f5f4f779d
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativefocusscope_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEFOCUSSCOPE_H
+#define QDECLARATIVEFOCUSSCOPE_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+//### set component root as focusscope
+class Q_AUTOTEST_EXPORT QDeclarativeFocusScope : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
+public:
+ QDeclarativeFocusScope(QDeclarativeItem *parent=0);
+ virtual ~QDeclarativeFocusScope();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFocusScope)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFOCUSSCOPE_H
diff --git a/src/declarative/graphicsitems/qdeclarativegraphicswidget.cpp b/src/declarative/graphicsitems/qdeclarativegraphicswidget.cpp
new file mode 100644
index 0000000000..e21585d8bb
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativegraphicswidget.cpp
@@ -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 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 "qdeclarativegraphicswidget_p.h"
+#include "private/qdeclarativeanchors_p.h"
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativeanchors_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGraphicsWidgetPrivate : public QObjectPrivate {
+ Q_DECLARE_PUBLIC(QDeclarativeGraphicsWidget)
+public :
+ QDeclarativeGraphicsWidgetPrivate() :
+ _anchors(0), _anchorLines(0)
+ {}
+ QDeclarativeItemPrivate::AnchorLines *anchorLines() const;
+ QDeclarativeAnchors *_anchors;
+ mutable QDeclarativeItemPrivate::AnchorLines *_anchorLines;
+};
+
+QDeclarativeGraphicsWidget::QDeclarativeGraphicsWidget(QObject *parent) :
+ QObject(*new QDeclarativeGraphicsWidgetPrivate, parent)
+{
+}
+QDeclarativeGraphicsWidget::~QDeclarativeGraphicsWidget()
+{
+ Q_D(QDeclarativeGraphicsWidget);
+ delete d->_anchorLines; d->_anchorLines = 0;
+ delete d->_anchors; d->_anchors = 0;
+}
+
+QDeclarativeAnchors *QDeclarativeGraphicsWidget::anchors()
+{
+ Q_D(QDeclarativeGraphicsWidget);
+ if (!d->_anchors)
+ d->_anchors = new QDeclarativeAnchors(static_cast<QGraphicsObject *>(parent()));
+ return d->_anchors;
+}
+
+QDeclarativeItemPrivate::AnchorLines *QDeclarativeGraphicsWidgetPrivate::anchorLines() const
+{
+ Q_Q(const QDeclarativeGraphicsWidget);
+ if (!_anchorLines)
+ _anchorLines = new QDeclarativeItemPrivate::AnchorLines(static_cast<QGraphicsObject *>(q->parent()));
+ return _anchorLines;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::left() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->left;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::right() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->right;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::horizontalCenter() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->hCenter;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::top() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->top;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::bottom() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->bottom;
+}
+
+QDeclarativeAnchorLine QDeclarativeGraphicsWidget::verticalCenter() const
+{
+ Q_D(const QDeclarativeGraphicsWidget);
+ return d->anchorLines()->vCenter;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qdeclarativegraphicswidget_p.cpp>
diff --git a/src/declarative/graphicsitems/qdeclarativegraphicswidget_p.h b/src/declarative/graphicsitems/qdeclarativegraphicswidget_p.h
new file mode 100644
index 0000000000..021097cf81
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativegraphicswidget_p.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 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 QDECLARATIVEGRAPHICSWIDGET_P_H
+#define QDECLARATIVEGRAPHICSWIDGET_P_H
+
+#include <QObject>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeAnchorLine;
+class QDeclarativeAnchors;
+class QGraphicsObject;
+class QDeclarativeGraphicsWidgetPrivate;
+
+// ### TODO can the extension object be the anchor directly? We save one allocation -> awesome.
+class QDeclarativeGraphicsWidget : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeAnchors * anchors READ anchors DESIGNABLE false CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine left READ left CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine right READ right CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine horizontalCenter READ horizontalCenter CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine top READ top CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine bottom READ bottom CONSTANT FINAL)
+ Q_PROPERTY(QDeclarativeAnchorLine verticalCenter READ verticalCenter CONSTANT FINAL)
+ // ### TODO : QGraphicsWidget don't have a baseline concept yet.
+ //Q_PROPERTY(QDeclarativeAnchorLine baseline READ baseline CONSTANT FINAL)
+public:
+ QDeclarativeGraphicsWidget(QObject *parent = 0);
+ ~QDeclarativeGraphicsWidget();
+ QDeclarativeAnchors *anchors();
+ QDeclarativeAnchorLine left() const;
+ QDeclarativeAnchorLine right() const;
+ QDeclarativeAnchorLine horizontalCenter() const;
+ QDeclarativeAnchorLine top() const;
+ QDeclarativeAnchorLine bottom() const;
+ QDeclarativeAnchorLine verticalCenter() const;
+ Q_DISABLE_COPY(QDeclarativeGraphicsWidget)
+ Q_DECLARE_PRIVATE(QDeclarativeGraphicsWidget)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEGRAPHICSWIDGET_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
new file mode 100644
index 0000000000..f30831d7d9
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -0,0 +1,3125 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativegridview_p.h"
+
+#include "private/qdeclarativevisualitemmodel_p.h"
+#include "private/qdeclarativeflickable_p_p.h"
+
+#include "private/qdeclarativesmoothedanimation_p_p.h"
+#include <qdeclarativeguard_p.h>
+
+#include <qlistmodelinterface_p.h>
+#include <QKeyEvent>
+
+#include <qmath.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+
+//----------------------------------------------------------------------------
+
+class FxGridItem
+{
+public:
+ FxGridItem(QDeclarativeItem *i, QDeclarativeGridView *v) : item(i), view(v) {
+ attached = static_cast<QDeclarativeGridViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeGridView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxGridItem() {}
+
+ qreal rowPos() const {
+ qreal rowPos = 0;
+ if (view->flow() == QDeclarativeGridView::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() == QDeclarativeGridView::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() == QDeclarativeGridView::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() == QDeclarativeGridView::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() == QDeclarativeGridView::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());
+ }
+
+ QDeclarativeItem *item;
+ QDeclarativeGridView *view;
+ QDeclarativeGridViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeGridView)
+
+public:
+ QDeclarativeGridViewPrivate()
+ : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QDeclarativeGridView::LeftToRight)
+ , visibleIndex(0) , currentIndex(-1)
+ , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , highlightRange(QDeclarativeGridView::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(QDeclarativeGridView::NoSnap)
+ , ownModel(false), wrap(false), autoHighlight(true)
+ , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
+ , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false) {}
+
+ void init();
+ void clear();
+ FxGridItem *createItem(int modelIndex);
+ void releaseItem(FxGridItem *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();
+
+ FxGridItem *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxGridItem *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ bool isRightToLeftTopToBottom() const {
+ Q_Q(const QDeclarativeGridView);
+ return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ void regenerate() {
+ Q_Q(QDeclarativeGridView);
+ if (q->isComponentComplete()) {
+ clear();
+ updateGrid();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QDeclarativeGridView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ qreal position() const {
+ Q_Q(const QDeclarativeGridView);
+ return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QDeclarativeGridView);
+ if (flow == QDeclarativeGridView::LeftToRight) {
+ q->QDeclarativeFlickable::setContentY(pos);
+ q->QDeclarativeFlickable::setContentX(0);
+ } else {
+ if (q->effectiveLayoutDirection() == Qt::LeftToRight)
+ q->QDeclarativeFlickable::setContentX(pos);
+ else
+ q->QDeclarativeFlickable::setContentX(-pos-size());
+ q->QDeclarativeFlickable::setContentY(0);
+ }
+ }
+ int size() const {
+ Q_Q(const QDeclarativeGridView);
+ return flow == QDeclarativeGridView::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 == QDeclarativeGridView::LeftToRight ? cellHeight : cellWidth;
+ }
+ int colSize() const {
+ return flow == QDeclarativeGridView::LeftToRight ? cellWidth : cellHeight;
+ }
+
+ qreal colPosAt(int modelIndex) const {
+ if (FxGridItem *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 (FxGridItem *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;
+ }
+
+ FxGridItem *firstVisibleItem() const {
+ const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItem *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) {
+ FxGridItem *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) {
+ FxGridItem *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 QDeclarativeGridView);
+ 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 == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ }
+ if (snapPos > maxExtent)
+ snapPos = maxExtent;
+ if (snapPos < minExtent)
+ snapPos = minExtent;
+ }
+ return snapPos;
+ }
+
+ FxGridItem *snapItemAt(qreal pos) {
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItem *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) {
+ FxGridItem *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 == QDeclarativeGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+
+
+ virtual void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(const QDeclarativeGridView);
+ QDeclarativeFlickablePrivate::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) {
+ FxGridItem *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<QDeclarativeVisualModel> model;
+ QVariant modelVariant;
+ QList<FxGridItem*> visibleItems;
+ QHash<QDeclarativeItem*,int> unrequestedItems;
+ FxGridItem *currentItem;
+ Qt::LayoutDirection layoutDirection;
+ QDeclarativeGridView::Flow flow;
+ int visibleIndex;
+ int currentIndex;
+ int cellWidth;
+ int cellHeight;
+ int columns;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ bool highlightRangeStartValid;
+ bool highlightRangeEndValid;
+ QDeclarativeGridView::HighlightRangeMode highlightRange;
+ QDeclarativeComponent *highlightComponent;
+ FxGridItem *highlight;
+ FxGridItem *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightXAnimator;
+ QSmoothedAnimation *highlightYAnimator;
+ int highlightMoveDuration;
+ QDeclarativeComponent *footerComponent;
+ FxGridItem *footer;
+ QDeclarativeComponent *headerComponent;
+ FxGridItem *header;
+ enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
+ int bufferMode;
+ QDeclarativeGridView::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;
+};
+
+void QDeclarativeGridViewPrivate::init()
+{
+ Q_Q(QDeclarativeGridView);
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlag(QGraphicsItem::ItemIsFocusScope);
+ q->setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
+ addItemChangeListener(this, Geometry);
+}
+
+void QDeclarativeGridViewPrivate::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;
+}
+
+FxGridItem *QDeclarativeGridViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QDeclarativeGridView);
+ // create object
+ requestedIndex = modelIndex;
+ FxGridItem *listItem = 0;
+ if (QDeclarativeItem *item = model->item(modelIndex, false)) {
+ listItem = new FxGridItem(item, q);
+ listItem->index = modelIndex;
+ if (model->completePending()) {
+ // complete
+ listItem->item->setZValue(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ unrequestedItems.remove(listItem->item);
+ }
+ requestedIndex = -1;
+ return listItem;
+}
+
+
+void QDeclarativeGridViewPrivate::releaseItem(FxGridItem *item)
+{
+ Q_Q(QDeclarativeGridView);
+ 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 QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QDeclarativeGridView);
+ 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;
+ }
+
+ if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
+ || fillTo < rowPosAt(visibleIndex) - rowSize())) {
+ // We've jumped more than a page. Estimate which items are now
+ // visible and fill from there.
+ int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ modelIndex += count;
+ if (modelIndex >= model->count())
+ modelIndex = model->count() - 1;
+ else if (modelIndex < 0)
+ modelIndex = 0;
+ modelIndex = modelIndex / columns * columns;
+ visibleIndex = modelIndex;
+ colPos = colPosAt(visibleIndex);
+ rowPos = rowPosAt(visibleIndex);
+ }
+
+ int colNum = colPos / colSize();
+
+ FxGridItem *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 == QDeclarativeGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(endPosition() - startPosition());
+ } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
+ refill(from, to, true);
+ }
+ lazyRelease = false;
+}
+
+void QDeclarativeGridViewPrivate::updateGrid()
+{
+ Q_Q(QDeclarativeGridView);
+
+ columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
+ if (isValid()) {
+ if (flow == QDeclarativeGridView::LeftToRight)
+ q->setContentHeight(endPosition() - startPosition());
+ else
+ q->setContentWidth(lastPosition() - originPosition());
+ }
+}
+
+void QDeclarativeGridViewPrivate::scheduleLayout()
+{
+ Q_Q(QDeclarativeGridView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
+ }
+}
+
+void QDeclarativeGridViewPrivate::layout()
+{
+ Q_Q(QDeclarativeGridView);
+ 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) {
+ FxGridItem *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 == QDeclarativeGridView::LeftToRight) {
+ q->setContentHeight(endPosition() - startPosition());
+ fixupY();
+ } else {
+ q->setContentWidth(endPosition() - startPosition());
+ fixupX();
+ }
+ updateUnrequestedPositions();
+}
+
+void QDeclarativeGridViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QDeclarativeGridView);
+ QHash<QDeclarativeItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QDeclarativeGridViewPrivate::updateUnrequestedPositions()
+{
+ QHash<QDeclarativeItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QDeclarativeItem *item = it.key();
+ if (flow == QDeclarativeGridView::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 QDeclarativeGridViewPrivate::updateTrackedItem()
+{
+ Q_Q(QDeclarativeGridView);
+ FxGridItem *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 QDeclarativeGridViewPrivate::createHighlight()
+{
+ Q_Q(QDeclarativeGridView);
+ 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) {
+ QDeclarativeItem *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<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QDeclarativeItem;
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxGridItem(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 QDeclarativeGridViewPrivate::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 QDeclarativeGridViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QDeclarativeGridView);
+ 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;
+ }
+
+ FxGridItem *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 QDeclarativeGridViewPrivate::updateFooter()
+{
+ Q_Q(QDeclarativeGridView);
+ if (!footer && footerComponent) {
+ QDeclarativeItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZValue(1);
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ footer = new FxGridItem(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 == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width();
+ }
+ footer->setPosition(colOffset, endPos);
+ }
+ }
+}
+
+void QDeclarativeGridViewPrivate::updateHeader()
+{
+ Q_Q(QDeclarativeGridView);
+ if (!header && headerComponent) {
+ QDeclarativeItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZValue(1);
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ header = new FxGridItem(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 QDeclarativeGridViewPrivate::fixupPosition()
+{
+ moveReason = Other;
+ if (flow == QDeclarativeGridView::LeftToRight)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData)
+ || (flow == QDeclarativeGridView::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 != QDeclarativeGridView::NoSnap) {
+ qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+ FxGridItem *topItem = snapItemAt(tempPosition+highlightStart);
+ FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
+ qreal pos;
+ if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarativeGridView::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 {
+ QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
+ return;
+ }
+ if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::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 == QDeclarativeGridView::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 {
+ QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+}
+
+void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QDeclarativeGridView);
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
+ && snapMode == QDeclarativeGridView::NoSnap) {
+ QDeclarativeFlickablePrivate::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 == QDeclarativeGridView::SnapOneRow) {
+ if (FxGridItem *item = firstVisibleItem()) {
+ maxDistance = qAbs(item->rowPos() + dataValue);
+ }
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QDeclarativeGridView::SnapOneRow) {
+ qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
+ maxDistance = qAbs(pos + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+
+ bool overShoot = boundsBehavior == QDeclarativeFlickable::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 == QDeclarativeGridView::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(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);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass GridView QDeclarativeGridView
+ \since 4.7
+ \ingroup qml-view-elements
+
+ \inherits Flickable
+ \brief The GridView item provides a grid view of items provided by a model.
+
+ A GridView displays data from models created from built-in QML elements like ListModel
+ and XmlListModel, or custom model classes defined in C++ that inherit from
+ QAbstractListModel.
+
+ A GridView has a \l model, which defines the data to be displayed, and
+ a \l delegate, which defines how the data should be displayed. Items in a
+ GridView are laid out horizontally or vertically. Grid views are inherently flickable
+ as GridView inherits from \l Flickable.
+
+ \section1 Example Usage
+
+ The following example shows the definition of a simple list model defined
+ in a file called \c ContactModel.qml:
+
+ \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0
+
+ \div {class="float-right"}
+ \inlineimage gridview-simple.png
+ \enddiv
+
+ This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
+ for more information about creating reusable components like this.
+
+ Another component can display this model data in a GridView, as in the following
+ example, which creates a \c ContactModel component for its model, and a \l Column element
+ (containing \l Image and \l Text elements) for its delegate.
+
+ \clearfloat
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple
+
+ \div {class="float-right"}
+ \inlineimage gridview-highlight.png
+ \enddiv
+
+ The view will create a new delegate for each item in the model. Note that the delegate
+ is able to access the model's \c name and \c portrait data directly.
+
+ An improved grid view is shown below. The delegate is visually improved and is moved
+ into a separate \c contactDelegate component.
+
+ \clearfloat
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced
+
+ The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
+ and \c focus is set to \c true to enable keyboard navigation for the grid view.
+ The grid view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
+
+ Delegates are instantiated as needed and may be destroyed at any time.
+ State should \e never be stored in a delegate.
+
+ GridView attaches a number of properties to the root item of the delegate, for example
+ \c {GridView.isCurrentItem}. In the following example, the root delegate item can access
+ this attached property directly as \c GridView.isCurrentItem, while the child
+ \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
+
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
+
+ \note Views do not set the \l{Item::}{clip} property automatically.
+ If the view is not clipped by another item or the screen, it will be necessary
+ to set this property to true in order to clip the items that are partially or
+ fully outside the view.
+
+ \sa {declarative/modelviews/gridview}{GridView example}
+*/
+QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent)
+ : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent)
+{
+ Q_D(QDeclarativeGridView);
+ d->init();
+}
+
+QDeclarativeGridView::~QDeclarativeGridView()
+{
+ Q_D(QDeclarativeGridView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+/*!
+ \qmlattachedproperty bool GridView::isCurrentItem
+ This attached property is true if this delegate is the current item; otherwise false.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty GridView GridView::view
+ This attached property holds the view that manages this delegate instance.
+
+ It is attached to each instance of the delegate.
+
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
+*/
+
+/*!
+ \qmlattachedproperty bool GridView::delayRemove
+ This attached property holds whether the delegate may be destroyed.
+
+ It is attached to each instance of the delegate.
+
+ It is sometimes necessary to delay the destruction of an item
+ until an animation completes.
+
+ The example below ensures that the animation completes before
+ the item is removed from the grid.
+
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove
+*/
+
+/*!
+ \qmlattachedsignal GridView::onAdd()
+ This attached handler is called immediately after an item is added to the view.
+*/
+
+/*!
+ \qmlattachedsignal GridView::onRemove()
+ This attached handler is called immediately before an item is removed from the view.
+*/
+
+
+/*!
+ \qmlproperty model GridView::model
+ This property holds the model providing data for the grid.
+
+ The model provides the set of data that is used to create the items
+ in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
+ or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
+ used, it must be a subclass of \l QAbstractItemModel or a simple list.
+
+ \sa {qmlmodels}{Data Models}
+*/
+QVariant QDeclarativeGridView::model() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->modelVariant;
+}
+
+// For internal use
+int QDeclarativeGridView::modelCount() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->model->count();
+}
+
+void QDeclarativeGridView::setModel(const QVariant &model)
+{
+ Q_D(QDeclarativeGridView);
+ 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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ }
+ d->clear();
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QDeclarativeVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore | QDeclarativeGridViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QDeclarativeGridViewPrivate::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 = QDeclarativeGridViewPrivate::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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+/*!
+ \qmlproperty Component GridView::delegate
+
+ The delegate provides a template defining each item instantiated by the view.
+ The index is exposed as an accessible \c index property. Properties of the
+ model are also available depending upon the type of \l {qmlmodels}{Data Model}.
+
+ The number of elements in the delegate has a direct effect on the
+ flicking performance of the view. If at all possible, place functionality
+ that is not needed for the normal display of the delegate in a \l Loader which
+ can load additional elements when needed.
+
+ The GridView will layout the items based on the size of the root item
+ in the delegate.
+
+ \note Delegates are instantiated as needed and may be destroyed at any time.
+ State should \e never be stored in a delegate.
+*/
+QDeclarativeComponent *QDeclarativeGridView::delegate() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->model) {
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QDeclarativeGridView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QDeclarativeGridView);
+ if (delegate == this->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(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 = QDeclarativeGridViewPrivate::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 = QDeclarativeGridViewPrivate::Other;
+ }
+ emit delegateChanged();
+ }
+}
+
+/*!
+ \qmlproperty int GridView::currentIndex
+ \qmlproperty Item GridView::currentItem
+
+ The \c currentIndex property holds the index of the current item, and
+ \c currentItem holds the current item. Setting the currentIndex to -1
+ will clear the highlight and set currentItem to null.
+
+ If highlightFollowsCurrentItem is \c true, setting either of these
+ properties will smoothly scroll the GridView so that the current
+ item becomes visible.
+
+ Note that the position of the current item
+ may only be approximate until it becomes visible in the view.
+*/
+int QDeclarativeGridView::currentIndex() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->currentIndex;
+}
+
+void QDeclarativeGridView::setCurrentIndex(int index)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QDeclarativeItem *QDeclarativeGridView::currentItem()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+/*!
+ \qmlproperty Item GridView::highlightItem
+
+ This holds the highlight item created from the \l highlight component.
+
+ The highlightItem is managed by the view unless
+ \l highlightFollowsCurrentItem is set to false.
+
+ \sa highlight, highlightFollowsCurrentItem
+*/
+QDeclarativeItem *QDeclarativeGridView::highlightItem()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+/*!
+ \qmlproperty int GridView::count
+ This property holds the number of items in the view.
+*/
+int QDeclarativeGridView::count() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+/*!
+ \qmlproperty Component GridView::highlight
+ This property holds the component to use as the highlight.
+
+ An instance of the highlight component is created for each view.
+ The geometry of the resulting component instance will be managed by the view
+ so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
+
+ \sa highlightItem, highlightFollowsCurrentItem
+*/
+QDeclarativeComponent *QDeclarativeGridView::highlight() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->highlightComponent;
+}
+
+void QDeclarativeGridView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QDeclarativeGridView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->updateCurrent(d->currentIndex);
+ emit highlightChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool GridView::highlightFollowsCurrentItem
+ This property sets whether the highlight is managed by the view.
+
+ If this property is true (the default value), the highlight is moved smoothly
+ to follow the current item. Otherwise, the
+ highlight is not moved by the view, and any movement must be implemented
+ by the highlight.
+
+ Here is a highlight with its motion defined by a \l {SpringAnimation} item:
+
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem
+*/
+bool QDeclarativeGridView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->autoHighlight;
+}
+
+void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->autoHighlight != autoHighlight) {
+ d->autoHighlight = autoHighlight;
+ if (autoHighlight) {
+ d->updateHighlight();
+ } else if (d->highlightXAnimator) {
+ d->highlightXAnimator->stop();
+ d->highlightYAnimator->stop();
+ }
+ }
+}
+
+/*!
+ \qmlproperty int GridView::highlightMoveDuration
+ This property holds the move animation duration of the highlight delegate.
+
+ highlightFollowsCurrentItem must be true for this property
+ to have effect.
+
+ The default value for the duration is 150ms.
+
+ \sa highlightFollowsCurrentItem
+*/
+int QDeclarativeGridView::highlightMoveDuration() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->highlightMoveDuration;
+}
+
+void QDeclarativeGridView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightYAnimator) {
+ d->highlightXAnimator->userDuration = d->highlightMoveDuration;
+ d->highlightYAnimator->userDuration = d->highlightMoveDuration;
+ }
+ emit highlightMoveDurationChanged();
+ }
+}
+
+
+/*!
+ \qmlproperty real GridView::preferredHighlightBegin
+ \qmlproperty real GridView::preferredHighlightEnd
+ \qmlproperty enumeration GridView::highlightRangeMode
+
+ These properties define the preferred range of the highlight (for the current item)
+ within the view. The \c preferredHighlightBegin value must be less than the
+ \c preferredHighlightEnd value.
+
+ These properties affect the position of the current item when the view is scrolled.
+ For example, if the currently selected item should stay in the middle of the
+ view when it is scrolled, set the \c preferredHighlightBegin and
+ \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
+ item would be. If the \c currentItem is changed programmatically, the view will
+ automatically scroll so that the current item is in the middle of the view.
+ Furthermore, the behavior of the current item index will occur whether or not a
+ highlight exists.
+
+ Valid values for \c highlightRangeMode are:
+
+ \list
+ \o GridView.ApplyRange - the view attempts to maintain the highlight within the range.
+ However, the highlight can move outside of the range at the ends of the view or due
+ to mouse interaction.
+ \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
+ The current item changes if a keyboard or mouse action would cause the highlight to move
+ outside of the range.
+ \o GridView.NoHighlightRange - this is the default value.
+ \endlist
+*/
+qreal QDeclarativeGridView::preferredHighlightBegin() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->highlightRangeStart;
+}
+
+void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QDeclarativeGridView::resetPreferredHighlightBegin()
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QDeclarativeGridView::preferredHighlightEnd() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->highlightRangeEnd;
+}
+
+void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QDeclarativeGridView::resetPreferredHighlightEnd()
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->highlightRange;
+}
+
+void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+/*!
+ \qmlproperty enumeration GridView::layoutDirection
+ This property holds the layout direction of the grid.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
+ dependent on the \l GridView::flow property.
+ \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
+ on the \l GridView:flow property.
+ \endlist
+
+ \bold Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if
+ GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply
+ indicates that the flow is horizontal.
+*/
+
+Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->layoutDirection;
+}
+
+void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration GridView::effectiveLayoutDirection
+ This property holds the effective layout direction of the grid.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid will be mirrored. However, the
+ property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+/*!
+ \qmlproperty enumeration GridView::flow
+ This property holds the flow of the grid.
+
+ Possible values:
+
+ \list
+ \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
+ \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
+ \endlist
+*/
+QDeclarativeGridView::Flow QDeclarativeGridView::flow() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->flow;
+}
+
+void QDeclarativeGridView::setFlow(Flow flow)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->flow != flow) {
+ d->flow = flow;
+ if (d->flow == LeftToRight) {
+ setContentWidth(-1);
+ setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(QDeclarativeFlickable::HorizontalFlick);
+ }
+ setContentX(0);
+ setContentY(0);
+ d->regenerate();
+ emit flowChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool GridView::keyNavigationWraps
+ This property holds whether the grid wraps key navigation
+
+ If this is true, key navigation that would move the current item selection
+ past one end of the view instead wraps around and moves the selection to
+ the other end of the view.
+
+ By default, key navigation is not wrapped.
+*/
+bool QDeclarativeGridView::isWrapEnabled() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->wrap;
+}
+
+void QDeclarativeGridView::setWrapEnabled(bool wrap)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+/*!
+ \qmlproperty int GridView::cacheBuffer
+ This property determines whether delegates are retained outside the
+ visible area of the view.
+
+ If non-zero the view will keep as many delegates
+ instantiated as will fit within the buffer specified. For example,
+ if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
+ set to 40, then up to 2 delegates above and 2 delegates below the visible
+ area may be retained.
+
+ Note that cacheBuffer is not a pixel buffer - it only maintains additional
+ instantiated delegates.
+
+ Setting this value can make scrolling the list smoother at the expense
+ of additional memory usage. It is not a substitute for creating efficient
+ delegates; the fewer elements in a delegate, the faster a view may be
+ scrolled.
+*/
+int QDeclarativeGridView::cacheBuffer() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->buffer;
+}
+
+void QDeclarativeGridView::setCacheBuffer(int buffer)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->buffer != buffer) {
+ d->buffer = buffer;
+ if (isComponentComplete())
+ refill();
+ emit cacheBufferChanged();
+ }
+}
+
+/*!
+ \qmlproperty int GridView::cellWidth
+ \qmlproperty int GridView::cellHeight
+
+ These properties holds the width and height of each cell in the grid.
+
+ The default cell size is 100x100.
+*/
+int QDeclarativeGridView::cellWidth() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->cellWidth;
+}
+
+void QDeclarativeGridView::setCellWidth(int cellWidth)
+{
+ Q_D(QDeclarativeGridView);
+ if (cellWidth != d->cellWidth && cellWidth > 0) {
+ d->cellWidth = qMax(1, cellWidth);
+ d->updateGrid();
+ emit cellWidthChanged();
+ d->layout();
+ }
+}
+
+int QDeclarativeGridView::cellHeight() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->cellHeight;
+}
+
+void QDeclarativeGridView::setCellHeight(int cellHeight)
+{
+ Q_D(QDeclarativeGridView);
+ if (cellHeight != d->cellHeight && cellHeight > 0) {
+ d->cellHeight = qMax(1, cellHeight);
+ d->updateGrid();
+ emit cellHeightChanged();
+ d->layout();
+ }
+}
+/*!
+ \qmlproperty enumeration GridView::snapMode
+
+ This property determines how the view scrolling will settle following a drag or flick.
+ The possible values are:
+
+ \list
+ \o GridView.NoSnap (default) - the view stops anywhere within the visible area.
+ \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
+ aligned with the start of the view.
+ \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
+ away from the first visible row at the time the mouse button is released.
+ This mode is particularly useful for moving one page at a time.
+ \endlist
+
+*/
+QDeclarativeGridView::SnapMode QDeclarativeGridView::snapMode() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->snapMode;
+}
+
+void QDeclarativeGridView::setSnapMode(SnapMode mode)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+/*!
+ \qmlproperty Component GridView::footer
+ This property holds the component to use as the footer.
+
+ An instance of the footer component is created for each view. The
+ footer is positioned at the end of the view, after any items.
+
+ \sa header
+*/
+QDeclarativeComponent *QDeclarativeGridView::footer() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->footerComponent;
+}
+
+void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ if (scene())
+ scene()->removeItem(d->footer->item);
+ d->footer->item->deleteLater();
+ delete d->footer;
+ d->footer = 0;
+ }
+ d->footerComponent = footer;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateGrid();
+ d->fixupPosition();
+ }
+ emit footerChanged();
+ }
+}
+
+/*!
+ \qmlproperty Component GridView::header
+ This property holds the component to use as the header.
+
+ An instance of the header component is created for each view. The
+ header is positioned at the beginning of the view, before any items.
+
+ \sa footer
+*/
+QDeclarativeComponent *QDeclarativeGridView::header() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->headerComponent;
+}
+
+void QDeclarativeGridView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ if (scene())
+ scene()->removeItem(d->header->item);
+ 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 QDeclarativeGridView::setContentX(qreal pos)
+{
+ Q_D(QDeclarativeGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QDeclarativeGridViewPrivate::Other;
+ QDeclarativeFlickable::setContentX(pos);
+}
+
+void QDeclarativeGridView::setContentY(qreal pos)
+{
+ Q_D(QDeclarativeGridView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QDeclarativeGridViewPrivate::Other;
+ QDeclarativeFlickable::setContentY(pos);
+}
+
+bool QDeclarativeGridView::event(QEvent *event)
+{
+ Q_D(QDeclarativeGridView);
+ if (event->type() == QEvent::User) {
+ d->layout();
+ return true;
+ }
+
+ return QDeclarativeFlickable::event(event);
+}
+
+void QDeclarativeGridView::viewportMoved()
+{
+ Q_D(QDeclarativeGridView);
+ QDeclarativeFlickable::viewportMoved();
+ if (!d->itemCount)
+ return;
+ d->lazyRelease = true;
+ if (d->flickingHorizontally || d->flickingVertically) {
+ if (yflick()) {
+ if (d->vData.velocity > 0)
+ d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
+ else if (d->vData.velocity < 0)
+ d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
+ }
+
+ if (xflick()) {
+ if (d->hData.velocity > 0)
+ d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
+ else if (d->hData.velocity < 0)
+ d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
+ }
+ }
+ refill();
+ if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
+ d->moveReason = QDeclarativeGridViewPrivate::Mouse;
+ if (d->moveReason != QDeclarativeGridViewPrivate::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 QDeclarativeGridView::minYExtent() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->flow == QDeclarativeGridView::TopToBottom)
+ return QDeclarativeFlickable::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 QDeclarativeGridView::maxYExtent() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->flow == QDeclarativeGridView::TopToBottom)
+ return QDeclarativeFlickable::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 QDeclarativeGridView::minXExtent() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->flow == QDeclarativeGridView::LeftToRight)
+ return QDeclarativeFlickable::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 QDeclarativeGridView::maxXExtent() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->flow == QDeclarativeGridView::LeftToRight)
+ return QDeclarativeFlickable::maxXExtent();
+ qreal extent;
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition = 0;
+ 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;
+ lastItemPosition = 0;
+ 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 QDeclarativeGridView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeGridView);
+ keyPressPreHandler(event);
+ if (event->isAccepted())
+ return;
+ if (d->model && d->model->count() && d->interactive) {
+ d->moveReason = QDeclarativeGridViewPrivate::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 = QDeclarativeGridViewPrivate::Other;
+ event->ignore();
+ QDeclarativeFlickable::keyPressEvent(event);
+}
+
+/*!
+ \qmlmethod GridView::moveCurrentIndexUp()
+
+ Move the currentIndex up one item in the view.
+ The current index will wrap if keyNavigationWraps is true and it
+ is currently at the end. This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeGridView::moveCurrentIndexUp()
+{
+ Q_D(QDeclarativeGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QDeclarativeGridView::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);
+ }
+ }
+}
+
+/*!
+ \qmlmethod GridView::moveCurrentIndexDown()
+
+ Move the currentIndex down one item in the view.
+ The current index will wrap if keyNavigationWraps is true and it
+ is currently at the end. This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeGridView::moveCurrentIndexDown()
+{
+ Q_D(QDeclarativeGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+ if (d->flow == QDeclarativeGridView::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);
+ }
+ }
+}
+
+/*!
+ \qmlmethod GridView::moveCurrentIndexLeft()
+
+ Move the currentIndex left one item in the view.
+ The current index will wrap if keyNavigationWraps is true and it
+ is currently at the end. This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeGridView::moveCurrentIndexLeft()
+{
+ Q_D(QDeclarativeGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QDeclarativeGridView::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 == QDeclarativeGridView::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);
+ }
+ }
+ }
+}
+
+/*!
+ \qmlmethod GridView::moveCurrentIndexRight()
+
+ Move the currentIndex right one item in the view.
+ The current index will wrap if keyNavigationWraps is true and it
+ is currently at the end. This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeGridView::moveCurrentIndexRight()
+{
+ Q_D(QDeclarativeGridView);
+ const int count = d->model ? d->model->count() : 0;
+ if (!count)
+ return;
+
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QDeclarativeGridView::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 == QDeclarativeGridView::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 QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QDeclarativeGridView);
+ if (!isValid())
+ return;
+ if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
+ return;
+
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
+ FxGridItem *item = visibleItem(idx);
+ qreal maxExtent;
+ if (flow == QDeclarativeGridView::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<FxGridItem*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visibleIndex = idx - idx % columns;
+ if (flow == QDeclarativeGridView::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 QDeclarativeGridView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header) {
+ pos -= flow == QDeclarativeGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+ break;
+ case QDeclarativeGridView::Center:
+ pos = itemPos - (size() - rowSize())/2;
+ break;
+ case QDeclarativeGridView::End:
+ pos = itemPos - size() + rowSize();
+ if (index >= model->count() && footer) {
+ pos += flow == QDeclarativeGridView::LeftToRight
+ ? footer->item->height()
+ : footer->item->width();
+ }
+ break;
+ case QDeclarativeGridView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + rowSize();
+ else if (item->endRowPos() < pos)
+ pos = itemPos;
+ break;
+ case QDeclarativeGridView::Contain:
+ if (item->endRowPos() > pos + size())
+ pos = itemPos - size() + rowSize();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (flow == QDeclarativeGridView::LeftToRight)
+ minExtent = -q->minYExtent();
+ else
+ minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
+ pos = qMax(pos, minExtent);
+ moveReason = QDeclarativeGridViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ }
+ fixupPosition();
+}
+
+/*!
+ \qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
+
+ Positions the view such that the \a index is at the position specified by
+ \a mode:
+
+ \list
+ \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
+ \o GridView.Center - position item in the center of the view.
+ \o GridView.End - position item at bottom (or right for horizontal orientation) of the view.
+ \o GridView.Visible - if any part of the item is visible then take no action, otherwise
+ bring the item into view.
+ \o GridView.Contain - ensure the entire item is visible. If the item is larger than
+ the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
+ \endlist
+
+ If positioning the view at the index would cause empty space to be displayed at
+ the beginning or end of the view, the view will be positioned at the boundary.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the view does not cause all other items to be repositioned.
+ The correct way to bring an item into view is with \c positionViewAtIndex.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end:
+
+ \code
+ Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
+ \endcode
+*/
+void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+/*!
+ \qmlmethod GridView::positionViewAtBeginning()
+ \qmlmethod GridView::positionViewAtEnd()
+ \since Quick 1.1
+
+ Positions the view at the beginning or end, taking into account any header or footer.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the list does not cause all other items to be repositioned, and because
+ the actual start of the view can vary based on the size of the delegates.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end on startup:
+
+ \code
+ Component.onCompleted: positionViewAtEnd()
+ \endcode
+*/
+void QDeclarativeGridView::positionViewAtBeginning()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QDeclarativeGridView::positionViewAtEnd()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+/*!
+ \qmlmethod int GridView::indexAt(int x, int y)
+
+ Returns the index of the visible item containing the point \a x, \a y in content
+ coordinates. If there is no item at the point specified, or the item is
+ not visible -1 is returned.
+
+ If the item is outside the visible area, -1 is returned, regardless of
+ whether an item will exist at that point when scrolled into view.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+int QDeclarativeGridView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QDeclarativeGridView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxGridItem *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QDeclarativeGridView::componentComplete()
+{
+ Q_D(QDeclarativeGridView);
+ QDeclarativeFlickable::componentComplete();
+ d->updateHeader();
+ d->updateFooter();
+ d->updateGrid();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QDeclarativeGridViewPrivate::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 = QDeclarativeGridViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QDeclarativeGridView::trackedPositionChanged()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QDeclarativeGridViewPrivate::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 QDeclarativeGridView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QDeclarativeGridView);
+ 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) {
+ FxGridItem *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()+d->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) {
+ FxGridItem *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem->index >= modelIndex)
+ listItem->index += count;
+ }
+
+ bool addedVisible = false;
+ QList<FxGridItem*> 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;
+ }
+ FxGridItem *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<FxGridItem*>::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));
+ }
+ emit currentIndexChanged();
+ } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ 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 QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QDeclarativeGridView);
+ 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<FxGridItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItem *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));
+ else
+ emit currentIndexChanged();
+ }
+
+ // 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();
+ update();
+ }
+ }
+
+ emit countChanged();
+}
+
+void QDeclarativeGridView::destroyRemoved()
+{
+ Q_D(QDeclarativeGridView);
+ for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxGridItem *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 QDeclarativeGridView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QDeclarativeGridView);
+ if (!isComponentComplete())
+ return;
+ QHash<int,FxGridItem*> moved;
+
+ FxGridItem *firstItem = d->firstVisibleItem();
+
+ QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItem *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()) {
+ FxGridItem *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxGridItem *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 (FxGridItem *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();
+ FxGridItem *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 QDeclarativeGridView::modelReset()
+{
+ Q_D(QDeclarativeGridView);
+ d->clear();
+ refill();
+ d->moveReason = QDeclarativeGridViewPrivate::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 = QDeclarativeGridViewPrivate::Other;
+
+ emit countChanged();
+}
+
+void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(this);
+ d->unrequestedItems.insert(item, index);
+ if (d->flow == QDeclarativeGridView::LeftToRight) {
+ item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
+ } else {
+ item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
+ }
+ }
+}
+
+void QDeclarativeGridView::destroyingItem(QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeGridView);
+ d->unrequestedItems.remove(item);
+}
+
+void QDeclarativeGridView::animStopped()
+{
+ Q_D(QDeclarativeGridView);
+ d->bufferMode = QDeclarativeGridViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QDeclarativeGridView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+void QDeclarativeGridView::refill()
+{
+ Q_D(QDeclarativeGridView);
+ if (d->isRightToLeftTopToBottom())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+
+QDeclarativeGridViewAttached *QDeclarativeGridView::qmlAttachedProperties(QObject *obj)
+{
+ return new QDeclarativeGridViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativegridview_p.h b/src/declarative/graphicsitems/qdeclarativegridview_p.h
new file mode 100644
index 0000000000..4d99a14d78
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativegridview_p.h
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEGRIDVIEW_H
+#define QDECLARATIVEGRIDVIEW_H
+
+#include "private/qdeclarativeflickable_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QDeclarativeVisualModel;
+class QDeclarativeGridViewAttached;
+class QDeclarativeGridViewPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeGridView : public QDeclarativeFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeGridView)
+
+ 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(QDeclarativeItem *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(QDeclarativeItem *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 REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
+ 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:
+ QDeclarativeGridView(QDeclarativeItem *parent=0);
+ ~QDeclarativeGridView();
+
+ QVariant model() const;
+ int modelCount() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QDeclarativeItem *currentItem();
+ QDeclarativeItem *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 Q_REVISION(1) void positionViewAtBeginning();
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
+
+ static QDeclarativeGridViewAttached *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();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
+ void keyNavigationWrapsChanged();
+ void cacheBufferChanged();
+ void snapModeChanged();
+ void headerChanged();
+ void footerChanged();
+
+protected:
+ virtual bool event(QEvent *event);
+ 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, QDeclarativeItem *item);
+ void destroyingItem(QDeclarativeItem *item);
+ void animStopped();
+
+private:
+ void refill();
+};
+
+class QDeclarativeGridViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeGridViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QDeclarativeGridViewAttached() {}
+
+ Q_PROPERTY(QDeclarativeGridView *view READ view NOTIFY viewChanged)
+ QDeclarativeGridView *view() { return m_view; }
+ void setView(QDeclarativeGridView *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<QDeclarativeGridView> m_view;
+ bool m_isCurrent : 1;
+ bool m_delayRemove : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeGridView)
+QML_DECLARE_TYPEINFO(QDeclarativeGridView, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp
new file mode 100644
index 0000000000..b77653243a
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp
@@ -0,0 +1,584 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeimage_p.h"
+#include "private/qdeclarativeimage_p_p.h"
+
+#include <QKeyEvent>
+#include <QPainter>
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \qmlclass Image QDeclarativeImage
+ \since 4.7
+ \ingroup qml-basic-visual-elements
+ \brief The Image element displays an image in a declarative user interface
+ \inherits Item
+
+ The Image element is used to display images in a declarative user interface.
+
+ The source of the image is specified as a URL using the \l source property.
+ Images can be supplied in any of the standard image formats supported by Qt,
+ including bitmap formats such as PNG and JPEG, and vector graphics formats
+ such as SVG. If you need to display animated images, use the \l AnimatedImage
+ element.
+
+ If the \l{Item::width}{width} and \l{Item::height}{height} properties are not
+ specified, the Image element automatically uses the size of the loaded image.
+ By default, specifying the width and height of the element causes the image
+ to be scaled to that size. This behavior can be changed by setting the
+ \l fillMode property, allowing the image to be stretched and tiled instead.
+
+ \section1 Example Usage
+
+ The following example shows the simplest usage of the Image element.
+
+ \snippet doc/src/snippets/declarative/image.qml document
+
+ \beginfloatleft
+ \image declarative-qtlogo.png
+ \endfloat
+
+ \clearfloat
+
+ \section1 Performance
+
+ By default, locally available images are loaded immediately, and the user interface
+ is blocked until loading is complete. If a large image is to be loaded, it may be
+ preferable to load the image in a low priority thread, by enabling the \l asynchronous
+ property.
+
+ If the image is obtained from a network rather than a local resource, it is
+ automatically loaded asynchronously, and the \l progress and \l status properties
+ are updated as appropriate.
+
+ Images are cached and shared internally, so if several Image elements have the same \l source,
+ only one copy of the image will be loaded.
+
+ \bold Note: Images are often the greatest user of memory in QML user interfaces. It is recommended
+ that images which do not form part of the user interface have their
+ size bounded via the \l sourceSize property. This is especially important for content
+ that is loaded from external sources or provided by the user.
+
+ \sa {declarative/imageelements/image}{Image example}, QDeclarativeImageProvider
+*/
+
+QDeclarativeImage::QDeclarativeImage(QDeclarativeItem *parent)
+ : QDeclarativeImageBase(*(new QDeclarativeImagePrivate), parent)
+{
+}
+
+QDeclarativeImage::QDeclarativeImage(QDeclarativeImagePrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativeImageBase(dd, parent)
+{
+}
+
+QDeclarativeImage::~QDeclarativeImage()
+{
+}
+
+QPixmap QDeclarativeImage::pixmap() const
+{
+ Q_D(const QDeclarativeImage);
+ return d->pix.pixmap();
+}
+
+void QDeclarativeImage::setPixmap(const QPixmap &pix)
+{
+ Q_D(QDeclarativeImage);
+ if (!d->url.isEmpty())
+ return;
+ d->setPixmap(pix);
+}
+
+void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap)
+{
+ Q_Q(QDeclarativeImage);
+ pix.setPixmap(pixmap);
+
+ q->pixmapChange();
+ status = pix.isNull() ? QDeclarativeImageBase::Null : QDeclarativeImageBase::Ready;
+
+ q->update();
+}
+
+/*!
+ \qmlproperty enumeration Image::fillMode
+
+ Set this property to define what happens when the source image has a different size
+ than the item.
+
+ \list
+ \o Image.Stretch - the image is scaled to fit
+ \o Image.PreserveAspectFit - the image is scaled uniformly to fit without cropping
+ \o Image.PreserveAspectCrop - the image is scaled uniformly to fill, cropping if necessary
+ \o Image.Tile - the image is duplicated horizontally and vertically
+ \o Image.TileVertically - the image is stretched horizontally and tiled vertically
+ \o Image.TileHorizontally - the image is stretched vertically and tiled horizontally
+ \endlist
+
+ \table
+
+ \row
+ \o \image declarative-qtlogo-stretch.png
+ \o Stretch (default)
+ \qml
+ Image {
+ width: 130; height: 100
+ smooth: true
+ source: "qtlogo.png"
+ }
+ \endqml
+
+ \row
+ \o \image declarative-qtlogo-preserveaspectfit.png
+ \o PreserveAspectFit
+ \qml
+ Image {
+ width: 130; height: 100
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ source: "qtlogo.png"
+ }
+ \endqml
+
+ \row
+ \o \image declarative-qtlogo-preserveaspectcrop.png
+ \o PreserveAspectCrop
+ \qml
+ Image {
+ width: 130; height: 100
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+ source: "qtlogo.png"
+ clip: true
+ }
+ \endqml
+
+ \row
+ \o \image declarative-qtlogo-tile.png
+ \o Tile
+ \qml
+ Image {
+ width: 120; height: 120
+ fillMode: Image.Tile
+ source: "qtlogo.png"
+ }
+ \endqml
+
+ \row
+ \o \image declarative-qtlogo-tilevertically.png
+ \o TileVertically
+ \qml
+ Image {
+ width: 120; height: 120
+ fillMode: Image.TileVertically
+ smooth: true
+ source: "qtlogo.png"
+ }
+ \endqml
+
+ \row
+ \o \image declarative-qtlogo-tilehorizontally.png
+ \o TileHorizontally
+ \qml
+ Image {
+ width: 120; height: 120
+ fillMode: Image.TileHorizontally
+ smooth: true
+ source: "qtlogo.png"
+ }
+ \endqml
+
+ \endtable
+
+ Note that \c clip is \c false by default which means that the element might
+ paint outside its bounding rectangle even if the fillMode is set to \c PreserveAspectCrop.
+
+ \sa {declarative/imageelements/image}{Image example}
+*/
+QDeclarativeImage::FillMode QDeclarativeImage::fillMode() const
+{
+ Q_D(const QDeclarativeImage);
+ return d->fillMode;
+}
+
+void QDeclarativeImage::setFillMode(FillMode mode)
+{
+ Q_D(QDeclarativeImage);
+ if (d->fillMode == mode)
+ return;
+ d->fillMode = mode;
+ update();
+ updatePaintedGeometry();
+ emit fillModeChanged();
+}
+
+/*!
+
+ \qmlproperty real Image::paintedWidth
+ \qmlproperty real Image::paintedHeight
+
+ These properties hold the size of the image that is actually painted.
+ In most cases it is the same as \c width and \c height, but when using a
+ \c fillMode \c PreserveAspectFit or \c fillMode \c PreserveAspectCrop
+ \c paintedWidth or \c paintedHeight can be smaller or larger than
+ \c width and \c height of the Image element.
+*/
+qreal QDeclarativeImage::paintedWidth() const
+{
+ Q_D(const QDeclarativeImage);
+ return d->paintedWidth;
+}
+
+qreal QDeclarativeImage::paintedHeight() const
+{
+ Q_D(const QDeclarativeImage);
+ return d->paintedHeight;
+}
+
+/*!
+ \qmlproperty enumeration Image::status
+
+ This property holds the status of image loading. It can be one of:
+ \list
+ \o Image.Null - no image has been set
+ \o Image.Ready - the image has been loaded
+ \o Image.Loading - the image is currently being loaded
+ \o Image.Error - an error occurred while loading the image
+ \endlist
+
+ Use this status to provide an update or respond to the status change in some way.
+ For example, you could:
+
+ \list
+ \o Trigger a state change:
+ \qml
+ State { name: 'loaded'; when: image.status == Image.Ready }
+ \endqml
+
+ \o Implement an \c onStatusChanged signal handler:
+ \qml
+ Image {
+ id: image
+ onStatusChanged: if (image.status == Image.Ready) console.log('Loaded')
+ }
+ \endqml
+
+ \o Bind to the status value:
+ \qml
+ Text { text: image.status == Image.Ready ? 'Loaded' : 'Not loaded' }
+ \endqml
+ \endlist
+
+ \sa progress
+*/
+
+/*!
+ \qmlproperty real Image::progress
+
+ This property holds the progress of image loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+
+/*!
+ \qmlproperty bool Image::smooth
+
+ Set this property if you want the image to be smoothly filtered when scaled or
+ transformed. Smooth filtering gives better visual quality, but is slower. If
+ the image is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the image is stationary on
+ the screen. A common pattern when animating an image is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+ \qmlproperty QSize Image::sourceSize
+
+ This property holds the actual width and height of the loaded image.
+
+ Unlike the \l {Item::}{width} and \l {Item::}{height} properties, which scale
+ the painting of the image, this property sets the actual number of pixels
+ stored for the loaded image so that large images do not use more
+ memory than necessary. For example, this ensures the image in memory is no
+ larger than 1024x1024 pixels, regardless of the Image's \l {Item::}{width} and
+ \l {Item::}{height} values:
+
+ \code
+ Rectangle {
+ width: ...
+ height: ...
+
+ Image {
+ anchors.fill: parent
+ source: "reallyBigImage.jpg"
+ sourceSize.width: 1024
+ sourceSize.height: 1024
+ }
+ }
+ \endcode
+
+ If the image's actual size is larger than the sourceSize, the image is scaled down.
+ If only one dimension of the size is set to greater than 0, the
+ other dimension is set in proportion to preserve the source image's aspect ratio.
+ (The \l fillMode is independent of this.)
+
+ If the source is an instrinsically scalable image (eg. SVG), this property
+ determines the size of the loaded image regardless of intrinsic size.
+ Avoid changing this property dynamically; rendering an SVG is \e slow compared
+ to an image.
+
+ If the source is a non-scalable image (eg. JPEG), the loaded image will
+ be no greater than this property specifies. For some formats (currently only JPEG),
+ the whole image will never actually be loaded into memory.
+
+ Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image
+ by setting sourceSize to \c undefined.
+
+ \note \e {Changing this property dynamically causes the image source to be reloaded,
+ potentially even from the network, if it is not in the disk cache.}
+*/
+
+void QDeclarativeImage::updatePaintedGeometry()
+{
+ Q_D(QDeclarativeImage);
+
+ if (d->fillMode == PreserveAspectFit) {
+ if (!d->pix.width() || !d->pix.height()) {
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ 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);
+ } else {
+ setImplicitHeight(d->pix.height());
+ }
+ if (heightValid() && !widthValid()) {
+ setImplicitWidth(d->paintedWidth);
+ } else {
+ setImplicitWidth(d->pix.width());
+ }
+ } 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 QDeclarativeImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QDeclarativeImageBase::geometryChanged(newGeometry, oldGeometry);
+ updatePaintedGeometry();
+}
+
+QRectF QDeclarativeImage::boundingRect() const
+{
+ Q_D(const QDeclarativeImage);
+ return QRectF(0, 0, qMax(d->mWidth, d->paintedWidth), qMax(d->mHeight, d->paintedHeight));
+}
+
+/*!
+ \qmlproperty url Image::source
+
+ Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
+
+ The URL may be absolute, or relative to the URL of the component.
+
+ \sa QDeclarativeImageProvider
+*/
+
+/*!
+ \qmlproperty bool Image::asynchronous
+
+ Specifies that images on the local filesystem should be loaded
+ asynchronously in a separate thread. The default value is
+ false, causing the user interface thread to block while the
+ image is loaded. Setting \a asynchronous to true is useful where
+ maintaining a responsive user interface is more desirable
+ than having images immediately visible.
+
+ Note that this property is only valid for images read from the
+ local filesystem. Images loaded via a network resource (e.g. HTTP)
+ are always loaded asynchonously.
+*/
+
+/*!
+ \qmlproperty bool Image::cache
+ \since Quick 1.1
+
+ Specifies whether the image should be cached. The default value is
+ true. Setting \a cache to false is useful when dealing with large images,
+ to make sure that they aren't cached at the expense of small 'ui element' images.
+*/
+
+/*!
+ \qmlproperty bool Image::mirror
+ \since Quick 1.1
+
+ This property holds whether the image should be horizontally inverted
+ (effectively displaying a mirrored image).
+
+ The default value is false.
+*/
+
+
+void QDeclarativeImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ Q_D(QDeclarativeImage);
+ if (d->pix.pixmap().isNull() )
+ return;
+
+ int drawWidth = width();
+ int drawHeight = height();
+ bool doClip = false;
+ QTransform transform;
+ qreal widthScale = width() / qreal(d->pix.width());
+ qreal heightScale = height() / qreal(d->pix.height());
+
+ if (width() != d->pix.width() || height() != d->pix.height()) {
+ if (d->fillMode >= Tile) {
+ if (d->fillMode == TileVertically) {
+ transform.scale(widthScale, 1.0);
+ drawWidth = d->pix.width();
+ } else if (d->fillMode == TileHorizontally) {
+ transform.scale(1.0, heightScale);
+ drawHeight = d->pix.height();
+ }
+ } else {
+ if (d->fillMode == PreserveAspectFit) {
+ if (widthScale <= heightScale) {
+ heightScale = widthScale;
+ transform.translate(0, (height() - heightScale * d->pix.height()) / 2);
+ } else if(heightScale < widthScale) {
+ widthScale = heightScale;
+ transform.translate((width() - widthScale * d->pix.width()) / 2, 0);
+ }
+ } else if (d->fillMode == PreserveAspectCrop) {
+ if (widthScale < heightScale) {
+ widthScale = heightScale;
+ transform.translate((width() - widthScale * d->pix.width()) / 2, 0);
+ } else if(heightScale < widthScale) {
+ heightScale = widthScale;
+ transform.translate(0, (height() - heightScale * d->pix.height()) / 2);
+ }
+ }
+ transform.scale(widthScale, heightScale);
+ drawWidth = d->pix.width();
+ drawHeight = d->pix.height();
+ doClip = clip();
+ }
+ }
+
+ QTransform oldTransform;
+ bool oldAA = p->testRenderHint(QPainter::Antialiasing);
+ bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
+ if (d->smooth)
+ p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
+ if (doClip) {
+ p->save();
+ p->setClipRect(QRectF(0, 0, d->mWidth, d->mHeight), Qt::IntersectClip);
+ }
+ if (d->mirror)
+ transform.translate(drawWidth, 0).scale(-1.0, 1.0);
+ if (!transform.isIdentity()) {
+ oldTransform = p->transform();
+ p->setWorldTransform(transform * oldTransform);
+ }
+
+ if (d->fillMode >= Tile)
+ p->drawTiledPixmap(QRectF(0, 0, drawWidth, drawHeight), d->pix);
+ else
+ p->drawPixmap(QRectF(0, 0, drawWidth, drawHeight), d->pix, QRectF(0, 0, drawWidth, drawHeight));
+
+ if (d->smooth) {
+ p->setRenderHint(QPainter::Antialiasing, oldAA);
+ p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
+ }
+ if (doClip)
+ p->restore();
+ if (!transform.isIdentity())
+ p->setWorldTransform(oldTransform);
+}
+
+void QDeclarativeImage::pixmapChange()
+{
+ Q_D(QDeclarativeImage);
+ // PreserveAspectFit calculates the implicit size differently so we
+ // don't call our superclass pixmapChange(), since that would
+ // result in the implicit size being set incorrectly, then updated
+ // in updatePaintedGeometry()
+ if (d->fillMode != PreserveAspectFit)
+ QDeclarativeImageBase::pixmapChange();
+ updatePaintedGeometry();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeimage_p.h b/src/declarative/graphicsitems/qdeclarativeimage_p.h
new file mode 100644
index 0000000000..f937d163f8
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimage_p.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 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 QDECLARATIVEIMAGE_H
+#define QDECLARATIVEIMAGE_H
+
+#include "private/qdeclarativeimagebase_p.h"
+
+#include <QtNetwork/qnetworkreply.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeImagePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeImage : public QDeclarativeImageBase
+{
+ 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)
+
+public:
+ QDeclarativeImage(QDeclarativeItem *parent=0);
+ ~QDeclarativeImage();
+
+ enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally };
+ FillMode fillMode() const;
+ void setFillMode(FillMode);
+
+ QPixmap pixmap() const;
+ void setPixmap(const QPixmap &);
+
+ qreal paintedWidth() const;
+ qreal paintedHeight() const;
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void fillModeChanged();
+ void paintedGeometryChanged();
+
+protected:
+ QDeclarativeImage(QDeclarativeImagePrivate &dd, QDeclarativeItem *parent);
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ void pixmapChange();
+ void updatePaintedGeometry();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeImage)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeImage)
+};
+
+QT_END_NAMESPACE
+QML_DECLARE_TYPE(QDeclarativeImage)
+QT_END_HEADER
+
+#endif // QDECLARATIVEIMAGE_H
diff --git a/src/declarative/graphicsitems/qdeclarativeimage_p_p.h b/src/declarative/graphicsitems/qdeclarativeimage_p_p.h
new file mode 100644
index 0000000000..a94bb15500
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimage_p_p.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 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 QDECLARATIVEIMAGE_P_H
+#define QDECLARATIVEIMAGE_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/qdeclarativeitem_p.h"
+#include "private/qdeclarativeimagebase_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeImagePrivate : public QDeclarativeImageBasePrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeImage)
+
+public:
+ QDeclarativeImagePrivate()
+ : fillMode(QDeclarativeImage::Stretch), paintedWidth(0), paintedHeight(0)
+ {
+ }
+
+ QDeclarativeImage::FillMode fillMode;
+ qreal paintedWidth;
+ qreal paintedHeight;
+ void setPixmap(const QPixmap &pix);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEIMAGE_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp
new file mode 100644
index 0000000000..81eac78b2f
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeimagebase_p.h"
+#include "private/qdeclarativeimagebase_p_p.h"
+
+#include <qdeclarativeengine.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativepixmapcache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeImageBase::QDeclarativeImageBase(QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(*(new QDeclarativeImageBasePrivate), parent)
+{
+}
+
+QDeclarativeImageBase::QDeclarativeImageBase(QDeclarativeImageBasePrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(dd, parent)
+{
+}
+
+QDeclarativeImageBase::~QDeclarativeImageBase()
+{
+}
+
+QDeclarativeImageBase::Status QDeclarativeImageBase::status() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->status;
+}
+
+
+qreal QDeclarativeImageBase::progress() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->progress;
+}
+
+
+bool QDeclarativeImageBase::asynchronous() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->async;
+}
+
+void QDeclarativeImageBase::setAsynchronous(bool async)
+{
+ Q_D(QDeclarativeImageBase);
+ if (d->async != async) {
+ d->async = async;
+ emit asynchronousChanged();
+ }
+}
+
+QUrl QDeclarativeImageBase::source() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->url;
+}
+
+void QDeclarativeImageBase::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeImageBase);
+ //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 QDeclarativeImageBase::setSourceSize(const QSize& size)
+{
+ Q_D(QDeclarativeImageBase);
+ if (d->sourcesize == size)
+ return;
+
+ d->sourcesize = size;
+ d->explicitSourceSize = true;
+ emit sourceSizeChanged();
+ if (isComponentComplete())
+ load();
+}
+
+QSize QDeclarativeImageBase::sourceSize() const
+{
+ Q_D(const QDeclarativeImageBase);
+
+ int width = d->sourcesize.width();
+ int height = d->sourcesize.height();
+ return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
+}
+
+void QDeclarativeImageBase::resetSourceSize()
+{
+ Q_D(QDeclarativeImageBase);
+ if (!d->explicitSourceSize)
+ return;
+ d->explicitSourceSize = false;
+ d->sourcesize = QSize();
+ emit sourceSizeChanged();
+ if (isComponentComplete())
+ load();
+}
+
+bool QDeclarativeImageBase::cache() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->cache;
+}
+
+void QDeclarativeImageBase::setCache(bool cache)
+{
+ Q_D(QDeclarativeImageBase);
+ if (d->cache == cache)
+ return;
+
+ d->cache = cache;
+ emit cacheChanged();
+ if (isComponentComplete())
+ load();
+}
+
+void QDeclarativeImageBase::setMirror(bool mirror)
+{
+ Q_D(QDeclarativeImageBase);
+ if (mirror == d->mirror)
+ return;
+
+ d->mirror = mirror;
+
+ if (isComponentComplete())
+ update();
+
+ emit mirrorChanged();
+}
+
+bool QDeclarativeImageBase::mirror() const
+{
+ Q_D(const QDeclarativeImageBase);
+ return d->mirror;
+}
+
+void QDeclarativeImageBase::load()
+{
+ Q_D(QDeclarativeImageBase);
+
+ if (d->url.isEmpty()) {
+ d->pix.clear(this);
+ d->status = Null;
+ d->progress = 0.0;
+ pixmapChange();
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+ 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 =
+ QDeclarativeImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QDeclarativeImageBase::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+
+ } else {
+ requestFinished();
+ }
+ }
+}
+
+void QDeclarativeImageBase::requestFinished()
+{
+ Q_D(QDeclarativeImageBase);
+
+ QDeclarativeImageBase::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;
+
+ pixmapChange();
+
+ 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);
+
+ update();
+}
+
+void QDeclarativeImageBase::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QDeclarativeImageBase);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QDeclarativeImageBase::componentComplete()
+{
+ Q_D(QDeclarativeImageBase);
+ QDeclarativeItem::componentComplete();
+ if (d->url.isValid())
+ load();
+}
+
+void QDeclarativeImageBase::pixmapChange()
+{
+ Q_D(QDeclarativeImageBase);
+ setImplicitWidth(d->pix.width());
+ setImplicitHeight(d->pix.height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h
new file mode 100644
index 0000000000..1763bbacce
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.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 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 QDECLARATIVEIMAGEBASE_H
+#define QDECLARATIVEIMAGEBASE_H
+
+#include "qdeclarativeimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeImageBasePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeImageBase : public QDeclarativeImplicitSizeItem
+{
+ 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 REVISION 1)
+ Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged)
+ Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged REVISION 1)
+
+public:
+ QDeclarativeImageBase(QDeclarativeItem *parent=0);
+ ~QDeclarativeImageBase();
+ 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;
+ void resetSourceSize();
+
+ virtual void setMirror(bool mirror);
+ bool mirror() const;
+
+Q_SIGNALS:
+ void sourceChanged(const QUrl &);
+ void sourceSizeChanged();
+ void statusChanged(QDeclarativeImageBase::Status);
+ void progressChanged(qreal progress);
+ void asynchronousChanged();
+ Q_REVISION(1) void cacheChanged();
+ Q_REVISION(1) void mirrorChanged();
+
+protected:
+ virtual void load();
+ virtual void componentComplete();
+ virtual void pixmapChange();
+ QDeclarativeImageBase(QDeclarativeImageBasePrivate &dd, QDeclarativeItem *parent);
+
+private Q_SLOTS:
+ virtual void requestFinished();
+ void requestProgress(qint64,qint64);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeImageBase)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeImageBase)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEIMAGEBASE_H
diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h
new file mode 100644
index 0000000000..ab16e66fd6
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h
@@ -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 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 QDECLARATIVEIMAGEBASE_P_H
+#define QDECLARATIVEIMAGEBASE_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/qdeclarativeimplicitsizeitem_p_p.h"
+#include "private/qdeclarativepixmapcache_p.h"
+
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QDeclarativeImageBasePrivate : public QDeclarativeImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeImageBase)
+
+public:
+ QDeclarativeImageBasePrivate()
+ : status(QDeclarativeImageBase::Null),
+ progress(0.0),
+ explicitSourceSize(false),
+ async(false),
+ cache(true),
+ mirror(false)
+ {
+ QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
+ }
+
+ QDeclarativePixmap pix;
+ QDeclarativeImageBase::Status status;
+ QUrl url;
+ qreal progress;
+ QSize sourcesize;
+ bool explicitSourceSize : 1;
+ bool async : 1;
+ bool cache : 1;
+ bool mirror: 1;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem.cpp b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem.cpp
new file mode 100644
index 0000000000..31ac28f062
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeimplicitsizeitem_p.h"
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDeclarativeImplicitSizeItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QDeclarativeImplicitSizeItem);
+ emit q->implicitWidthChanged();
+}
+
+void QDeclarativeImplicitSizeItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QDeclarativeImplicitSizeItem);
+ emit q->implicitHeightChanged();
+}
+
+QDeclarativeImplicitSizeItem::QDeclarativeImplicitSizeItem(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativeImplicitSizeItemPrivate), parent)
+{
+}
+
+QDeclarativeImplicitSizeItem::QDeclarativeImplicitSizeItem(QDeclarativeImplicitSizeItemPrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativeItem(dd, parent)
+{
+}
+
+
+void QDeclarativeImplicitSizePaintedItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QDeclarativeImplicitSizePaintedItem);
+ emit q->implicitWidthChanged();
+}
+
+void QDeclarativeImplicitSizePaintedItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QDeclarativeImplicitSizePaintedItem);
+ emit q->implicitHeightChanged();
+}
+
+QDeclarativeImplicitSizePaintedItem::QDeclarativeImplicitSizePaintedItem(QDeclarativeItem *parent)
+ : QDeclarativePaintedItem(*(new QDeclarativeImplicitSizePaintedItemPrivate), parent)
+{
+}
+
+QDeclarativeImplicitSizePaintedItem::QDeclarativeImplicitSizePaintedItem(QDeclarativeImplicitSizePaintedItemPrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativePaintedItem(dd, parent)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p.h b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p.h
new file mode 100644
index 0000000000..1863d95fa7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p.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 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 QDECLARATIVEIMPLICITSIZEITEM_H
+#define QDECLARATIVEIMPLICITSIZEITEM_H
+
+#include "qdeclarativepainteditem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeImplicitSizeItemPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeImplicitSizeItem : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged REVISION 1)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged REVISION 1)
+
+public:
+ QDeclarativeImplicitSizeItem(QDeclarativeItem *parent = 0);
+
+protected:
+ QDeclarativeImplicitSizeItem(QDeclarativeImplicitSizeItemPrivate &dd, QDeclarativeItem *parent);
+
+Q_SIGNALS:
+ Q_REVISION(1) void implicitWidthChanged();
+ Q_REVISION(1) void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeImplicitSizeItem)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeImplicitSizeItem)
+};
+
+class QDeclarativeImplicitSizePaintedItemPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeImplicitSizePaintedItem : public QDeclarativePaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged REVISION 1)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged REVISION 1)
+
+public:
+ QDeclarativeImplicitSizePaintedItem(QDeclarativeItem *parent = 0);
+
+protected:
+ QDeclarativeImplicitSizePaintedItem(QDeclarativeImplicitSizePaintedItemPrivate &dd, QDeclarativeItem *parent);
+ virtual void drawContents(QPainter *, const QRect &) {};
+
+Q_SIGNALS:
+ Q_REVISION(1) void implicitWidthChanged();
+ Q_REVISION(1) void implicitHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeImplicitSizePaintedItem)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeImplicitSizePaintedItem)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEIMPLICITSIZEITEM_H
diff --git a/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p_p.h b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p_p.h
new file mode 100644
index 0000000000..0bb7163c62
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeimplicitsizeitem_p_p.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 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 QDECLARATIVEIMPLICITSIZEITEM_P_H
+#define QDECLARATIVEIMPLICITSIZEITEM_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/qdeclarativeitem_p.h"
+#include "private/qdeclarativepainteditem_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeImplicitSizeItemPrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeImplicitSizeItem)
+
+public:
+ QDeclarativeImplicitSizeItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+
+class QDeclarativeImplicitSizePaintedItemPrivate : public QDeclarativePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeImplicitSizePaintedItem)
+
+public:
+ QDeclarativeImplicitSizePaintedItemPrivate()
+ {
+ }
+
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEIMPLICITSIZEITEM_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp
new file mode 100644
index 0000000000..6602dda28b
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp
@@ -0,0 +1,3724 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeitem.h"
+
+#include "private/qdeclarativeevents_p_p.h"
+#include <private/qdeclarativeengine_p.h>
+#include <private/qgraphicsitem_p.h>
+#include <QtDeclarative/private/qdeclarativeitem_p.h>
+
+#include <qdeclarativeengine.h>
+#include <qdeclarativeopenmetaobject_p.h>
+#include <qdeclarativestate_p.h>
+#include <qdeclarativeview.h>
+#include <qdeclarativestategroup_p.h>
+#include <qdeclarativecomponent.h>
+#include <qdeclarativeinfo.h>
+
+#include <QDebug>
+#include <QPen>
+#include <QEvent>
+#include <QGraphicsSceneMouseEvent>
+#include <QtCore/qnumeric.h>
+#include <QtScript/qscriptengine.h>
+#include <QtGui/qgraphicstransform.h>
+#include <qlistmodelinterface_p.h>
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Transform QGraphicsTransform
+ \ingroup qml-transform-elements
+ \since 4.7
+ \brief The Transform elements provide a way of building advanced transformations on Items.
+
+ The Transform element is a base type which cannot be instantiated directly.
+ The following concrete Transform types are available:
+
+ \list
+ \o \l Rotation
+ \o \l Scale
+ \o \l Translate
+ \endlist
+
+ The Transform elements let you create and control advanced transformations that can be configured
+ independently using specialized properties.
+
+ You can assign any number of Transform elements to an \l Item. Each Transform is applied in order,
+ one at a time.
+*/
+
+/*!
+ \qmlclass Translate QDeclarativeTranslate
+ \ingroup qml-transform-elements
+ \since 4.7
+ \brief The Translate object provides a way to move an Item without changing its x or y properties.
+
+ The Translate object provides independent control over position in addition to the Item's x and y properties.
+
+ The following example moves the Y axis of the \l Rectangle elements while still allowing the \l Row element
+ to lay the items out as if they had not been transformed:
+ \qml
+ import QtQuick 1.0
+
+ Row {
+ Rectangle {
+ width: 100; height: 100
+ color: "blue"
+ transform: Translate { y: 20 }
+ }
+ Rectangle {
+ width: 100; height: 100
+ color: "red"
+ transform: Translate { y: -20 }
+ }
+ }
+ \endqml
+
+ \image translate.png
+*/
+
+/*!
+ \qmlproperty real Translate::x
+
+ The translation along the X axis.
+*/
+
+/*!
+ \qmlproperty real Translate::y
+
+ The translation along the Y axis.
+*/
+
+/*!
+ \qmlclass Scale QGraphicsScale
+ \ingroup qml-transform-elements
+ \since 4.7
+ \brief The Scale element provides a way to scale an Item.
+
+ The Scale element gives more control over scaling than using \l Item's \l{Item::scale}{scale} property. Specifically,
+ it allows a different scale for the x and y axes, and allows the scale to be relative to an
+ arbitrary point.
+
+ The following example scales the X axis of the Rectangle, relative to its interior point 25, 25:
+ \qml
+ Rectangle {
+ width: 100; height: 100
+ color: "blue"
+ transform: Scale { origin.x: 25; origin.y: 25; xScale: 3}
+ }
+ \endqml
+
+ \sa Rotation, Translate
+*/
+
+/*!
+ \qmlproperty real Scale::origin.x
+ \qmlproperty real Scale::origin.y
+
+ The point that the item is scaled from (i.e., the point that stays fixed relative to the parent as
+ the rest of the item grows). By default the origin is 0, 0.
+*/
+
+/*!
+ \qmlproperty real Scale::xScale
+
+ The scaling factor for the X axis.
+*/
+
+/*!
+ \qmlproperty real Scale::yScale
+
+ The scaling factor for the Y axis.
+*/
+
+/*!
+ \qmlclass Rotation QGraphicsRotation
+ \ingroup qml-transform-elements
+ \since 4.7
+ \brief The Rotation object provides a way to rotate an Item.
+
+ The Rotation object gives more control over rotation than using \l Item's \l{Item::rotation}{rotation} property.
+ Specifically, it allows (z axis) rotation to be relative to an arbitrary point.
+
+ The following example rotates a Rectangle around its interior point 25, 25:
+ \qml
+ Rectangle {
+ width: 100; height: 100
+ color: "blue"
+ transform: Rotation { origin.x: 25; origin.y: 25; angle: 45}
+ }
+ \endqml
+
+ Rotation also provides a way to specify 3D-like rotations for Items. For these types of
+ rotations you must specify the axis to rotate around in addition to the origin point.
+
+ The following example shows various 3D-like rotations applied to an \l Image.
+ \snippet doc/src/snippets/declarative/rotation.qml 0
+
+ \image axisrotation.png
+
+ \sa {declarative/ui-components/dialcontrol}{Dial Control example}, {declarative/toys/clocks}{Clocks example}
+*/
+
+/*!
+ \qmlproperty real Rotation::origin.x
+ \qmlproperty real Rotation::origin.y
+
+ The origin point of the rotation (i.e., the point that stays fixed relative to the parent as
+ the rest of the item rotates). By default the origin is 0, 0.
+*/
+
+/*!
+ \qmlproperty real Rotation::axis.x
+ \qmlproperty real Rotation::axis.y
+ \qmlproperty real Rotation::axis.z
+
+ The axis to rotate around. For simple (2D) rotation around a point, you do not need to specify an axis,
+ as the default axis is the z axis (\c{ axis { x: 0; y: 0; z: 1 } }).
+
+ For a typical 3D-like rotation you will usually specify both the origin and the axis.
+
+ \image 3d-rotation-axis.png
+*/
+
+/*!
+ \qmlproperty real Rotation::angle
+
+ The angle to rotate, in degrees clockwise.
+*/
+
+QDeclarativeContents::QDeclarativeContents(QDeclarativeItem *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)));
+}
+
+QDeclarativeContents::~QDeclarativeContents()
+{
+ QList<QGraphicsItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i));
+ if(!child)//### Should this be ignoring non-QDeclarativeItem graphicsobjects?
+ continue;
+ QDeclarativeItemPrivate::get(child)->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
+ }
+}
+
+QRectF QDeclarativeContents::rectF() const
+{
+ return QRectF(m_x, m_y, m_width, m_height);
+}
+
+void QDeclarativeContents::calcHeight(QDeclarativeItem *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<QGraphicsItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i));
+ if(!child)//### Should this be ignoring non-QDeclarativeItem graphicsobjects?
+ continue;
+ 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 QDeclarativeContents::calcWidth(QDeclarativeItem *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<QGraphicsItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i));
+ if(!child)//### Should this be ignoring non-QDeclarativeItem graphicsobjects?
+ continue;
+ 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 QDeclarativeContents::complete()
+{
+ QList<QGraphicsItem *> children = m_item->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i));
+ if(!child)//### Should this be ignoring non-QDeclarativeItem graphicsobjects?
+ continue;
+ QDeclarativeItemPrivate::get(child)->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
+ //###what about changes to visibility?
+ }
+
+ calcGeometry();
+}
+
+void QDeclarativeContents::itemGeometryChanged(QDeclarativeItem *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 QDeclarativeContents::itemDestroyed(QDeclarativeItem *item)
+{
+ if (item)
+ QDeclarativeItemPrivate::get(item)->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QDeclarativeContents::childRemoved(QDeclarativeItem *item)
+{
+ if (item)
+ QDeclarativeItemPrivate::get(item)->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
+ calcGeometry();
+}
+
+void QDeclarativeContents::childAdded(QDeclarativeItem *item)
+{
+ if (item)
+ QDeclarativeItemPrivate::get(item)->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Destroyed);
+ calcWidth(item);
+ calcHeight(item);
+}
+
+QDeclarativeItemKeyFilter::QDeclarativeItemKeyFilter(QDeclarativeItem *item)
+: m_processPost(false), m_next(0)
+{
+ QDeclarativeItemPrivate *p =
+ item?static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(item)):0;
+ if (p) {
+ m_next = p->keyHandler;
+ p->keyHandler = this;
+ }
+}
+
+QDeclarativeItemKeyFilter::~QDeclarativeItemKeyFilter()
+{
+}
+
+void QDeclarativeItemKeyFilter::keyPressed(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyPressed(event, post);
+}
+
+void QDeclarativeItemKeyFilter::keyReleased(QKeyEvent *event, bool post)
+{
+ if (m_next) m_next->keyReleased(event, post);
+}
+
+void QDeclarativeItemKeyFilter::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ if (m_next) m_next->inputMethodEvent(event, post);
+}
+
+QVariant QDeclarativeItemKeyFilter::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ if (m_next) return m_next->inputMethodQuery(query);
+ return QVariant();
+}
+
+void QDeclarativeItemKeyFilter::componentComplete()
+{
+ if (m_next) m_next->componentComplete();
+}
+
+
+/*!
+ \qmlclass KeyNavigation QDeclarativeKeyNavigationAttached
+ \ingroup qml-basic-interaction-elements
+ \since 4.7
+ \brief The KeyNavigation attached property supports key navigation by arrow keys.
+
+ Key-based user interfaces commonly allow the use of arrow keys to navigate between
+ focusable items. The KeyNavigation attached property enables this behavior by providing a
+ convenient way to specify the item that should gain focus when an arrow or tab key is pressed.
+
+ The following example provides key navigation for a 2x2 grid of items:
+
+ \snippet doc/src/snippets/declarative/keynavigation.qml 0
+
+ The top-left item initially receives focus by setting \l {Item::}{focus} to
+ \c true. When an arrow key is pressed, the focus will move to the
+ appropriate item, as defined by the value that has been set for
+ the KeyNavigation \l left, \l right, \l up or \l down properties.
+
+ Note that if a KeyNavigation attached property receives the key press and release
+ events for a requested arrow or tab key, the event is accepted and does not
+ propagate any further.
+
+ By default, KeyNavigation receives key events after the item to which it is attached.
+ If the item accepts the key event, the KeyNavigation attached property will not
+ receive an event for that key. Setting the \l priority property to
+ \c KeyNavigation.BeforeItem allows the event to be used for key navigation
+ before the item, rather than after.
+
+ If item to which the focus is switching is not enabled or visible, an attempt will
+ be made to skip this item and focus on the next. This is possible if there are
+ 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.
+
+ \sa {Keys}{Keys attached property}
+*/
+
+/*!
+ \qmlproperty Item KeyNavigation::left
+ \qmlproperty Item KeyNavigation::right
+ \qmlproperty Item KeyNavigation::up
+ \qmlproperty Item KeyNavigation::down
+ \qmlproperty Item KeyNavigation::tab
+ \qmlproperty Item KeyNavigation::backtab
+
+ These properties hold the item to assign focus to
+ when the left, right, up or down cursor keys, or the
+ tab key are pressed.
+*/
+
+/*!
+ \qmlproperty Item KeyNavigation::tab
+ \qmlproperty Item KeyNavigation::backtab
+
+ These properties hold the item to assign focus to
+ when the Tab key or Shift+Tab key combination (Backtab) are pressed.
+*/
+
+QDeclarativeKeyNavigationAttached::QDeclarativeKeyNavigationAttached(QObject *parent)
+: QObject(*(new QDeclarativeKeyNavigationAttachedPrivate), parent),
+ QDeclarativeItemKeyFilter(qobject_cast<QDeclarativeItem*>(parent))
+{
+ m_processPost = true;
+}
+
+QDeclarativeKeyNavigationAttached *
+QDeclarativeKeyNavigationAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QDeclarativeKeyNavigationAttached(obj);
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::left() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->left;
+}
+
+void QDeclarativeKeyNavigationAttached::setLeft(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->left == i)
+ return;
+ d->left = i;
+ emit leftChanged();
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::right() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->right;
+}
+
+void QDeclarativeKeyNavigationAttached::setRight(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->right == i)
+ return;
+ d->right = i;
+ emit rightChanged();
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::up() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->up;
+}
+
+void QDeclarativeKeyNavigationAttached::setUp(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->up == i)
+ return;
+ d->up = i;
+ emit upChanged();
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::down() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->down;
+}
+
+void QDeclarativeKeyNavigationAttached::setDown(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->down == i)
+ return;
+ d->down = i;
+ emit downChanged();
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::tab() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->tab;
+}
+
+void QDeclarativeKeyNavigationAttached::setTab(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->tab == i)
+ return;
+ d->tab = i;
+ emit tabChanged();
+}
+
+QDeclarativeItem *QDeclarativeKeyNavigationAttached::backtab() const
+{
+ Q_D(const QDeclarativeKeyNavigationAttached);
+ return d->backtab;
+}
+
+void QDeclarativeKeyNavigationAttached::setBacktab(QDeclarativeItem *i)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ if (d->backtab == i)
+ return;
+ d->backtab = i;
+ emit backtabChanged();
+}
+
+/*!
+ \qmlproperty enumeration KeyNavigation::priority
+
+ This property determines whether the keys are processed before
+ or after the attached item's own key handling.
+
+ \list
+ \o KeyNavigation.BeforeItem - process the key events before normal
+ item key processing. If the event is used for key navigation, it will be accepted and will not
+ be passed on to the item.
+ \o KeyNavigation.AfterItem (default) - process the key events after normal item key
+ handling. If the item accepts the key event it will not be
+ handled by the KeyNavigation attached property handler.
+ \endlist
+*/
+QDeclarativeKeyNavigationAttached::Priority QDeclarativeKeyNavigationAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QDeclarativeKeyNavigationAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QDeclarativeKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QDeclarativeItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left: {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QDeclarativeItem* leftItem = mirror ? d->right : d->left;
+ if (leftItem) {
+ setFocusNavigation(leftItem, mirror ? "right" : "left");
+ event->accept();
+ }
+ break;
+ }
+ case Qt::Key_Right: {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QDeclarativeItem* 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()) QDeclarativeItemKeyFilter::keyPressed(event, post);
+}
+
+void QDeclarativeKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QDeclarativeKeyNavigationAttached);
+ event->ignore();
+
+ if (post != m_processPost) {
+ QDeclarativeItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ bool mirror = false;
+ switch(event->key()) {
+ case Qt::Key_Left:
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->right : d->left)
+ event->accept();
+ break;
+ case Qt::Key_Right:
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::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()) QDeclarativeItemKeyFilter::keyReleased(event, post);
+}
+
+void QDeclarativeKeyNavigationAttached::setFocusNavigation(QDeclarativeItem *currentItem, const char *dir)
+{
+ QDeclarativeItem *initialItem = currentItem;
+ bool isNextItem = false;
+ do {
+ isNextItem = false;
+ if (currentItem->isVisible() && currentItem->isEnabled()) {
+ currentItem->setFocus(true);
+ } else {
+ QObject *attached =
+ qmlAttachedPropertiesObject<QDeclarativeKeyNavigationAttached>(currentItem, false);
+ if (attached) {
+ QDeclarativeItem *tempItem = qvariant_cast<QDeclarativeItem*>(attached->property(dir));
+ if (tempItem) {
+ currentItem = tempItem;
+ isNextItem = true;
+ }
+ }
+ }
+ }
+ while (currentItem != initialItem && isNextItem);
+}
+
+/*!
+ \qmlclass LayoutMirroring QDeclarativeLayoutMirroringAttached
+ \since QtQuick 1.1
+ \ingroup qml-utility-elements
+ \brief The LayoutMirroring attached property is used to mirror layout behavior.
+
+ The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors},
+ \l{Using QML Positioner and Repeater Items}{positioner} elements (such as \l Row and \l Grid)
+ and views (such as \l GridView and horizontal \l ListView). Mirroring is a visual change: left
+ anchors become right anchors, and positioner elements like \l Grid and \l Row reverse the
+ horizontal layout of child items.
+
+ Mirroring is enabled for an item by setting the \l enabled property to true. By default, this
+ only affects the item itself; setting the \l childrenInherit property to true propagates the mirroring
+ behavior to all child elements as well. If the \c LayoutMirroring attached property has not been defined
+ for an item, mirroring is not enabled.
+
+ The following example shows mirroring in action. The \l Row below is specified as being anchored
+ to the left of its parent. However, since mirroring has been enabled, the anchor is horizontally
+ reversed and it is now anchored to the right. Also, since items in a \l Row are positioned
+ from left to right by default, they are now positioned from right to left instead, as demonstrated
+ by the numbering and opacity of the items:
+
+ \snippet doc/src/snippets/declarative/layoutmirroring.qml 0
+
+ \image layoutmirroring.png
+
+ Layout mirroring is useful when it is necessary to support both left-to-right and right-to-left
+ layout versions of an application to target different language areas. The \l childrenInherit
+ property allows layout mirroring to be applied without manually setting layout configurations
+ for every item in an application. Keep in mind, however, that mirroring does not affect any
+ positioning that is defined by the \l Item \l {Item::}{x} coordinate value, so even with
+ mirroring enabled, it will often be necessary to apply some layout fixes to support the
+ desired layout direction. Also, it may be necessary to disable the mirroring of individual
+ child items (by setting \l {enabled}{LayoutMirroring.enabled} to false for such items) if
+ mirroring is not the desired behavior, or if the child item already implements mirroring in
+ some custom way.
+
+ See \l {QML Right-to-left User Interfaces} for further details on using \c LayoutMirroring and
+ other related features to implement right-to-left support for an application.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::enabled
+
+ This property holds whether the item's layout is mirrored horizontally. Setting this to true
+ horizontally reverses \l {anchor-layout}{anchor} settings such that left anchors become right,
+ and right anchors become left. For \l{Using QML Positioner and Repeater Items}{positioner} elements
+ (such as \l Row and \l Grid) and view elements (such as \l {GridView}{GridView} and \l {ListView}{ListView})
+ this also mirrors the horizontal layout direction of the item.
+
+ The default value is false.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::childrenInherit
+
+ This property holds whether the \l {enabled}{LayoutMirroring.enabled} value for this item
+ is inherited by its children.
+
+ The default value is false.
+*/
+
+QDeclarativeLayoutMirroringAttached::QDeclarativeLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
+{
+ if (QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent)) {
+ itemPrivate = QDeclarativeItemPrivate::get(item);
+ itemPrivate->attachedLayoutDirection = this;
+ } else
+ qmlInfo(parent) << tr("LayoutDirection attached property only works with Items");
+}
+
+QDeclarativeLayoutMirroringAttached * QDeclarativeLayoutMirroringAttached::qmlAttachedProperties(QObject *object)
+{
+ return new QDeclarativeLayoutMirroringAttached(object);
+}
+
+bool QDeclarativeLayoutMirroringAttached::enabled() const
+{
+ return itemPrivate ? itemPrivate->effectiveLayoutMirror : false;
+}
+
+void QDeclarativeLayoutMirroringAttached::setEnabled(bool enabled)
+{
+ if (!itemPrivate)
+ return;
+
+ itemPrivate->isMirrorImplicit = false;
+ if (enabled != itemPrivate->effectiveLayoutMirror) {
+ itemPrivate->setLayoutMirror(enabled);
+ if (itemPrivate->inheritMirrorFromItem)
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+void QDeclarativeLayoutMirroringAttached::resetEnabled()
+{
+ if (itemPrivate && !itemPrivate->isMirrorImplicit) {
+ itemPrivate->isMirrorImplicit = true;
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+bool QDeclarativeLayoutMirroringAttached::childrenInherit() const
+{
+ return itemPrivate ? itemPrivate->inheritMirrorFromItem : false;
+}
+
+void QDeclarativeLayoutMirroringAttached::setChildrenInherit(bool childrenInherit) {
+ if (itemPrivate && childrenInherit != itemPrivate->inheritMirrorFromItem) {
+ itemPrivate->inheritMirrorFromItem = childrenInherit;
+ itemPrivate->resolveLayoutMirror();
+ childrenInheritChanged();
+ }
+}
+
+void QDeclarativeItemPrivate::resolveLayoutMirror()
+{
+ Q_Q(QDeclarativeItem);
+ if (QDeclarativeItem *parentItem = q->parentItem()) {
+ QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parentItem);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ } else {
+ setImplicitLayoutMirror(isMirrorImplicit ? false : effectiveLayoutMirror, inheritMirrorFromItem);
+ }
+}
+
+void QDeclarativeItemPrivate::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 < children.count(); ++i) {
+ if (QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i))) {
+ QDeclarativeItemPrivate *childPrivate = QDeclarativeItemPrivate::get(child);
+ childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
+ }
+ }
+}
+
+void QDeclarativeItemPrivate::setLayoutMirror(bool mirror)
+{
+ if (mirror != effectiveLayoutMirror) {
+ effectiveLayoutMirror = mirror;
+ if (_anchors) {
+ _anchors->d_func()->fillChanged();
+ _anchors->d_func()->centerInChanged();
+ _anchors->d_func()->updateHorizontalAnchors();
+ emit _anchors->mirroredChanged();
+ }
+ mirrorChange();
+ if (attachedLayoutDirection) {
+ emit attachedLayoutDirection->enabledChanged();
+ }
+ }
+}
+
+/*!
+ \qmlclass Keys QDeclarativeKeysAttached
+ \ingroup qml-basic-interaction-elements
+ \since 4.7
+ \brief The Keys attached property provides key handling to Items.
+
+ All visual primitives support key handling via the Keys
+ attached property. Keys can be handled via the onPressed
+ and onReleased signal properties.
+
+ The signal properties have a \l KeyEvent parameter, named
+ \e event which contains details of the event. If a key is
+ handled \e event.accepted should be set to true to prevent the
+ event from propagating up the item hierarchy.
+
+ \section1 Example Usage
+
+ The following example shows how the general onPressed handler can
+ be used to test for a certain key; in this case, the left cursor
+ key:
+
+ \snippet doc/src/snippets/declarative/keys/keys-pressed.qml key item
+
+ Some keys may alternatively be handled via specific signal properties,
+ for example \e onSelectPressed. These handlers automatically set
+ \e event.accepted to true.
+
+ \snippet doc/src/snippets/declarative/keys/keys-handler.qml key item
+
+ See \l{Qt::Key}{Qt.Key} for the list of keyboard codes.
+
+ \section1 Key Handling Priorities
+
+ The Keys attached property can be configured to handle key events
+ before or after the item it is attached to. This makes it possible
+ to intercept events in order to override an item's default behavior,
+ or act as a fallback for keys not handled by the item.
+
+ If \l priority is Keys.BeforeItem (default) the order of key event processing is:
+
+ \list 1
+ \o Items specified in \c forwardTo
+ \o specific key handlers, e.g. onReturnPressed
+ \o onKeyPress, onKeyRelease handlers
+ \o Item specific key handling, e.g. TextInput key handling
+ \o parent item
+ \endlist
+
+ If priority is Keys.AfterItem the order of key event processing is:
+
+ \list 1
+ \o Item specific key handling, e.g. TextInput key handling
+ \o Items specified in \c forwardTo
+ \o specific key handlers, e.g. onReturnPressed
+ \o onKeyPress, onKeyRelease handlers
+ \o parent item
+ \endlist
+
+ If the event is accepted during any of the above steps, key
+ propagation stops.
+
+ \sa KeyEvent, {KeyNavigation}{KeyNavigation attached property}
+*/
+
+/*!
+ \qmlproperty bool Keys::enabled
+
+ This flags enables key handling if true (default); otherwise
+ no key handlers will be called.
+*/
+
+/*!
+ \qmlproperty enumeration Keys::priority
+
+ This property determines whether the keys are processed before
+ or after the attached item's own key handling.
+
+ \list
+ \o Keys.BeforeItem (default) - process the key events before normal
+ item key processing. If the event is accepted it will not
+ be passed on to the item.
+ \o Keys.AfterItem - process the key events after normal item key
+ handling. If the item accepts the key event it will not be
+ handled by the Keys attached property handler.
+ \endlist
+*/
+
+/*!
+ \qmlproperty list<Object> Keys::forwardTo
+
+ This property provides a way to forward key presses, key releases, and keyboard input
+ coming from input methods to other items. This can be useful when you want
+ one item to handle some keys (e.g. the up and down arrow keys), and another item to
+ handle other keys (e.g. the left and right arrow keys). Once an item that has been
+ forwarded keys accepts the event it is no longer forwarded to items later in the
+ list.
+
+ This example forwards key events to two lists:
+ \qml
+ Item {
+ ListView {
+ id: list1
+ // ...
+ }
+ ListView {
+ id: list2
+ // ...
+ }
+ Keys.forwardTo: [list1, list2]
+ focus: true
+ }
+ \endqml
+*/
+
+/*!
+ \qmlsignal Keys::onPressed(KeyEvent event)
+
+ This handler is called when a key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onReleased(KeyEvent event)
+
+ This handler is called when a key has been released. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit0Pressed(KeyEvent event)
+
+ This handler is called when the digit '0' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit1Pressed(KeyEvent event)
+
+ This handler is called when the digit '1' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit2Pressed(KeyEvent event)
+
+ This handler is called when the digit '2' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit3Pressed(KeyEvent event)
+
+ This handler is called when the digit '3' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit4Pressed(KeyEvent event)
+
+ This handler is called when the digit '4' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit5Pressed(KeyEvent event)
+
+ This handler is called when the digit '5' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit6Pressed(KeyEvent event)
+
+ This handler is called when the digit '6' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit7Pressed(KeyEvent event)
+
+ This handler is called when the digit '7' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit8Pressed(KeyEvent event)
+
+ This handler is called when the digit '8' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDigit9Pressed(KeyEvent event)
+
+ This handler is called when the digit '9' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onLeftPressed(KeyEvent event)
+
+ This handler is called when the Left arrow has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onRightPressed(KeyEvent event)
+
+ This handler is called when the Right arrow has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onUpPressed(KeyEvent event)
+
+ This handler is called when the Up arrow has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDownPressed(KeyEvent event)
+
+ This handler is called when the Down arrow has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onTabPressed(KeyEvent event)
+
+ This handler is called when the Tab key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onBacktabPressed(KeyEvent event)
+
+ This handler is called when the Shift+Tab key combination (Backtab) has
+ been pressed. The \a event parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onAsteriskPressed(KeyEvent event)
+
+ This handler is called when the Asterisk '*' has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onEscapePressed(KeyEvent event)
+
+ This handler is called when the Escape key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onReturnPressed(KeyEvent event)
+
+ This handler is called when the Return key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onEnterPressed(KeyEvent event)
+
+ This handler is called when the Enter key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onDeletePressed(KeyEvent event)
+
+ This handler is called when the Delete key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onSpacePressed(KeyEvent event)
+
+ This handler is called when the Space key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onBackPressed(KeyEvent event)
+
+ This handler is called when the Back key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onCancelPressed(KeyEvent event)
+
+ This handler is called when the Cancel key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onSelectPressed(KeyEvent event)
+
+ This handler is called when the Select key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onYesPressed(KeyEvent event)
+
+ This handler is called when the Yes key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onNoPressed(KeyEvent event)
+
+ This handler is called when the No key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onContext1Pressed(KeyEvent event)
+
+ This handler is called when the Context1 key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onContext2Pressed(KeyEvent event)
+
+ This handler is called when the Context2 key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onContext3Pressed(KeyEvent event)
+
+ This handler is called when the Context3 key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onContext4Pressed(KeyEvent event)
+
+ This handler is called when the Context4 key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onCallPressed(KeyEvent event)
+
+ This handler is called when the Call key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onHangupPressed(KeyEvent event)
+
+ This handler is called when the Hangup key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onFlipPressed(KeyEvent event)
+
+ This handler is called when the Flip key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onMenuPressed(KeyEvent event)
+
+ This handler is called when the Menu key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onVolumeUpPressed(KeyEvent event)
+
+ This handler is called when the VolumeUp key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+/*!
+ \qmlsignal Keys::onVolumeDownPressed(KeyEvent event)
+
+ This handler is called when the VolumeDown key has been pressed. The \a event
+ parameter provides information about the event.
+*/
+
+const QDeclarativeKeysAttached::SigMap QDeclarativeKeysAttached::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 QDeclarativeKeysAttachedPrivate::isConnected(const char *signalName)
+{
+ return isSignalConnected(signalIndex(signalName));
+}
+
+QDeclarativeKeysAttached::QDeclarativeKeysAttached(QObject *parent)
+: QObject(*(new QDeclarativeKeysAttachedPrivate), parent),
+ QDeclarativeItemKeyFilter(qobject_cast<QDeclarativeItem*>(parent))
+{
+ Q_D(QDeclarativeKeysAttached);
+ m_processPost = false;
+ d->item = qobject_cast<QDeclarativeItem*>(parent);
+}
+
+QDeclarativeKeysAttached::~QDeclarativeKeysAttached()
+{
+}
+
+QDeclarativeKeysAttached::Priority QDeclarativeKeysAttached::priority() const
+{
+ return m_processPost ? AfterItem : BeforeItem;
+}
+
+void QDeclarativeKeysAttached::setPriority(Priority order)
+{
+ bool processPost = order == AfterItem;
+ if (processPost != m_processPost) {
+ m_processPost = processPost;
+ emit priorityChanged();
+ }
+}
+
+void QDeclarativeKeysAttached::componentComplete()
+{
+ Q_D(QDeclarativeKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QGraphicsItem *targetItem = d->finalFocusProxy(d->targets.at(ii));
+ if (targetItem && (targetItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
+ d->item->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
+ break;
+ }
+ }
+ }
+}
+
+void QDeclarativeKeysAttached::keyPressed(QKeyEvent *event, bool post)
+{
+ Q_D(QDeclarativeKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inPress) {
+ event->ignore();
+ QDeclarativeItemKeyFilter::keyPressed(event, post);
+ return;
+ }
+
+ // first process forwards
+ if (d->item && d->item->scene()) {
+ d->inPress = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii));
+ if (i && i->isVisible()) {
+ d->item->scene()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inPress = false;
+ return;
+ }
+ }
+ }
+ d->inPress = false;
+ }
+
+ QDeclarativeKeyEvent ke(*event);
+ QByteArray keySignal = keyToSignal(event->key());
+ if (!keySignal.isEmpty()) {
+ keySignal += "(QDeclarativeKeyEvent*)";
+ if (d->isConnected(keySignal)) {
+ // If we specifically handle a key then default to accepted
+ ke.setAccepted(true);
+ int idx = QDeclarativeKeysAttached::staticMetaObject.indexOfSignal(keySignal);
+ metaObject()->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QDeclarativeKeyEvent*, &ke));
+ }
+ }
+ if (!ke.isAccepted())
+ emit pressed(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QDeclarativeItemKeyFilter::keyPressed(event, post);
+}
+
+void QDeclarativeKeysAttached::keyReleased(QKeyEvent *event, bool post)
+{
+ Q_D(QDeclarativeKeysAttached);
+ if (post != m_processPost || !d->enabled || d->inRelease) {
+ event->ignore();
+ QDeclarativeItemKeyFilter::keyReleased(event, post);
+ return;
+ }
+
+ if (d->item && d->item->scene()) {
+ d->inRelease = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii));
+ if (i && i->isVisible()) {
+ d->item->scene()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->inRelease = false;
+ return;
+ }
+ }
+ }
+ d->inRelease = false;
+ }
+
+ QDeclarativeKeyEvent ke(*event);
+ emit released(&ke);
+ event->setAccepted(ke.isAccepted());
+
+ if (!event->isAccepted()) QDeclarativeItemKeyFilter::keyReleased(event, post);
+}
+
+void QDeclarativeKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post)
+{
+ Q_D(QDeclarativeKeysAttached);
+ if (post == m_processPost && d->item && !d->inIM && d->item->scene()) {
+ d->inIM = true;
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii));
+ if (i && i->isVisible() && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
+ d->item->scene()->sendEvent(i, event);
+ if (event->isAccepted()) {
+ d->imeItem = i;
+ d->inIM = false;
+ return;
+ }
+ }
+ }
+ d->inIM = false;
+ }
+ if (!event->isAccepted()) QDeclarativeItemKeyFilter::inputMethodEvent(event, post);
+}
+
+class QDeclarativeItemAccessor : public QGraphicsItem
+{
+public:
+ QVariant doInputMethodQuery(Qt::InputMethodQuery query) const {
+ return QGraphicsItem::inputMethodQuery(query);
+ }
+};
+
+QVariant QDeclarativeKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QDeclarativeKeysAttached);
+ if (d->item) {
+ for (int ii = 0; ii < d->targets.count(); ++ii) {
+ QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii));
+ if (i && i->isVisible() && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod) && i == d->imeItem) { //### how robust is i == d->imeItem check?
+ QVariant v = static_cast<QDeclarativeItemAccessor *>(i)->doInputMethodQuery(query);
+ if (v.userType() == QVariant::RectF)
+ v = d->item->mapRectFromItem(i, v.toRectF()); //### cost?
+ return v;
+ }
+ }
+ }
+ return QDeclarativeItemKeyFilter::inputMethodQuery(query);
+}
+
+QDeclarativeKeysAttached *QDeclarativeKeysAttached::qmlAttachedProperties(QObject *obj)
+{
+ return new QDeclarativeKeysAttached(obj);
+}
+
+/*!
+ \class QDeclarativeItem
+ \since 4.7
+ \brief The QDeclarativeItem class provides the most basic of all visual items in QML.
+
+ All visual items in Qt Declarative inherit from QDeclarativeItem. Although QDeclarativeItem
+ has no visual appearance, it defines all the properties that are
+ common across visual items - such as the x and y position, the
+ width and height, \l {anchor-layout}{anchoring} and key handling.
+
+ You can subclass QDeclarativeItem to provide your own custom visual item that inherits
+ these features. Note that, because it does not draw anything, QDeclarativeItem sets the
+ QGraphicsItem::ItemHasNoContents flag. If you subclass QDeclarativeItem to create a visual
+ item, you will need to unset this flag.
+
+*/
+
+/*!
+ \qmlclass Item QDeclarativeItem
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The Item is the most basic of all visual items in QML.
+
+ All visual items in Qt Declarative inherit from Item. Although Item
+ has no visual appearance, it defines all the properties that are
+ common across visual items - such as the x and y position, the
+ width and height, \l {anchor-layout}{anchoring} and key handling.
+
+ Item is also useful for grouping items together.
+
+ \qml
+ Item {
+ Image {
+ source: "tile.png"
+ }
+ Image {
+ x: 80
+ width: 100
+ height: 100
+ source: "tile.png"
+ }
+ Image {
+ x: 190
+ width: 100
+ height: 100
+ fillMode: Image.Tile
+ source: "tile.png"
+ }
+ }
+ \endqml
+
+
+ \section1 Key Handling
+
+ Key handling is available to all Item-based visual elements via the \l {Keys}{Keys}
+ attached property. The \e Keys attached property provides basic handlers such
+ as \l {Keys::onPressed}{onPressed} and \l {Keys::onReleased}{onReleased},
+ as well as handlers for specific keys, such as
+ \l {Keys::onCancelPressed}{onCancelPressed}. The example below
+ assigns \l {qmlfocus}{focus} to the item and handles
+ the Left key via the general \e onPressed handler and the Select key via the
+ onSelectPressed handler:
+
+ \qml
+ Item {
+ focus: true
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Left) {
+ console.log("move left");
+ event.accepted = true;
+ }
+ }
+ Keys.onSelectPressed: console.log("Selected");
+ }
+ \endqml
+
+ See the \l {Keys}{Keys} attached property for detailed documentation.
+
+ \section1 Layout Mirroring
+
+ Item layouts can be mirrored using the \l {LayoutMirroring}{LayoutMirroring} attached property.
+
+*/
+
+/*!
+ \fn void QDeclarativeItem::childrenRectChanged(const QRectF &)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::baselineOffsetChanged(qreal)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::stateChanged(const QString &state)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::parentChanged(QDeclarativeItem *)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::smoothChanged(bool)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::clipChanged(bool)
+ \internal
+*/
+
+/*! \fn void QDeclarativeItem::transformOriginChanged(TransformOrigin)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::focusChanged(bool)
+ \internal
+*/
+
+/*!
+ \fn void QDeclarativeItem::activeFocusChanged(bool)
+ \internal
+*/
+
+// ### Must fix
+struct RegisterAnchorLineAtStartup {
+ RegisterAnchorLineAtStartup() {
+ qRegisterMetaType<QDeclarativeAnchorLine>("QDeclarativeAnchorLine");
+ }
+};
+static RegisterAnchorLineAtStartup registerAnchorLineAtStartup;
+
+
+/*!
+ \fn QDeclarativeItem::QDeclarativeItem(QDeclarativeItem *parent)
+
+ Constructs a QDeclarativeItem with the given \a parent.
+*/
+QDeclarativeItem::QDeclarativeItem(QDeclarativeItem* parent)
+ : QGraphicsObject(*(new QDeclarativeItemPrivate), parent, 0)
+{
+ Q_D(QDeclarativeItem);
+ d->init(parent);
+}
+
+/*! \internal
+*/
+QDeclarativeItem::QDeclarativeItem(QDeclarativeItemPrivate &dd, QDeclarativeItem *parent)
+ : QGraphicsObject(dd, parent, 0)
+{
+ Q_D(QDeclarativeItem);
+ d->init(parent);
+}
+
+/*!
+ Destroys the QDeclarativeItem.
+*/
+QDeclarativeItem::~QDeclarativeItem()
+{
+ Q_D(QDeclarativeItem);
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QDeclarativeAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor)
+ anchor->clearItem(this);
+ }
+ if (!d->parent || (parentItem() && !parentItem()->QGraphicsItem::d_ptr->inDestructor)) {
+ for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ QDeclarativeAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ if (anchor && anchor->item && anchor->item->parentItem() != this) //child will be deleted anyway
+ anchor->updateOnComplete();
+ }
+ }
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::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;
+}
+
+/*!
+ \qmlproperty enumeration Item::transformOrigin
+ This property holds the origin point around which scale and rotation transform.
+
+ Nine transform origins are available, as shown in the image below.
+
+ \image declarative-transformorigin.png
+
+ This example rotates an image around its bottom-right corner.
+ \qml
+ Image {
+ source: "myimage.png"
+ transformOrigin: Item.BottomRight
+ rotation: 45
+ }
+ \endqml
+
+ The default transform origin is \c Item.Center.
+
+ To set an arbitrary transform origin point use the \l Scale or \l Rotation
+ transform elements.
+*/
+
+/*!
+ \qmlproperty Item Item::parent
+ This property holds the parent of the item.
+*/
+
+/*!
+ \property QDeclarativeItem::parent
+ This property holds the parent of the item.
+*/
+void QDeclarativeItem::setParentItem(QDeclarativeItem *parent)
+{
+ QGraphicsObject::setParentItem(parent);
+}
+
+/*!
+ Returns the QDeclarativeItem parent of this item.
+*/
+QDeclarativeItem *QDeclarativeItem::parentItem() const
+{
+ return qobject_cast<QDeclarativeItem *>(QGraphicsObject::parentItem());
+}
+
+/*!
+ \qmlproperty real Item::childrenRect.x
+ \qmlproperty real Item::childrenRect.y
+ \qmlproperty real Item::childrenRect.width
+ \qmlproperty real Item::childrenRect.height
+
+ The childrenRect properties allow an item access to the geometry of its
+ children. This property is useful if you have an item that needs to be
+ sized to fit its children.
+*/
+
+
+/*!
+ \qmlproperty list<Item> Item::children
+ \qmlproperty list<Object> Item::resources
+
+ The children property contains the list of visual children of this item.
+ The resources property contains non-visual resources that you want to
+ reference by name.
+
+ Generally you can rely on Item's default property to handle all this for
+ you, but it can come in handy in some cases.
+
+ \qml
+ Item {
+ children: [
+ Text {},
+ Rectangle {}
+ ]
+ resources: [
+ Component {
+ id: myComponent
+ Text {}
+ }
+ ]
+ }
+ \endqml
+*/
+
+/*!
+ Returns true if construction of the QML component is complete; otherwise
+ returns false.
+
+ It is often desirable to delay some processing until the component is
+ completed.
+
+ \sa componentComplete()
+*/
+bool QDeclarativeItem::isComponentComplete() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->componentComplete;
+}
+
+void QDeclarativeItemPrivate::data_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ if (!o)
+ return;
+
+ QDeclarativeItem *that = static_cast<QDeclarativeItem *>(prop->object);
+
+ // This test is measurably (albeit only slightly) faster than qobject_cast<>()
+ const QMetaObject *mo = o->metaObject();
+ while (mo && mo != &QGraphicsObject::staticMetaObject) mo = mo->d.superdata;
+
+ if (mo) {
+ QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(o);
+ QDeclarativeItemPrivate *contentItemPrivate = static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(graphicsObject));
+ if (contentItemPrivate->componentComplete) {
+ graphicsObject->setParentItem(that);
+ } else {
+ contentItemPrivate->setParentItemHelper(that, /*newParentVariant=*/0, /*thisPointerVariant=*/0);
+ }
+ } else {
+ o->setParent(that);
+ }
+}
+
+static inline int children_count_helper(QDeclarativeListProperty<QObject> *prop)
+{
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object));
+ return d->children.count();
+}
+
+static inline QObject *children_at_helper(QDeclarativeListProperty<QObject> *prop, int index)
+{
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object));
+ if (index >= 0 && index < d->children.count())
+ return d->children.at(index)->toGraphicsObject();
+ else
+ return 0;
+}
+
+static inline void children_clear_helper(QDeclarativeListProperty<QObject> *prop)
+{
+ QDeclarativeItemPrivate *d = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(prop->object)));
+ int childCount = d->children.count();
+ if (d->componentComplete) {
+ for (int index = 0 ;index < childCount; index++)
+ d->children.at(0)->setParentItem(0);
+ } else {
+ for (int index = 0 ;index < childCount; index++)
+ QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(0, /*newParentVariant=*/0, /*thisPointerVariant=*/0);
+ }
+}
+
+int QDeclarativeItemPrivate::data_count(QDeclarativeListProperty<QObject> *prop)
+{
+ return resources_count(prop) + children_count_helper(prop);
+}
+
+QObject *QDeclarativeItemPrivate::data_at(QDeclarativeListProperty<QObject> *prop, int i)
+{
+ int resourcesCount = resources_count(prop);
+ if (i < resourcesCount)
+ return resources_at(prop, i);
+ const int j = i - resourcesCount;
+ if (j < children_count_helper(prop))
+ return children_at_helper(prop, j);
+ return 0;
+}
+
+void QDeclarativeItemPrivate::data_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ resources_clear(prop);
+ children_clear_helper(prop);
+}
+
+QObject *QDeclarativeItemPrivate::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 QDeclarativeItemPrivate::resources_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ o->setParent(prop->object);
+}
+
+int QDeclarativeItemPrivate::resources_count(QDeclarativeListProperty<QObject> *prop)
+{
+ return prop->object->children().count();
+}
+
+void QDeclarativeItemPrivate::resources_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ const QObjectList children = prop->object->children();
+ for (int index = 0; index < children.count(); index++)
+ children.at(index)->setParent(0);
+}
+
+int QDeclarativeItemPrivate::transform_count(QDeclarativeListProperty<QGraphicsTransform> *list)
+{
+ QGraphicsObject *object = qobject_cast<QGraphicsObject *>(list->object);
+ if (object) {
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
+ return d->transformData ? d->transformData->graphicsTransforms.size() : 0;
+ } else {
+ return 0;
+ }
+}
+
+void QDeclarativeItemPrivate::transform_append(QDeclarativeListProperty<QGraphicsTransform> *list, QGraphicsTransform *item)
+{
+ QGraphicsObject *object = qobject_cast<QGraphicsObject *>(list->object);
+ if (object && item) // QGraphicsItem applies the list in the wrong order, so we prepend.
+ QGraphicsItemPrivate::get(object)->prependGraphicsTransform(item);
+}
+
+QGraphicsTransform *QDeclarativeItemPrivate::transform_at(QDeclarativeListProperty<QGraphicsTransform> *list, int idx)
+{
+ QGraphicsObject *object = qobject_cast<QGraphicsObject *>(list->object);
+ if (object) {
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
+ if (!d->transformData)
+ return 0;
+ return d->transformData->graphicsTransforms.at(idx);
+ } else {
+ return 0;
+ }
+}
+
+void QDeclarativeItemPrivate::transform_clear(QDeclarativeListProperty<QGraphicsTransform> *list)
+{
+ QGraphicsObject *object = qobject_cast<QGraphicsObject *>(list->object);
+ if (object) {
+ QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(object);
+ if (!d->transformData)
+ return;
+ object->setTransformations(QList<QGraphicsTransform *>());
+ }
+}
+
+void QDeclarativeItemPrivate::parentProperty(QObject *o, void *rv, QDeclarativeNotifierEndpoint *e)
+{
+ QDeclarativeItem *item = static_cast<QDeclarativeItem*>(o);
+ if (e)
+ e->connect(&item->d_func()->parentNotifier);
+ *((QDeclarativeItem **)rv) = item->parentItem();
+}
+
+/*!
+ \qmlproperty list<Object> Item::data
+ \default
+
+ The data property allows you to freely mix visual children and resources
+ in an item. If you assign a visual item to the data list it becomes
+ a child and if you assign any other object type, it is added as a resource.
+
+ So you can write:
+ \qml
+ Item {
+ Text {}
+ Rectangle {}
+ Timer {}
+ }
+ \endqml
+
+ instead of:
+ \qml
+ Item {
+ children: [
+ Text {},
+ Rectangle {}
+ ]
+ resources: [
+ Timer {}
+ ]
+ }
+ \endqml
+
+ data is a behind-the-scenes property: you should never need to explicitly
+ specify it.
+ */
+
+QDeclarativeListProperty<QObject> QDeclarativeItemPrivate::data()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QDeclarativeItemPrivate::data_append,
+ QDeclarativeItemPrivate::data_count,
+ QDeclarativeItemPrivate::data_at,
+ QDeclarativeItemPrivate::data_clear
+ );
+}
+
+/*!
+ \property QDeclarativeItem::childrenRect
+ \brief The geometry of an item's children.
+
+ This property holds the (collective) position and size of the item's children.
+*/
+QRectF QDeclarativeItem::childrenRect()
+{
+ Q_D(QDeclarativeItem);
+ if (!d->_contents) {
+ d->_contents = new QDeclarativeContents(this);
+ if (d->componentComplete)
+ d->_contents->complete();
+ }
+ return d->_contents->rectF();
+}
+
+bool QDeclarativeItem::clip() const
+{
+ return flags() & ItemClipsChildrenToShape;
+}
+
+void QDeclarativeItem::setClip(bool c)
+{
+ if (clip() == c)
+ return;
+ setFlag(ItemClipsChildrenToShape, c);
+ emit clipChanged(c);
+}
+
+/*!
+ \qmlproperty real Item::x
+ \qmlproperty real Item::y
+ \qmlproperty real Item::width
+ \qmlproperty real Item::height
+
+ Defines the item's position and size relative to its parent.
+
+ \qml
+ Item { x: 100; y: 100; width: 100; height: 100 }
+ \endqml
+ */
+
+/*!
+ \qmlproperty real Item::z
+
+ Sets the stacking order of sibling items. By default the stacking order is 0.
+
+ Items with a higher stacking value are drawn on top of siblings with a
+ lower stacking order. Items with the same stacking value are drawn
+ bottom up in the order they appear. Items with a negative stacking
+ value are drawn under their parent's content.
+
+ The following example shows the various effects of stacking order.
+
+ \table
+ \row
+ \o \image declarative-item_stacking1.png
+ \o Same \c z - later children above earlier children:
+ \qml
+ Item {
+ Rectangle {
+ color: "red"
+ width: 100; height: 100
+ }
+ Rectangle {
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-item_stacking2.png
+ \o Higher \c z on top:
+ \qml
+ Item {
+ Rectangle {
+ z: 1
+ color: "red"
+ width: 100; height: 100
+ }
+ Rectangle {
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-item_stacking3.png
+ \o Same \c z - children above parents:
+ \qml
+ Item {
+ Rectangle {
+ color: "red"
+ width: 100; height: 100
+ Rectangle {
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-item_stacking4.png
+ \o Lower \c z below:
+ \qml
+ Item {
+ Rectangle {
+ color: "red"
+ width: 100; height: 100
+ Rectangle {
+ z: -1
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ }
+ \endqml
+ \endtable
+ */
+
+/*!
+ \qmlproperty bool Item::visible
+
+ This property holds whether the item is visible. By default this is true.
+
+ Setting this property directly affects the \c visible value of child
+ items. When set to \c false, the \c visible values of all child items also
+ become \c false. When set to \c true, the \c visible values of child items
+ are returned to \c true, unless they have explicitly been set to \c false.
+
+ (Because of this flow-on behavior, using the \c visible property may not
+ have the intended effect if a property binding should only respond to
+ explicit property changes. In such cases it may be better to use the
+ \l opacity property instead.)
+
+ Setting this property to \c false automatically causes \l focus to be set
+ to \c false, and this item will longer receive mouse and keyboard events.
+ (In contrast, setting the \l opacity to 0 does not affect the \l focus
+ property and the receiving of key events.)
+
+ \note This property's value is only affected by changes to this property or
+ the parent's \c visible property. It does not change, for example, if this
+ item moves off-screen, or if the \l opacity changes to 0.
+*/
+
+
+/*!
+ This function is called to handle this item's changes in
+ geometry from \a oldGeometry to \a newGeometry. If the two
+ geometries are the same, it doesn't do anything.
+ */
+void QDeclarativeItem::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeItem);
+
+ if (d->_anchors)
+ d->_anchors->d_func()->updateMe();
+
+ if (transformOrigin() != QDeclarativeItem::TopLeft
+ && (newGeometry.width() != oldGeometry.width() || newGeometry.height() != oldGeometry.height())) {
+ if (d->transformData) {
+ QPointF origin = d->computeTransformOrigin();
+ if (transformOriginPoint() != origin)
+ setTransformOriginPoint(origin);
+ } else {
+ d->transformOriginDirty = true;
+ }
+ }
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::Geometry)
+ change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
+ }
+
+ if (newGeometry.width() != oldGeometry.width())
+ emit widthChanged();
+ if (newGeometry.height() != oldGeometry.height())
+ emit heightChanged();
+}
+
+void QDeclarativeItemPrivate::removeItemChangeListener(QDeclarativeItemChangeListener *listener, ChangeTypes types)
+{
+ ChangeListener change(listener, types);
+ changeListeners.removeOne(change);
+}
+
+/*! \internal */
+void QDeclarativeItem::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ keyPressPreHandler(event);
+ if (event->isAccepted())
+ return;
+ if (d->keyHandler)
+ d->keyHandler->keyPressed(event, true);
+ else
+ event->ignore();
+}
+
+/*! \internal */
+void QDeclarativeItem::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ keyReleasePreHandler(event);
+ if (event->isAccepted())
+ return;
+ if (d->keyHandler)
+ d->keyHandler->keyReleased(event, true);
+ else
+ event->ignore();
+}
+
+/*! \internal */
+void QDeclarativeItem::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ inputMethodPreHandler(event);
+ if (event->isAccepted())
+ return;
+ if (d->keyHandler)
+ d->keyHandler->inputMethodEvent(event, true);
+ else
+ event->ignore();
+}
+
+/*! \internal */
+QVariant QDeclarativeItem::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+ Q_D(const QDeclarativeItem);
+ QVariant v;
+ if (d->keyHandler)
+ v = d->keyHandler->inputMethodQuery(query);
+
+ if (!v.isValid())
+ v = QGraphicsObject::inputMethodQuery(query);
+
+ return v;
+}
+
+/*!
+ \internal
+ */
+void QDeclarativeItem::keyPressPreHandler(QKeyEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ if (d->keyHandler && !d->doneEventPreHandler)
+ d->keyHandler->keyPressed(event, false);
+ else
+ event->ignore();
+ d->doneEventPreHandler = true;
+}
+
+/*!
+ \internal
+ */
+void QDeclarativeItem::keyReleasePreHandler(QKeyEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ if (d->keyHandler && !d->doneEventPreHandler)
+ d->keyHandler->keyReleased(event, false);
+ else
+ event->ignore();
+ d->doneEventPreHandler = true;
+}
+
+/*!
+ \internal
+ */
+void QDeclarativeItem::inputMethodPreHandler(QInputMethodEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ if (d->keyHandler && !d->doneEventPreHandler)
+ d->keyHandler->inputMethodEvent(event, false);
+ else
+ event->ignore();
+ d->doneEventPreHandler = true;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::left() const
+{
+ return anchorLines()->left;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::right() const
+{
+ return anchorLines()->right;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::horizontalCenter() const
+{
+ return anchorLines()->hCenter;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::top() const
+{
+ return anchorLines()->top;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::bottom() const
+{
+ return anchorLines()->bottom;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::verticalCenter() const
+{
+ return anchorLines()->vCenter;
+}
+
+
+/*!
+ \internal
+*/
+QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const
+{
+ return anchorLines()->baseline;
+}
+
+/*!
+ \qmlproperty AnchorLine Item::anchors.top
+ \qmlproperty AnchorLine Item::anchors.bottom
+ \qmlproperty AnchorLine Item::anchors.left
+ \qmlproperty AnchorLine Item::anchors.right
+ \qmlproperty AnchorLine Item::anchors.horizontalCenter
+ \qmlproperty AnchorLine Item::anchors.verticalCenter
+ \qmlproperty AnchorLine Item::anchors.baseline
+
+ \qmlproperty Item Item::anchors.fill
+ \qmlproperty Item Item::anchors.centerIn
+
+ \qmlproperty real Item::anchors.margins
+ \qmlproperty real Item::anchors.topMargin
+ \qmlproperty real Item::anchors.bottomMargin
+ \qmlproperty real Item::anchors.leftMargin
+ \qmlproperty real Item::anchors.rightMargin
+ \qmlproperty real Item::anchors.horizontalCenterOffset
+ \qmlproperty real Item::anchors.verticalCenterOffset
+ \qmlproperty real Item::anchors.baselineOffset
+
+ \qmlproperty bool Item::anchors.mirrored
+
+ Anchors provide a way to position an item by specifying its
+ relationship with other items.
+
+ Margins apply to top, bottom, left, right, and fill anchors.
+ The \c anchors.margins property can be used to set all of the various margins at once, to the same value.
+ Note that margins are anchor-specific and are not applied if an item does not
+ use anchors.
+
+ Offsets apply for horizontal center, vertical center, and baseline anchors.
+
+ \table
+ \row
+ \o \image declarative-anchors_example.png
+ \o Text anchored to Image, horizontally centered and vertically below, with a margin.
+ \qml
+ Item {
+ Image {
+ id: pic
+ // ...
+ }
+ Text {
+ id: label
+ anchors.horizontalCenter: pic.horizontalCenter
+ anchors.top: pic.bottom
+ anchors.topMargin: 5
+ // ...
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-anchors_example2.png
+ \o
+ Left of Text anchored to right of Image, with a margin. The y
+ property of both defaults to 0.
+
+ \qml
+ Item {
+ Image {
+ id: pic
+ // ...
+ }
+ Text {
+ id: label
+ anchors.left: pic.right
+ anchors.leftMargin: 5
+ // ...
+ }
+ }
+ \endqml
+ \endtable
+
+ \c anchors.fill provides a convenient way for one item to have the
+ same geometry as another item, and is equivalent to connecting all
+ four directional anchors.
+
+ To clear an anchor value, set it to \c undefined.
+
+ \c anchors.mirrored returns true it the layout has been \l {LayoutMirroring}{mirrored}.
+
+ \note You can only anchor an item to siblings or a parent.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QDeclarativeItem::baselineOffset
+ \brief The position of the item's baseline in local coordinates.
+
+ The baseline of a \l Text item is the imaginary line on which the text
+ sits. Controls containing text usually set their baseline to the
+ baseline of their text.
+
+ For non-text items, a default baseline offset of 0 is used.
+*/
+qreal QDeclarativeItem::baselineOffset() const
+{
+ Q_D(const QDeclarativeItem);
+ if (!d->baselineOffset.isValid()) {
+ return 0.0;
+ } else
+ return d->baselineOffset;
+}
+
+void QDeclarativeItem::setBaselineOffset(qreal offset)
+{
+ Q_D(QDeclarativeItem);
+ if (offset == d->baselineOffset)
+ return;
+
+ d->baselineOffset = offset;
+
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::Geometry) {
+ QDeclarativeAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->updateVerticalAnchors();
+ }
+ }
+ emit baselineOffsetChanged(offset);
+}
+
+/*!
+ \qmlproperty real Item::rotation
+ This property holds the rotation of the item in degrees clockwise.
+
+ This specifies how many degrees to rotate the item around its transformOrigin.
+ The default rotation is 0 degrees (i.e. not rotated at all).
+
+ \table
+ \row
+ \o \image declarative-rotation.png
+ \o
+ \qml
+ Rectangle {
+ color: "blue"
+ width: 100; height: 100
+ Rectangle {
+ color: "red"
+ x: 25; y: 25; width: 50; height: 50
+ rotation: 30
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa transform, Rotation
+*/
+
+/*!
+ \qmlproperty real Item::scale
+ This property holds the scale of the item.
+
+ A scale of less than 1 means the item will be displayed smaller than
+ normal, and a scale of greater than 1 means the item will be
+ displayed larger than normal. A negative scale means the item will
+ be mirrored.
+
+ By default, items are displayed at a scale of 1 (i.e. at their
+ normal size).
+
+ Scaling is from the item's transformOrigin.
+
+ \table
+ \row
+ \o \image declarative-scale.png
+ \o
+ \qml
+ Rectangle {
+ color: "blue"
+ width: 100; height: 100
+ Rectangle {
+ color: "green"
+ width: 25; height: 25
+ }
+ Rectangle {
+ color: "red"
+ x: 25; y: 25; width: 50; height: 50
+ scale: 1.4
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa transform, Scale
+*/
+
+/*!
+ \qmlproperty real Item::opacity
+
+ This property holds the opacity of the item. Opacity is specified as a
+ number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
+
+ When this property is set, the specified opacity is also applied
+ individually to child items. In almost all cases this is what you want,
+ but in some cases it may produce undesired results. For example in the
+ second set of rectangles below, the red rectangle has specified an opacity
+ of 0.5, which affects the opacity of its blue child rectangle even though
+ the child has not specified an opacity.
+
+ \table
+ \row
+ \o \image declarative-item_opacity1.png
+ \o
+ \qml
+ Item {
+ Rectangle {
+ color: "red"
+ width: 100; height: 100
+ Rectangle {
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-item_opacity2.png
+ \o
+ \qml
+ Item {
+ Rectangle {
+ opacity: 0.5
+ color: "red"
+ width: 100; height: 100
+ Rectangle {
+ color: "blue"
+ x: 50; y: 50; width: 100; height: 100
+ }
+ }
+ }
+ \endqml
+ \endtable
+
+ If an item's opacity is set to 0, the item will no longer receive mouse
+ events, but will continue to receive key events and will retain the keyboard
+ \l focus if it has been set. (In contrast, setting the \l visible property
+ to \c false stops both mouse and keyboard events, and also removes focus
+ from the item.)
+*/
+
+/*!
+ Returns a value indicating whether mouse input should
+ remain with this item exclusively.
+
+ \sa setKeepMouseGrab()
+ */
+bool QDeclarativeItem::keepMouseGrab() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->keepMouse;
+}
+
+/*!
+ The flag indicating whether the mouse should remain
+ with this item is set to \a keep.
+
+ This is useful for items that wish to grab and keep mouse
+ interaction following a predefined gesture. For example,
+ an item that is interested in horizontal mouse movement
+ may set keepMouseGrab to true once a threshold has been
+ exceeded. Once keepMouseGrab has been set to true, filtering
+ items will not react to mouse events.
+
+ If the item does not indicate that it wishes to retain mouse grab,
+ a filtering item may steal the grab. For example, Flickable may attempt
+ to steal a mouse grab if it detects that the user has begun to
+ move the viewport.
+
+ \sa keepMouseGrab()
+ */
+void QDeclarativeItem::setKeepMouseGrab(bool keep)
+{
+ Q_D(QDeclarativeItem);
+ d->keepMouse = keep;
+}
+
+/*!
+ \qmlmethod object Item::mapFromItem(Item item, real x, real y)
+
+ Maps the point (\a x, \a y), which is in \a item's coordinate system, to
+ this item's coordinate system, and returns an object with \c x and \c y
+ properties matching the mapped cooordinate.
+
+ If \a item is a \c null value, this maps the point from the coordinate
+ system of the root QML view.
+*/
+QScriptValue QDeclarativeItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QDeclarativeItem *itemObj = qobject_cast<QDeclarativeItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QGraphicsItem::mapFromItem() is called with 0, behaves the same as mapFromScene()
+ QPointF p = qobject_cast<QGraphicsItem*>(this)->mapFromItem(itemObj, x, y);
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+/*!
+ \qmlmethod object Item::mapToItem(Item item, real x, real y)
+
+ Maps the point (\a x, \a y), which is in this item's coordinate system, to
+ \a item's coordinate system, and returns an object with \c x and \c y
+ properties matching the mapped cooordinate.
+
+ If \a item is a \c null value, this maps \a x and \a y to the coordinate
+ system of the root QML view.
+*/
+QScriptValue QDeclarativeItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const
+{
+ QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
+ QDeclarativeItem *itemObj = qobject_cast<QDeclarativeItem*>(item.toQObject());
+ if (!itemObj && !item.isNull()) {
+ qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
+ return 0;
+ }
+
+ // If QGraphicsItem::mapToItem() is called with 0, behaves the same as mapToScene()
+ QPointF p = qobject_cast<QGraphicsItem*>(this)->mapToItem(itemObj, x, y);
+ sv.setProperty(QLatin1String("x"), p.x());
+ sv.setProperty(QLatin1String("y"), p.y());
+ return sv;
+}
+
+/*!
+ \qmlmethod Item::forceActiveFocus()
+
+ Force active focus on the item.
+ This method sets focus on the item and makes sure that all the focus scopes higher in the object hierarchy are also given focus.
+*/
+void QDeclarativeItem::forceActiveFocus()
+{
+ setFocus(true);
+ QGraphicsItem *parent = parentItem();
+ while (parent) {
+ if (parent->flags() & QGraphicsItem::ItemIsFocusScope)
+ parent->setFocus(Qt::OtherFocusReason);
+ parent = parent->parentItem();
+ }
+}
+
+
+/*!
+ \qmlmethod Item::childAt(real x, real y)
+
+ Returns the visible child item at point (\a x, \a y), which is in this
+ item's coordinate system, or \c null if there is no such item.
+ */
+QDeclarativeItem *QDeclarativeItem::childAt(qreal x, qreal y) const
+{
+ const QList<QGraphicsItem *> children = childItems();
+ for (int i = children.count()-1; i >= 0; --i) {
+ if (QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(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;
+}
+
+void QDeclarativeItemPrivate::focusChanged(bool flag)
+{
+ Q_Q(QDeclarativeItem);
+ if (!(flags & QGraphicsItem::ItemIsFocusScope) && parent)
+ emit q->activeFocusChanged(flag); //see also QDeclarativeItemPrivate::subFocusItemChange()
+ emit q->focusChanged(flag);
+}
+
+QDeclarativeListProperty<QObject> QDeclarativeItemPrivate::resources()
+{
+ return QDeclarativeListProperty<QObject>(q_func(), 0, QDeclarativeItemPrivate::resources_append,
+ QDeclarativeItemPrivate::resources_count,
+ QDeclarativeItemPrivate::resources_at,
+ QDeclarativeItemPrivate::resources_clear
+ );
+}
+
+/*!
+ \qmlproperty list<State> Item::states
+ This property holds a list of states defined by the item.
+
+ \qml
+ Item {
+ states: [
+ State {
+ // ...
+ },
+ State {
+ // ...
+ }
+ // ...
+ ]
+ }
+ \endqml
+
+ \sa {qmlstate}{States}
+*/
+
+QDeclarativeListProperty<QDeclarativeState> QDeclarativeItemPrivate::states()
+{
+ return _states()->statesProperty();
+}
+
+/*!
+ \qmlproperty list<Transition> Item::transitions
+ This property holds a list of transitions defined by the item.
+
+ \qml
+ Item {
+ transitions: [
+ Transition {
+ // ...
+ },
+ Transition {
+ // ...
+ }
+ // ...
+ ]
+ }
+ \endqml
+
+ \sa {QML Animation and Transitions}{Transitions}
+*/
+
+
+QDeclarativeListProperty<QDeclarativeTransition> QDeclarativeItemPrivate::transitions()
+{
+ return _states()->transitionsProperty();
+}
+
+/*
+ \qmlproperty list<Filter> Item::filter
+ This property holds a list of graphical filters to be applied to the item.
+
+ \l {Filter}{Filters} include things like \l {Blur}{blurring}
+ the item, or giving it a \l Reflection. Some
+ filters may not be available on all canvases; if a filter is not
+ available on a certain canvas, it will simply not be applied for
+ that canvas (but the QML will still be considered valid).
+
+ \qml
+ Item {
+ filter: [
+ Blur {
+ // ...
+ },
+ Reflection {
+ // ...
+ }
+ // ...
+ ]
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool Item::clip
+ This property holds whether clipping is enabled. The default clip value is \c false.
+
+ If clipping is enabled, an item will clip its own painting, as well
+ as the painting of its children, to its bounding rectangle.
+
+ Non-rectangular clipping regions are not supported for performance reasons.
+*/
+
+/*!
+ \property QDeclarativeItem::clip
+ This property holds whether clipping is enabled. The default clip value is \c false.
+
+ If clipping is enabled, an item will clip its own painting, as well
+ as the painting of its children, to its bounding rectangle. If you set
+ clipping during an item's paint operation, remember to re-set it to
+ prevent clipping the rest of your scene.
+
+ Non-rectangular clipping regions are not supported for performance reasons.
+*/
+
+/*!
+ \qmlproperty string Item::state
+
+ This property holds the name of the current state of the item.
+
+ This property is often used in scripts to change between states. For
+ example:
+
+ \js
+ function toggle() {
+ if (button.state == 'On')
+ button.state = 'Off';
+ else
+ button.state = 'On';
+ }
+ \endjs
+
+ If the item is in its base state (i.e. no explicit state has been
+ set), \c state will be a blank string. Likewise, you can return an
+ item to its base state by setting its current state to \c ''.
+
+ \sa {qmlstates}{States}
+*/
+
+QString QDeclarativeItemPrivate::state() const
+{
+ if (!_stateGroup)
+ return QString();
+ else
+ return _stateGroup->state();
+}
+
+void QDeclarativeItemPrivate::setState(const QString &state)
+{
+ _states()->setState(state);
+}
+
+/*!
+ \qmlproperty list<Transform> Item::transform
+ This property holds the list of transformations to apply.
+
+ For more information see \l Transform.
+*/
+
+/*! \internal */
+QDeclarativeListProperty<QGraphicsTransform> QDeclarativeItem::transform()
+{
+ Q_D(QDeclarativeItem);
+ return QDeclarativeListProperty<QGraphicsTransform>(this, 0, d->transform_append, d->transform_count,
+ d->transform_at, d->transform_clear);
+}
+
+/*!
+ \internal
+
+ classBegin() is called when the item is constructed, but its
+ properties have not yet been set.
+
+ \sa componentComplete(), isComponentComplete()
+*/
+void QDeclarativeItem::classBegin()
+{
+ Q_D(QDeclarativeItem);
+ d->componentComplete = false;
+ if (d->_stateGroup)
+ d->_stateGroup->classBegin();
+ if (d->_anchors)
+ d->_anchors->classBegin();
+}
+
+/*!
+ \internal
+
+ componentComplete() is called when all items in the component
+ have been constructed. It is often desirable to delay some
+ processing until the component is complete an all bindings in the
+ component have been resolved.
+*/
+void QDeclarativeItem::componentComplete()
+{
+ Q_D(QDeclarativeItem);
+ d->componentComplete = true;
+ if (d->_stateGroup)
+ d->_stateGroup->componentComplete();
+ if (d->_anchors) {
+ d->_anchors->componentComplete();
+ d->_anchors->d_func()->updateOnComplete();
+ }
+ if (d->keyHandler)
+ d->keyHandler->componentComplete();
+ if (d->_contents)
+ d->_contents->complete();
+}
+
+QDeclarativeStateGroup *QDeclarativeItemPrivate::_states()
+{
+ Q_Q(QDeclarativeItem);
+ if (!_stateGroup) {
+ _stateGroup = new QDeclarativeStateGroup;
+ if (!componentComplete)
+ _stateGroup->classBegin();
+ QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)),
+ q, SIGNAL(stateChanged(QString)));
+ }
+
+ return _stateGroup;
+}
+
+QDeclarativeItemPrivate::AnchorLines::AnchorLines(QGraphicsObject *q)
+{
+ left.item = q;
+ left.anchorLine = QDeclarativeAnchorLine::Left;
+ right.item = q;
+ right.anchorLine = QDeclarativeAnchorLine::Right;
+ hCenter.item = q;
+ hCenter.anchorLine = QDeclarativeAnchorLine::HCenter;
+ top.item = q;
+ top.anchorLine = QDeclarativeAnchorLine::Top;
+ bottom.item = q;
+ bottom.anchorLine = QDeclarativeAnchorLine::Bottom;
+ vCenter.item = q;
+ vCenter.anchorLine = QDeclarativeAnchorLine::VCenter;
+ baseline.item = q;
+ baseline.anchorLine = QDeclarativeAnchorLine::Baseline;
+}
+
+QPointF QDeclarativeItemPrivate::computeTransformOrigin() const
+{
+ Q_Q(const QDeclarativeItem);
+
+ QRectF br = q->boundingRect();
+
+ switch(origin) {
+ default:
+ case QDeclarativeItem::TopLeft:
+ return QPointF(0, 0);
+ case QDeclarativeItem::Top:
+ return QPointF(br.width() / 2., 0);
+ case QDeclarativeItem::TopRight:
+ return QPointF(br.width(), 0);
+ case QDeclarativeItem::Left:
+ return QPointF(0, br.height() / 2.);
+ case QDeclarativeItem::Center:
+ return QPointF(br.width() / 2., br.height() / 2.);
+ case QDeclarativeItem::Right:
+ return QPointF(br.width(), br.height() / 2.);
+ case QDeclarativeItem::BottomLeft:
+ return QPointF(0, br.height());
+ case QDeclarativeItem::Bottom:
+ return QPointF(br.width() / 2., br.height());
+ case QDeclarativeItem::BottomRight:
+ return QPointF(br.width(), br.height());
+ }
+}
+
+/*! \internal */
+bool QDeclarativeItem::sceneEvent(QEvent *event)
+{
+ Q_D(QDeclarativeItem);
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *k = static_cast<QKeyEvent *>(event);
+ if ((k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) &&
+ !(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {
+ keyPressEvent(static_cast<QKeyEvent *>(event));
+ if (!event->isAccepted())
+ return QGraphicsItem::sceneEvent(event);
+ else
+ return true;
+ } else {
+ return QGraphicsItem::sceneEvent(event);
+ }
+ } else {
+ bool rv = QGraphicsItem::sceneEvent(event);
+
+ if (event->type() == QEvent::FocusIn ||
+ event->type() == QEvent::FocusOut) {
+ d->focusChanged(hasActiveFocus());
+ }
+ return rv;
+ }
+}
+
+/*!
+ \internal
+
+ Note that unlike QGraphicsItems, QDeclarativeItem::itemChange() is \e not called
+ during initial widget polishing. Items wishing to optimize start-up construction
+ should instead consider using componentComplete().
+*/
+QVariant QDeclarativeItem::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ Q_D(QDeclarativeItem);
+ switch (change) {
+ case ItemParentHasChanged:
+ d->resolveLayoutMirror();
+ emit parentChanged(parentItem());
+ d->parentNotifier.notify();
+ break;
+ case ItemVisibleHasChanged: {
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::Visibility) {
+ change.listener->itemVisibilityChanged(this);
+ }
+ }
+ }
+ break;
+ case ItemOpacityHasChanged: {
+ for(int ii = 0; ii < d->changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::Opacity) {
+ change.listener->itemOpacityChanged(this);
+ }
+ }
+ }
+ break;
+ case ItemChildAddedChange:
+ if (d->_contents && d->componentComplete)
+ d->_contents->childAdded(qobject_cast<QDeclarativeItem*>(
+ value.value<QGraphicsItem*>()));
+ break;
+ case ItemChildRemovedChange:
+ if (d->_contents && d->componentComplete)
+ d->_contents->childRemoved(qobject_cast<QDeclarativeItem*>(
+ value.value<QGraphicsItem*>()));
+ break;
+ default:
+ break;
+ }
+
+ return QGraphicsItem::itemChange(change, value);
+}
+
+/*! \internal */
+QRectF QDeclarativeItem::boundingRect() const
+{
+ Q_D(const QDeclarativeItem);
+ return QRectF(0, 0, d->mWidth, d->mHeight);
+}
+
+/*!
+ \enum QDeclarativeItem::TransformOrigin
+
+ Controls the point about which simple transforms like scale apply.
+
+ \value TopLeft The top-left corner of the item.
+ \value Top The center point of the top of the item.
+ \value TopRight The top-right corner of the item.
+ \value Left The left most point of the vertical middle.
+ \value Center The center of the item.
+ \value Right The right most point of the vertical middle.
+ \value BottomLeft The bottom-left corner of the item.
+ \value Bottom The center point of the bottom of the item.
+ \value BottomRight The bottom-right corner of the item.
+*/
+
+/*!
+ Returns the current transform origin.
+*/
+QDeclarativeItem::TransformOrigin QDeclarativeItem::transformOrigin() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->origin;
+}
+
+/*!
+ Set the transform \a origin.
+*/
+void QDeclarativeItem::setTransformOrigin(TransformOrigin origin)
+{
+ Q_D(QDeclarativeItem);
+ if (origin != d->origin) {
+ d->origin = origin;
+ if (d->transformData)
+ QGraphicsItem::setTransformOriginPoint(d->computeTransformOrigin());
+ else
+ d->transformOriginDirty = true;
+ emit transformOriginChanged(d->origin);
+ }
+}
+
+void QDeclarativeItemPrivate::transformChanged()
+{
+ Q_Q(QDeclarativeItem);
+ if (transformOriginDirty) {
+ q->QGraphicsItem::setTransformOriginPoint(computeTransformOrigin());
+ transformOriginDirty = false;
+ }
+}
+
+/*!
+ \property QDeclarativeItem::smooth
+ \brief whether the item is smoothly transformed.
+
+ This property is provided purely for the purpose of optimization. Turning
+ smooth transforms off is faster, but looks worse; turning smooth
+ transformations on is slower, but looks better.
+
+ By default smooth transformations are off.
+*/
+
+/*!
+ Returns true if the item should be drawn with antialiasing and
+ smooth pixmap filtering, false otherwise.
+
+ The default is false.
+
+ \sa setSmooth()
+*/
+bool QDeclarativeItem::smooth() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->smooth;
+}
+
+/*!
+ Sets whether the item should be drawn with antialiasing and
+ smooth pixmap filtering to \a smooth.
+
+ \sa smooth()
+*/
+void QDeclarativeItem::setSmooth(bool smooth)
+{
+ Q_D(QDeclarativeItem);
+ if (d->smooth == smooth)
+ return;
+ d->smooth = smooth;
+ emit smoothChanged(smooth);
+ update();
+}
+
+/*!
+ \property QDeclarativeItem::anchors
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::left
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::right
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::horizontalCenter
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::top
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::bottom
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::verticalCenter
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::focus
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::transform
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::transformOrigin
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::activeFocus
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::baseline
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::data
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::resources
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::state
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::states
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::transformOriginPoint
+ \internal
+*/
+
+/*!
+ \property QDeclarativeItem::transitions
+ \internal
+*/
+
+/*!
+ \internal
+ Return the width of the item
+*/
+qreal QDeclarativeItem::width() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->width();
+}
+
+/*!
+ \internal
+ Set the width of the item
+*/
+void QDeclarativeItem::setWidth(qreal w)
+{
+ Q_D(QDeclarativeItem);
+ d->setWidth(w);
+}
+
+/*!
+ \internal
+ Reset the width of the item
+*/
+void QDeclarativeItem::resetWidth()
+{
+ Q_D(QDeclarativeItem);
+ d->resetWidth();
+}
+
+/*!
+ \internal
+ Return the width of the item
+*/
+qreal QDeclarativeItemPrivate::width() const
+{
+ return mWidth;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeItemPrivate::setWidth(qreal w)
+{
+ Q_Q(QDeclarativeItem);
+ if (qIsNaN(w))
+ return;
+
+ widthValid = true;
+ if (mWidth == w)
+ return;
+
+ qreal oldWidth = mWidth;
+
+ q->prepareGeometryChange();
+ mWidth = w;
+
+ q->geometryChanged(QRectF(q->x(), q->y(), width(), height()),
+ QRectF(q->x(), q->y(), oldWidth, height()));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeItemPrivate::resetWidth()
+{
+ Q_Q(QDeclarativeItem);
+ widthValid = false;
+ q->setImplicitWidth(q->implicitWidth());
+}
+
+void QDeclarativeItemPrivate::implicitWidthChanged()
+{
+ Q_Q(QDeclarativeItem);
+ emit q->implicitWidthChanged();
+}
+
+qreal QDeclarativeItemPrivate::implicitWidth() const
+{
+ return mImplicitWidth;
+}
+
+/*!
+ Returns the width of the item that is implied by other properties that determine the content.
+*/
+qreal QDeclarativeItem::implicitWidth() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->implicitWidth();
+}
+
+/*!
+ Sets the implied width of the item to \a w.
+ This is the width implied by other properties that determine the content.
+*/
+void QDeclarativeItem::setImplicitWidth(qreal w)
+{
+ Q_D(QDeclarativeItem);
+ bool changed = w != d->mImplicitWidth;
+ d->mImplicitWidth = w;
+ if (d->mWidth == w || widthValid()) {
+ if (changed)
+ d->implicitWidthChanged();
+ return;
+ }
+
+ qreal oldWidth = d->mWidth;
+
+ prepareGeometryChange();
+ d->mWidth = w;
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, height()));
+
+ if (changed)
+ d->implicitWidthChanged();
+}
+
+/*!
+ Returns whether the width property has been set explicitly.
+*/
+bool QDeclarativeItem::widthValid() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->widthValid;
+}
+
+/*!
+ \internal
+ Return the height of the item
+*/
+qreal QDeclarativeItem::height() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->height();
+}
+
+/*!
+ \internal
+ Set the height of the item
+*/
+void QDeclarativeItem::setHeight(qreal h)
+{
+ Q_D(QDeclarativeItem);
+ d->setHeight(h);
+}
+
+/*!
+ \internal
+ Reset the height of the item
+*/
+void QDeclarativeItem::resetHeight()
+{
+ Q_D(QDeclarativeItem);
+ d->resetHeight();
+}
+
+/*!
+ \internal
+*/
+qreal QDeclarativeItemPrivate::height() const
+{
+ return mHeight;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeItemPrivate::setHeight(qreal h)
+{
+ Q_Q(QDeclarativeItem);
+ if (qIsNaN(h))
+ return;
+
+ heightValid = true;
+ if (mHeight == h)
+ return;
+
+ qreal oldHeight = mHeight;
+
+ q->prepareGeometryChange();
+ mHeight = h;
+
+ q->geometryChanged(QRectF(q->x(), q->y(), width(), height()),
+ QRectF(q->x(), q->y(), width(), oldHeight));
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeItemPrivate::resetHeight()
+{
+ Q_Q(QDeclarativeItem);
+ heightValid = false;
+ q->setImplicitHeight(q->implicitHeight());
+}
+
+void QDeclarativeItemPrivate::implicitHeightChanged()
+{
+ Q_Q(QDeclarativeItem);
+ emit q->implicitHeightChanged();
+}
+
+qreal QDeclarativeItemPrivate::implicitHeight() const
+{
+ return mImplicitHeight;
+}
+
+/*!
+ Returns the height of the item that is implied by other properties that determine the content.
+*/
+qreal QDeclarativeItem::implicitHeight() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->implicitHeight();
+}
+
+/*!
+ \qmlproperty real Item::implicitWidth
+ \qmlproperty real Item::implicitHeight
+ \since Quick 1.1
+
+ Defines the natural width or height of the Item if no \l width or \l height is specified.
+
+ The default implicit size for most items is 0x0, however some elements have an inherent
+ implicit size which cannot be overridden, e.g. Image, Text.
+
+ Setting the implicit size is useful for defining components that have a preferred size
+ based on their content, for example:
+
+ \qml
+ // Label.qml
+ import QtQuick 1.1
+
+ Item {
+ property alias icon: image.source
+ property alias label: text.text
+ implicitWidth: text.implicitWidth + image.implicitWidth
+ implicitHeight: Math.max(text.implicitHeight, image.implicitHeight)
+ Image { id: image }
+ Text {
+ id: text
+ wrapMode: Text.Wrap
+ anchors.left: image.right; anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ \endqml
+
+ \bold Note: using implicitWidth of Text or TextEdit and setting the width explicitly
+ incurs a performance penalty as the text must be laid out twice.
+*/
+
+
+/*!
+ Sets the implied height of the item to \a h.
+ This is the height implied by other properties that determine the content.
+*/
+void QDeclarativeItem::setImplicitHeight(qreal h)
+{
+ Q_D(QDeclarativeItem);
+ bool changed = h != d->mImplicitHeight;
+ d->mImplicitHeight = h;
+ if (d->mHeight == h || heightValid()) {
+ if (changed)
+ d->implicitHeightChanged();
+ return;
+ }
+
+ qreal oldHeight = d->mHeight;
+
+ prepareGeometryChange();
+ d->mHeight = h;
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), width(), oldHeight));
+
+ if (changed)
+ d->implicitHeightChanged();
+}
+
+/*!
+ Returns whether the height property has been set explicitly.
+*/
+bool QDeclarativeItem::heightValid() const
+{
+ Q_D(const QDeclarativeItem);
+ return d->heightValid;
+}
+
+/*! \internal */
+void QDeclarativeItem::setSize(const QSizeF &size)
+{
+ Q_D(QDeclarativeItem);
+ d->heightValid = true;
+ d->widthValid = true;
+
+ if (d->height() == size.height() && d->width() == size.width())
+ return;
+
+ qreal oldHeight = d->height();
+ qreal oldWidth = d->width();
+
+ prepareGeometryChange();
+ d->setHeight(size.height());
+ d->setWidth(size.width());
+
+ geometryChanged(QRectF(x(), y(), width(), height()),
+ QRectF(x(), y(), oldWidth, oldHeight));
+}
+
+/*!
+ \qmlproperty bool Item::activeFocus
+
+ This property indicates whether the item has active focus.
+
+ An item with active focus will receive keyboard input,
+ or is a FocusScope ancestor of the item that will receive keyboard input.
+
+ Usually, activeFocus is gained by setting focus on an item and its enclosing
+ FocusScopes. In the following example \c input will have activeFocus.
+ \qml
+ Rectangle {
+ FocusScope {
+ focus: true
+ TextInput {
+ id: input
+ focus: true
+ }
+ }
+ }
+ \endqml
+
+ \sa focus, {qmlfocus}{Keyboard Focus}
+*/
+
+/*! \internal */
+bool QDeclarativeItem::hasActiveFocus() const
+{
+ Q_D(const QDeclarativeItem);
+ return focusItem() == this ||
+ (d->flags & QGraphicsItem::ItemIsFocusScope && focusItem() != 0);
+}
+
+/*!
+ \qmlproperty bool Item::focus
+ This property indicates whether the item has focus within the enclosing focus scope. If true, this item
+ will gain active focus when the enclosing focus scope gains active focus.
+ In the following example, \c input will be given active focus when \c scope gains active focus.
+ \qml
+ Rectangle {
+ FocusScope {
+ id: scope
+ TextInput {
+ id: input
+ focus: true
+ }
+ }
+ }
+ \endqml
+
+ For the purposes of this property, the scene as a whole is assumed to act like a focus scope.
+ On a practical level, that means the following QML will give active focus to \c input on startup.
+
+ \qml
+ Rectangle {
+ TextInput {
+ id: input
+ focus: true
+ }
+ }
+ \endqml
+
+ \sa activeFocus, {qmlfocus}{Keyboard Focus}
+*/
+
+/*! \internal */
+bool QDeclarativeItem::hasFocus() const
+{
+ Q_D(const QDeclarativeItem);
+ QGraphicsItem *p = d->parent;
+ while (p) {
+ if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+ return p->focusScopeItem() == this;
+ }
+ p = p->parentItem();
+ }
+
+ return hasActiveFocus();
+}
+
+/*! \internal */
+void QDeclarativeItem::setFocus(bool focus)
+{
+ if (focus)
+ QGraphicsItem::setFocus(Qt::OtherFocusReason);
+ else
+ QGraphicsItem::clearFocus();
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeItem::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
+{
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeItem::event(QEvent *ev)
+{
+ Q_D(QDeclarativeItem);
+ switch (ev->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::InputMethod:
+ d->doneEventPreHandler = false;
+ break;
+ default:
+ break;
+ }
+
+ return QGraphicsObject::event(ev);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QDeclarativeItem *item)
+{
+ if (!item) {
+ debug << "QDeclarativeItem(0)";
+ return debug;
+ }
+
+ debug << item->metaObject()->className() << "(this =" << ((void*)item)
+ << ", parent =" << ((void*)item->parentItem())
+ << ", geometry =" << QRectF(item->pos(), QSizeF(item->width(), item->height()))
+ << ", z =" << item->zValue() << ')';
+ return debug;
+}
+#endif
+
+qint64 QDeclarativeItemPrivate::consistentTime = -1;
+void QDeclarativeItemPrivate::setConsistentTime(qint64 t)
+{
+ consistentTime = t;
+}
+
+class QElapsedTimerConsistentTimeHack
+{
+public:
+ void start() {
+ t1 = QDeclarativeItemPrivate::consistentTime;
+ t2 = 0;
+ }
+ qint64 elapsed() {
+ return QDeclarativeItemPrivate::consistentTime - t1;
+ }
+ qint64 restart() {
+ qint64 val = QDeclarativeItemPrivate::consistentTime - t1;
+ t1 = QDeclarativeItemPrivate::consistentTime;
+ t2 = 0;
+ return val;
+ }
+
+private:
+ qint64 t1;
+ qint64 t2;
+};
+
+void QDeclarativeItemPrivate::start(QElapsedTimer &t)
+{
+ if (QDeclarativeItemPrivate::consistentTime == -1)
+ t.start();
+ else
+ ((QElapsedTimerConsistentTimeHack*)&t)->start();
+}
+
+qint64 QDeclarativeItemPrivate::elapsed(QElapsedTimer &t)
+{
+ if (QDeclarativeItemPrivate::consistentTime == -1)
+ return t.elapsed();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->elapsed();
+}
+
+qint64 QDeclarativeItemPrivate::restart(QElapsedTimer &t)
+{
+ if (QDeclarativeItemPrivate::consistentTime == -1)
+ return t.restart();
+ else
+ return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qdeclarativeitem.cpp>
diff --git a/src/declarative/graphicsitems/qdeclarativeitem.h b/src/declarative/graphicsitems/qdeclarativeitem.h
new file mode 100644
index 0000000000..839b934903
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitem.h
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEITEM_H
+#define QDECLARATIVEITEM_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicstransform.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qaction.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeState;
+class QDeclarativeAnchorLine;
+class QDeclarativeTransition;
+class QDeclarativeKeyEvent;
+class QDeclarativeAnchors;
+class QDeclarativeItemPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeItem : public QGraphicsObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+
+ Q_PROPERTY(QDeclarativeItem * parent READ parentItem WRITE setParentItem NOTIFY parentChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeListProperty<QObject> data READ data DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeListProperty<QObject> resources READ resources DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeListProperty<QDeclarativeState> states READ states DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeListProperty<QDeclarativeTransition> transitions READ transitions DESIGNABLE false)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QRectF childrenRect READ childrenRect NOTIFY childrenRectChanged DESIGNABLE false FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchors * anchors READ anchors DESIGNABLE false CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine left READ left CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine right READ right CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine horizontalCenter READ horizontalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine top READ top CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine bottom READ bottom CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine verticalCenter READ verticalCenter CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QDeclarativeItem::d_func(), QDeclarativeAnchorLine 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) // ### move to QGI/QGO, NOTIFY
+ Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL)
+ Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QGraphicsTransform> transform READ transform DESIGNABLE false FINAL)
+ Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin NOTIFY transformOriginChanged)
+ Q_PROPERTY(QPointF transformOriginPoint READ transformOriginPoint) // transformOriginPoint is read-only for Item
+ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged REVISION 1)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged REVISION 1)
+
+ Q_ENUMS(TransformOrigin)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ enum TransformOrigin {
+ TopLeft, Top, TopRight,
+ Left, Center, Right,
+ BottomLeft, Bottom, BottomRight
+ };
+
+ QDeclarativeItem(QDeclarativeItem *parent = 0);
+ virtual ~QDeclarativeItem();
+
+ QDeclarativeItem *parentItem() const;
+ void setParentItem(QDeclarativeItem *parent);
+
+ QRectF childrenRect();
+
+ bool clip() const;
+ void setClip(bool);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal);
+
+ QDeclarativeListProperty<QGraphicsTransform> transform();
+
+ 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);
+
+ bool smooth() const;
+ void setSmooth(bool);
+
+ QRectF boundingRect() const;
+ virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+ bool hasActiveFocus() const;
+ bool hasFocus() const;
+ void setFocus(bool);
+
+ bool keepMouseGrab() const;
+ void setKeepMouseGrab(bool);
+
+ 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 QDeclarativeItem *childAt(qreal x, qreal y) const;
+
+Q_SIGNALS:
+ void childrenRectChanged(const QRectF &);
+ void baselineOffsetChanged(qreal);
+ void stateChanged(const QString &);
+ void focusChanged(bool);
+ void activeFocusChanged(bool);
+ void parentChanged(QDeclarativeItem *);
+ void transformOriginChanged(TransformOrigin);
+ void smoothChanged(bool);
+ void clipChanged(bool);
+ Q_REVISION(1) void implicitWidthChanged();
+ Q_REVISION(1) void implicitHeightChanged();
+
+protected:
+ bool isComponentComplete() const;
+ virtual bool sceneEvent(QEvent *);
+ virtual bool event(QEvent *);
+ virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
+
+ 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 QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+ void keyPressPreHandler(QKeyEvent *);
+ void keyReleasePreHandler(QKeyEvent *);
+ void inputMethodPreHandler(QInputMethodEvent *);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+protected:
+ QDeclarativeItem(QDeclarativeItemPrivate &dd, QDeclarativeItem *parent = 0);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeItem)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
+};
+
+template<typename T>
+ T qobject_cast(QGraphicsObject *o)
+{
+ QObject *obj = o;
+ return qobject_cast<T>(obj);
+}
+
+// ### move to QGO
+template<typename T>
+T qobject_cast(QGraphicsItem *item)
+{
+ if (!item) return 0;
+ QObject *o = item->toGraphicsObject();
+ return qobject_cast<T>(o);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, QDeclarativeItem *item);
+#endif
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeItem)
+QML_DECLARE_TYPE(QGraphicsObject)
+QML_DECLARE_TYPE(QGraphicsTransform)
+QML_DECLARE_TYPE(QGraphicsScale)
+QML_DECLARE_TYPE(QGraphicsRotation)
+QML_DECLARE_TYPE(QGraphicsWidget)
+QML_DECLARE_TYPE(QAction)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEITEM_H
diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h
new file mode 100644
index 0000000000..dae581c94f
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEITEM_P_H
+#define QDECLARATIVEITEM_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 "qdeclarativeitem.h"
+
+#include "private/qdeclarativeanchors_p.h"
+#include "private/qdeclarativeanchors_p_p.h"
+#include "private/qdeclarativeitemchangelistener_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 <private/qgraphicsitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QDeclarativeItemKeyFilter;
+class QDeclarativeLayoutMirroringAttached;
+
+//### merge into private?
+class QDeclarativeContents : public QObject, public QDeclarativeItemChangeListener
+{
+ Q_OBJECT
+public:
+ QDeclarativeContents(QDeclarativeItem *item);
+ ~QDeclarativeContents();
+
+ QRectF rectF() const;
+
+ void childRemoved(QDeclarativeItem *item);
+ void childAdded(QDeclarativeItem *item);
+
+ void calcGeometry() { calcWidth(); calcHeight(); }
+ void complete();
+
+Q_SIGNALS:
+ void rectChanged(QRectF);
+
+protected:
+ void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void itemDestroyed(QDeclarativeItem *item);
+ //void itemVisibilityChanged(QDeclarativeItem *item)
+
+private:
+ void calcHeight(QDeclarativeItem *changed = 0);
+ void calcWidth(QDeclarativeItem *changed = 0);
+
+ QDeclarativeItem *m_item;
+ qreal m_x;
+ qreal m_y;
+ qreal m_width;
+ qreal m_height;
+};
+
+class Q_DECLARATIVE_EXPORT QDeclarativeItemPrivate : public QGraphicsItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeItem)
+
+public:
+ QDeclarativeItemPrivate()
+ : _anchors(0), _contents(0),
+ baselineOffset(0),
+ _anchorLines(0),
+ _stateGroup(0), origin(QDeclarativeItem::Center),
+ widthValid(false), heightValid(false),
+ componentComplete(true), keepMouse(false),
+ smooth(false), transformOriginDirty(true), doneEventPreHandler(false),
+ inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
+ inheritMirrorFromParent(false), inheritMirrorFromItem(false), keyHandler(0),
+ mWidth(0), mHeight(0), mImplicitWidth(0), mImplicitHeight(0), attachedLayoutDirection(0), hadSubFocusItem(false)
+ {
+ QGraphicsItemPrivate::acceptedMouseButtons = 0;
+ isDeclarativeItem = 1;
+ QGraphicsItemPrivate::flags = QGraphicsItem::GraphicsItemFlags(
+ QGraphicsItem::ItemHasNoContents
+ | QGraphicsItem::ItemIsFocusable
+ | QGraphicsItem::ItemNegativeZStacksBehindParent);
+ }
+
+ void init(QDeclarativeItem *parent)
+ {
+ Q_Q(QDeclarativeItem);
+ if (parent) {
+ QDeclarative_setParent_noEvent(q, parent);
+ q->setParentItem(parent);
+ QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parent);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ }
+ baselineOffset.invalidate();
+ mouseSetsFocus = false;
+ }
+
+ bool isMirrored() const {
+ return effectiveLayoutMirror;
+ }
+
+ // Private Properties
+ qreal width() const;
+ void setWidth(qreal);
+ void resetWidth();
+
+ qreal height() const;
+ void setHeight(qreal);
+ void resetHeight();
+
+ virtual qreal implicitWidth() const;
+ virtual qreal implicitHeight() const;
+ virtual void implicitWidthChanged();
+ virtual void implicitHeightChanged();
+
+ void resolveLayoutMirror();
+ void setImplicitLayoutMirror(bool mirror, bool inherit);
+ void setLayoutMirror(bool mirror);
+
+ QDeclarativeListProperty<QObject> data();
+ QDeclarativeListProperty<QObject> resources();
+
+ QDeclarativeListProperty<QDeclarativeState> states();
+ QDeclarativeListProperty<QDeclarativeTransition> transitions();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QDeclarativeAnchorLine left() const;
+ QDeclarativeAnchorLine right() const;
+ QDeclarativeAnchorLine horizontalCenter() const;
+ QDeclarativeAnchorLine top() const;
+ QDeclarativeAnchorLine bottom() const;
+ QDeclarativeAnchorLine verticalCenter() const;
+ QDeclarativeAnchorLine 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> *);
+
+ // transform property
+ static int transform_count(QDeclarativeListProperty<QGraphicsTransform> *list);
+ static void transform_append(QDeclarativeListProperty<QGraphicsTransform> *list, QGraphicsTransform *);
+ static QGraphicsTransform *transform_at(QDeclarativeListProperty<QGraphicsTransform> *list, int);
+ static void transform_clear(QDeclarativeListProperty<QGraphicsTransform> *list);
+
+ static QDeclarativeItemPrivate* get(QDeclarativeItem *item)
+ {
+ return item->d_func();
+ }
+
+ // Accelerated property accessors
+ QDeclarativeNotifier parentNotifier;
+ static void parentProperty(QObject *o, void *rv, QDeclarativeNotifierEndpoint *e);
+
+ QDeclarativeAnchors *anchors() {
+ if (!_anchors) {
+ Q_Q(QDeclarativeItem);
+ _anchors = new QDeclarativeAnchors(q);
+ if (!componentComplete)
+ _anchors->classBegin();
+ }
+ return _anchors;
+ }
+ QDeclarativeAnchors *_anchors;
+ QDeclarativeContents *_contents;
+
+ QDeclarativeNullableValue<qreal> baselineOffset;
+
+ struct AnchorLines {
+ AnchorLines(QGraphicsObject *);
+ QDeclarativeAnchorLine left;
+ QDeclarativeAnchorLine right;
+ QDeclarativeAnchorLine hCenter;
+ QDeclarativeAnchorLine top;
+ QDeclarativeAnchorLine bottom;
+ QDeclarativeAnchorLine vCenter;
+ QDeclarativeAnchorLine baseline;
+ };
+ mutable AnchorLines *_anchorLines;
+ AnchorLines *anchorLines() const {
+ Q_Q(const QDeclarativeItem);
+ if (!_anchorLines) _anchorLines =
+ new AnchorLines(const_cast<QDeclarativeItem *>(q));
+ return _anchorLines;
+ }
+
+ enum ChangeType {
+ Geometry = 0x01,
+ SiblingOrder = 0x02,
+ Visibility = 0x04,
+ Opacity = 0x08,
+ Destroyed = 0x10
+ };
+
+ Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+
+ struct ChangeListener {
+ ChangeListener(QDeclarativeItemChangeListener *l, QDeclarativeItemPrivate::ChangeTypes t) : listener(l), types(t) {}
+ QDeclarativeItemChangeListener *listener;
+ QDeclarativeItemPrivate::ChangeTypes types;
+ bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
+ };
+
+ void addItemChangeListener(QDeclarativeItemChangeListener *listener, ChangeTypes types) {
+ changeListeners.append(ChangeListener(listener, types));
+ }
+ void removeItemChangeListener(QDeclarativeItemChangeListener *, ChangeTypes types);
+ QPODVector<ChangeListener,4> changeListeners;
+
+ QDeclarativeStateGroup *_states();
+ QDeclarativeStateGroup *_stateGroup;
+
+ QDeclarativeItem::TransformOrigin origin:5;
+ bool widthValid:1;
+ bool heightValid:1;
+ bool componentComplete:1;
+ bool keepMouse:1;
+ bool smooth:1;
+ bool transformOriginDirty : 1;
+ bool doneEventPreHandler : 1;
+ bool inheritedLayoutMirror:1;
+ bool effectiveLayoutMirror:1;
+ bool isMirrorImplicit:1;
+ bool inheritMirrorFromParent:1;
+ bool inheritMirrorFromItem:1;
+
+ QDeclarativeItemKeyFilter *keyHandler;
+
+ qreal mWidth;
+ qreal mHeight;
+ qreal mImplicitWidth;
+ qreal mImplicitHeight;
+
+ QDeclarativeLayoutMirroringAttached* attachedLayoutDirection;
+
+ bool hadSubFocusItem;
+
+ QPointF computeTransformOrigin() const;
+
+ virtual void setPosHelper(const QPointF &pos)
+ {
+ Q_Q(QDeclarativeItem);
+ QRectF oldGeometry(this->pos.x(), this->pos.y(), mWidth, mHeight);
+ QGraphicsItemPrivate::setPosHelper(pos);
+ q->geometryChanged(QRectF(this->pos.x(), this->pos.y(), mWidth, mHeight), oldGeometry);
+ }
+
+ // Reimplemented from QGraphicsItemPrivate
+ virtual void subFocusItemChange()
+ {
+ bool hasSubFocusItem = subFocusItem != 0;
+ if (((flags & QGraphicsItem::ItemIsFocusScope) || !parent) && hasSubFocusItem != hadSubFocusItem)
+ emit q_func()->activeFocusChanged(hasSubFocusItem);
+ //see also QDeclarativeItemPrivate::focusChanged
+ hadSubFocusItem = hasSubFocusItem;
+ }
+
+ // Reimplemented from QGraphicsItemPrivate
+ virtual void focusScopeItemChange(bool isSubFocusItem)
+ {
+ emit q_func()->focusChanged(isSubFocusItem);
+ }
+
+
+ // Reimplemented from QGraphicsItemPrivate
+ virtual void siblingOrderChange()
+ {
+ Q_Q(QDeclarativeItem);
+ for(int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QDeclarativeItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QDeclarativeItemPrivate::SiblingOrder) {
+ change.listener->itemSiblingOrderChanged(q);
+ }
+ }
+ }
+
+ // Reimplemented from QGraphicsItemPrivate
+ virtual void transformChanged();
+
+ virtual void focusChanged(bool);
+
+ 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 QDeclarativeItem, 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 QDeclarativeItemKeyFilter
+{
+public:
+ QDeclarativeItemKeyFilter(QDeclarativeItem * = 0);
+ virtual ~QDeclarativeItemKeyFilter();
+
+ 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:
+ QDeclarativeItemKeyFilter *m_next;
+};
+
+class QDeclarativeKeyNavigationAttachedPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeKeyNavigationAttachedPrivate()
+ : QObjectPrivate(), left(0), right(0), up(0), down(0), tab(0), backtab(0) {}
+
+ QDeclarativeItem *left;
+ QDeclarativeItem *right;
+ QDeclarativeItem *up;
+ QDeclarativeItem *down;
+ QDeclarativeItem *tab;
+ QDeclarativeItem *backtab;
+};
+
+class QDeclarativeKeyNavigationAttached : public QObject, public QDeclarativeItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeKeyNavigationAttached)
+
+ Q_PROPERTY(QDeclarativeItem *left READ left WRITE setLeft NOTIFY leftChanged)
+ Q_PROPERTY(QDeclarativeItem *right READ right WRITE setRight NOTIFY rightChanged)
+ Q_PROPERTY(QDeclarativeItem *up READ up WRITE setUp NOTIFY upChanged)
+ Q_PROPERTY(QDeclarativeItem *down READ down WRITE setDown NOTIFY downChanged)
+ Q_PROPERTY(QDeclarativeItem *tab READ tab WRITE setTab NOTIFY tabChanged)
+ Q_PROPERTY(QDeclarativeItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QDeclarativeKeyNavigationAttached(QObject * = 0);
+
+ QDeclarativeItem *left() const;
+ void setLeft(QDeclarativeItem *);
+ QDeclarativeItem *right() const;
+ void setRight(QDeclarativeItem *);
+ QDeclarativeItem *up() const;
+ void setUp(QDeclarativeItem *);
+ QDeclarativeItem *down() const;
+ void setDown(QDeclarativeItem *);
+ QDeclarativeItem *tab() const;
+ void setTab(QDeclarativeItem *);
+ QDeclarativeItem *backtab() const;
+ void setBacktab(QDeclarativeItem *);
+
+ enum Priority { BeforeItem, AfterItem };
+ Priority priority() const;
+ void setPriority(Priority);
+
+ static QDeclarativeKeyNavigationAttached *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(QDeclarativeItem *currentItem, const char *dir);
+};
+
+class QDeclarativeLayoutMirroringAttached : 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 QDeclarativeLayoutMirroringAttached(QObject *parent = 0);
+
+ bool enabled() const;
+ void setEnabled(bool);
+ void resetEnabled();
+
+ bool childrenInherit() const;
+ void setChildrenInherit(bool);
+
+ static QDeclarativeLayoutMirroringAttached *qmlAttachedProperties(QObject *);
+Q_SIGNALS:
+ void enabledChanged();
+ void childrenInheritChanged();
+private:
+ friend class QDeclarativeItemPrivate;
+ QDeclarativeItemPrivate *itemPrivate;
+};
+
+class QDeclarativeKeysAttachedPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeKeysAttachedPrivate()
+ : QObjectPrivate(), inPress(false), inRelease(false)
+ , inIM(false), enabled(true), imeItem(0), item(0)
+ {}
+
+ bool isConnected(const char *signalName);
+
+ QGraphicsItem *finalFocusProxy(QGraphicsItem *item) const
+ {
+ QGraphicsItem *fp;
+ while ((fp = item->focusProxy()))
+ item = fp;
+ return item;
+ }
+
+ //loop detection
+ bool inPress:1;
+ bool inRelease:1;
+ bool inIM:1;
+
+ bool enabled : 1;
+
+ QGraphicsItem *imeItem;
+ QList<QDeclarativeItem *> targets;
+ QDeclarativeItem *item;
+};
+
+class QDeclarativeKeysAttached : public QObject, public QDeclarativeItemKeyFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeKeysAttached)
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeItem> forwardTo READ forwardTo)
+ Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+
+ Q_ENUMS(Priority)
+
+public:
+ QDeclarativeKeysAttached(QObject *parent=0);
+ ~QDeclarativeKeysAttached();
+
+ bool enabled() const { Q_D(const QDeclarativeKeysAttached); return d->enabled; }
+ void setEnabled(bool enabled) {
+ Q_D(QDeclarativeKeysAttached);
+ if (enabled != d->enabled) {
+ d->enabled = enabled;
+ emit enabledChanged();
+ }
+ }
+
+ enum Priority { BeforeItem, AfterItem};
+ Priority priority() const;
+ void setPriority(Priority);
+
+ QDeclarativeListProperty<QDeclarativeItem> forwardTo() {
+ Q_D(QDeclarativeKeysAttached);
+ return QDeclarativeListProperty<QDeclarativeItem>(this, d->targets);
+ }
+
+ virtual void componentComplete();
+
+ static QDeclarativeKeysAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void enabledChanged();
+ void priorityChanged();
+ void pressed(QDeclarativeKeyEvent *event);
+ void released(QDeclarativeKeyEvent *event);
+ void digit0Pressed(QDeclarativeKeyEvent *event);
+ void digit1Pressed(QDeclarativeKeyEvent *event);
+ void digit2Pressed(QDeclarativeKeyEvent *event);
+ void digit3Pressed(QDeclarativeKeyEvent *event);
+ void digit4Pressed(QDeclarativeKeyEvent *event);
+ void digit5Pressed(QDeclarativeKeyEvent *event);
+ void digit6Pressed(QDeclarativeKeyEvent *event);
+ void digit7Pressed(QDeclarativeKeyEvent *event);
+ void digit8Pressed(QDeclarativeKeyEvent *event);
+ void digit9Pressed(QDeclarativeKeyEvent *event);
+
+ void leftPressed(QDeclarativeKeyEvent *event);
+ void rightPressed(QDeclarativeKeyEvent *event);
+ void upPressed(QDeclarativeKeyEvent *event);
+ void downPressed(QDeclarativeKeyEvent *event);
+ void tabPressed(QDeclarativeKeyEvent *event);
+ void backtabPressed(QDeclarativeKeyEvent *event);
+
+ void asteriskPressed(QDeclarativeKeyEvent *event);
+ void numberSignPressed(QDeclarativeKeyEvent *event);
+ void escapePressed(QDeclarativeKeyEvent *event);
+ void returnPressed(QDeclarativeKeyEvent *event);
+ void enterPressed(QDeclarativeKeyEvent *event);
+ void deletePressed(QDeclarativeKeyEvent *event);
+ void spacePressed(QDeclarativeKeyEvent *event);
+ void backPressed(QDeclarativeKeyEvent *event);
+ void cancelPressed(QDeclarativeKeyEvent *event);
+ void selectPressed(QDeclarativeKeyEvent *event);
+ void yesPressed(QDeclarativeKeyEvent *event);
+ void noPressed(QDeclarativeKeyEvent *event);
+ void context1Pressed(QDeclarativeKeyEvent *event);
+ void context2Pressed(QDeclarativeKeyEvent *event);
+ void context3Pressed(QDeclarativeKeyEvent *event);
+ void context4Pressed(QDeclarativeKeyEvent *event);
+ void callPressed(QDeclarativeKeyEvent *event);
+ void hangupPressed(QDeclarativeKeyEvent *event);
+ void flipPressed(QDeclarativeKeyEvent *event);
+ void menuPressed(QDeclarativeKeyEvent *event);
+ void volumeUpPressed(QDeclarativeKeyEvent *event);
+ void volumeDownPressed(QDeclarativeKeyEvent *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[];
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeItemPrivate::ChangeTypes);
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeKeysAttached)
+QML_DECLARE_TYPEINFO(QDeclarativeKeysAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QDeclarativeKeyNavigationAttached)
+QML_DECLARE_TYPEINFO(QDeclarativeKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QDeclarativeLayoutMirroringAttached)
+QML_DECLARE_TYPEINFO(QDeclarativeLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QDECLARATIVEITEM_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeitemchangelistener_p.h b/src/declarative/graphicsitems/qdeclarativeitemchangelistener_p.h
new file mode 100644
index 0000000000..411ae26527
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitemchangelistener_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEITEMCHANGELISTENER
+#define QDECLARATIVEITEMCHANGELISTENER
+
+//
+// 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 QDeclarativeItem;
+class QDeclarativeAnchorsPrivate;
+class QDeclarativeItemChangeListener
+{
+public:
+ virtual void itemGeometryChanged(QDeclarativeItem *, const QRectF &, const QRectF &) {}
+ virtual void itemSiblingOrderChanged(QDeclarativeItem *) {}
+ virtual void itemVisibilityChanged(QDeclarativeItem *) {}
+ virtual void itemOpacityChanged(QDeclarativeItem *) {}
+ virtual void itemDestroyed(QDeclarativeItem *) {}
+ virtual QDeclarativeAnchorsPrivate *anchorPrivate() { return 0; }
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEITEMCHANGELISTENER
diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
new file mode 100644
index 0000000000..c4a9030102
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** 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 "private/qdeclarativeitemsmodule_p.h"
+
+#include <QtGui/qaction.h>
+#include <QtGui/qvalidator.h>
+#include <QtGui/qgraphicseffect.h>
+
+#include "private/qdeclarativeevents_p_p.h"
+#include "private/qdeclarativescalegrid_p_p.h"
+#include "private/qdeclarativeanimatedimage_p.h"
+#include "private/qdeclarativeborderimage_p.h"
+#include "private/qdeclarativepositioners_p.h"
+#include "private/qdeclarativemousearea_p.h"
+#include "private/qdeclarativeflickable_p.h"
+#include "private/qdeclarativeflickable_p_p.h"
+#include "private/qdeclarativeflipable_p.h"
+#include "private/qdeclarativefocuspanel_p.h"
+#include "private/qdeclarativefocusscope_p.h"
+#include "private/qdeclarativegridview_p.h"
+#include "private/qdeclarativeimage_p.h"
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativelayoutitem_p.h"
+#include "private/qdeclarativelistview_p.h"
+#include "private/qdeclarativeloader_p.h"
+#include "private/qdeclarativemousearea_p.h"
+#include "private/qdeclarativepath_p.h"
+#include "private/qdeclarativepathview_p.h"
+#include "private/qdeclarativerectangle_p.h"
+#include "private/qdeclarativerepeater_p.h"
+#include "private/qdeclarativetranslate_p.h"
+#include "private/qdeclarativetext_p.h"
+#include "private/qdeclarativetextedit_p.h"
+#include "private/qdeclarativetextinput_p.h"
+#include "private/qdeclarativevisualitemmodel_p.h"
+#include "private/qdeclarativegraphicswidget_p.h"
+#ifdef QT_WEBKIT_LIB
+#include "private/qdeclarativewebview_p.h"
+#include "private/qdeclarativewebview_p_p.h"
+#endif
+#include "private/qdeclarativeanchors_p.h"
+#include "private/qdeclarativepincharea_p.h"
+
+static QDeclarativePrivate::AutoParentResult qgraphicsobject_autoParent(QObject *obj, QObject *parent)
+{
+ QGraphicsObject* gobj = qobject_cast<QGraphicsObject*>(obj);
+ if (!gobj)
+ return QDeclarativePrivate::IncompatibleObject;
+
+ QGraphicsObject* gparent = qobject_cast<QGraphicsObject*>(parent);
+ if (!gparent)
+ return QDeclarativePrivate::IncompatibleParent;
+
+ gobj->setParentItem(gparent);
+ return QDeclarativePrivate::Parented;
+}
+
+void QDeclarativeItemModule::defineModule()
+{
+ QDeclarativePrivate::RegisterAutoParent autoparent = { 0, &qgraphicsobject_autoParent };
+ QDeclarativePrivate::qmlregister(QDeclarativePrivate::AutoParentRegistration, &autoparent);
+#ifdef QT_NO_MOVIE
+ qmlRegisterTypeNotAvailable("QtQuick",1,0,"AnimatedImage",
+ qApp->translate("QDeclarativeAnimatedImage","Qt was built without support for QMovie"));
+#else
+ qmlRegisterType<QDeclarativeAnimatedImage>("QtQuick",1,0,"AnimatedImage");
+#endif
+ qmlRegisterType<QDeclarativeBorderImage>("QtQuick",1,0,"BorderImage");
+ qmlRegisterType<QDeclarativeColumn>("QtQuick",1,0,"Column");
+ qmlRegisterType<QDeclarativeDrag>("QtQuick",1,0,"Drag");
+ qmlRegisterType<QDeclarativeFlickable>("QtQuick",1,0,"Flickable");
+ qmlRegisterType<QDeclarativeFlipable>("QtQuick",1,0,"Flipable");
+ qmlRegisterType<QDeclarativeFlow>("QtQuick",1,0,"Flow");
+ qmlRegisterType<QDeclarativeFocusPanel>("QtQuick",1,0,"FocusPanel");
+ qmlRegisterType<QDeclarativeFocusScope>("QtQuick",1,0,"FocusScope");
+ qmlRegisterType<QDeclarativeGradient>("QtQuick",1,0,"Gradient");
+ qmlRegisterType<QDeclarativeGradientStop>("QtQuick",1,0,"GradientStop");
+ qmlRegisterType<QDeclarativeGrid>("QtQuick",1,0,"Grid");
+ qmlRegisterType<QDeclarativeGridView>("QtQuick",1,0,"GridView");
+ qmlRegisterType<QDeclarativeImage>("QtQuick",1,0,"Image");
+ qmlRegisterType<QDeclarativeItem>("QtQuick",1,0,"Item");
+ qmlRegisterType<QDeclarativeLayoutItem>("QtQuick",1,0,"LayoutItem");
+ qmlRegisterType<QDeclarativeListView>("QtQuick",1,0,"ListView");
+ qmlRegisterType<QDeclarativeLoader>("QtQuick",1,0,"Loader");
+ qmlRegisterType<QDeclarativeMouseArea>("QtQuick",1,0,"MouseArea");
+ qmlRegisterType<QDeclarativePath>("QtQuick",1,0,"Path");
+ qmlRegisterType<QDeclarativePathAttribute>("QtQuick",1,0,"PathAttribute");
+ qmlRegisterType<QDeclarativePathCubic>("QtQuick",1,0,"PathCubic");
+ qmlRegisterType<QDeclarativePathLine>("QtQuick",1,0,"PathLine");
+ qmlRegisterType<QDeclarativePathPercent>("QtQuick",1,0,"PathPercent");
+ qmlRegisterType<QDeclarativePathQuad>("QtQuick",1,0,"PathQuad");
+ qmlRegisterType<QDeclarativePathView>("QtQuick",1,0,"PathView");
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QIntValidator>("QtQuick",1,0,"IntValidator");
+ qmlRegisterType<QDoubleValidator>("QtQuick",1,0,"DoubleValidator");
+ qmlRegisterType<QRegExpValidator>("QtQuick",1,0,"RegExpValidator");
+#endif
+ qmlRegisterType<QDeclarativeRectangle>("QtQuick",1,0,"Rectangle");
+ qmlRegisterType<QDeclarativeRepeater>("QtQuick",1,0,"Repeater");
+ qmlRegisterType<QGraphicsRotation>("QtQuick",1,0,"Rotation");
+ qmlRegisterType<QDeclarativeRow>("QtQuick",1,0,"Row");
+ qmlRegisterType<QDeclarativeTranslate>("QtQuick",1,0,"Translate");
+ qmlRegisterType<QGraphicsScale>("QtQuick",1,0,"Scale");
+ qmlRegisterType<QDeclarativeText>("QtQuick",1,0,"Text");
+ qmlRegisterType<QDeclarativeTextEdit>("QtQuick",1,0,"TextEdit");
+#ifndef QT_NO_LINEEDIT
+ qmlRegisterType<QDeclarativeTextInput>("QtQuick",1,0,"TextInput");
+#endif
+ qmlRegisterType<QDeclarativeViewSection>("QtQuick",1,0,"ViewSection");
+ qmlRegisterType<QDeclarativeVisualDataModel>("QtQuick",1,0,"VisualDataModel");
+ qmlRegisterType<QDeclarativeVisualItemModel>("QtQuick",1,0,"VisualItemModel");
+
+ qmlRegisterType<QDeclarativeAnchors>();
+ qmlRegisterType<QDeclarativeKeyEvent>();
+ qmlRegisterType<QDeclarativeMouseEvent>();
+ qmlRegisterType<QGraphicsObject>();
+ qmlRegisterType<QGraphicsWidget>("QtQuick",1,0,"QGraphicsWidget");
+ qmlRegisterExtendedType<QGraphicsWidget,QDeclarativeGraphicsWidget>("QtQuick",1,0,"QGraphicsWidget");
+ qmlRegisterType<QGraphicsTransform>();
+ qmlRegisterType<QDeclarativePathElement>();
+ qmlRegisterType<QDeclarativeCurve>();
+ qmlRegisterType<QDeclarativeScaleGrid>();
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QValidator>();
+#endif
+ qmlRegisterType<QDeclarativeVisualModel>();
+#ifndef QT_NO_ACTION
+ qmlRegisterType<QAction>();
+#endif
+ qmlRegisterType<QDeclarativePen>();
+ qmlRegisterType<QDeclarativeFlickableVisibleArea>();
+#ifndef QT_NO_GRAPHICSEFFECT
+ qmlRegisterType<QGraphicsEffect>();
+#endif
+
+ qmlRegisterUncreatableType<QDeclarativeKeyNavigationAttached>("QtQuick",1,0,"KeyNavigation",QDeclarativeKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
+ qmlRegisterUncreatableType<QDeclarativeKeysAttached>("QtQuick",1,0,"Keys",QDeclarativeKeysAttached::tr("Keys is only available via attached properties"));
+
+ // QtQuick 1.1 items
+ qmlRegisterType<QDeclarativePinchArea>("QtQuick",1,1,"PinchArea");
+ qmlRegisterType<QDeclarativePinch>("QtQuick",1,1,"Pinch");
+ qmlRegisterType<QDeclarativePinchEvent>();
+ qmlRegisterType<QDeclarativeItem,1>("QtQuick",1,1,"Item");
+ qmlRegisterType<QDeclarativeMouseArea,1>("QtQuick",1,1,"MouseArea");
+ qmlRegisterType<QDeclarativeFlickable,1>("QtQuick",1,1,"Flickable");
+ qmlRegisterType<QDeclarativeListView,1>("QtQuick",1,1,"ListView");
+ qmlRegisterType<QDeclarativeGridView,1>("QtQuick",1,1,"GridView");
+ qmlRegisterType<QDeclarativeRow,1>("QtQuick",1,1,"Row");
+ qmlRegisterType<QDeclarativeGrid,1>("QtQuick",1,1,"Grid");
+ qmlRegisterType<QDeclarativeFlow,1>("QtQuick",1,1,"Flow");
+ qmlRegisterType<QDeclarativeRepeater,1>("QtQuick",1,1,"Repeater");
+ qmlRegisterType<QDeclarativeText,1>("QtQuick",1,1,"Text");
+ qmlRegisterType<QDeclarativeTextEdit,1>("QtQuick",1,1,"TextEdit");
+#ifndef QT_NO_LINEEDIT
+ qmlRegisterType<QDeclarativeTextInput,1>("QtQuick",1,1,"TextInput");
+#endif
+ qmlRegisterRevision<QDeclarativeImageBase,1>("QtQuick",1,1);
+ qmlRegisterRevision<QDeclarativeImplicitSizeItem,0>("QtQuick",1,0);
+ qmlRegisterRevision<QDeclarativeImplicitSizeItem,1>("QtQuick",1,1);
+ qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,0>("QtQuick",1,0);
+ qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,1>("QtQuick",1,1);
+ qmlRegisterUncreatableType<QDeclarativeLayoutMirroringAttached>("QtQuick",1,1,"LayoutMirroring", QDeclarativeLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties"));
+
+#ifndef QT_NO_IMPORT_QT47_QML
+#ifdef QT_NO_MOVIE
+ qmlRegisterTypeNotAvailable("Qt",4,7,"AnimatedImage",
+ qApp->translate("QDeclarativeAnimatedImage","Qt was built without support for QMovie"));
+#else
+ qmlRegisterType<QDeclarativeAnimatedImage>("Qt",4,7,"AnimatedImage");
+#endif
+ qmlRegisterType<QDeclarativeBorderImage>("Qt",4,7,"BorderImage");
+ qmlRegisterType<QDeclarativeColumn>("Qt",4,7,"Column");
+ qmlRegisterType<QDeclarativeDrag>("Qt",4,7,"Drag");
+ qmlRegisterType<QDeclarativeFlickable>("Qt",4,7,"Flickable");
+ qmlRegisterType<QDeclarativeFlipable>("Qt",4,7,"Flipable");
+ qmlRegisterType<QDeclarativeFlow>("Qt",4,7,"Flow");
+ qmlRegisterType<QDeclarativeFocusPanel>("Qt",4,7,"FocusPanel");
+ qmlRegisterType<QDeclarativeFocusScope>("Qt",4,7,"FocusScope");
+ qmlRegisterType<QDeclarativeGradient>("Qt",4,7,"Gradient");
+ qmlRegisterType<QDeclarativeGradientStop>("Qt",4,7,"GradientStop");
+ qmlRegisterType<QDeclarativeGrid>("Qt",4,7,"Grid");
+ qmlRegisterType<QDeclarativeGridView>("Qt",4,7,"GridView");
+ qmlRegisterType<QDeclarativeImage>("Qt",4,7,"Image");
+ qmlRegisterType<QDeclarativeItem>("Qt",4,7,"Item");
+ qmlRegisterType<QDeclarativeLayoutItem>("Qt",4,7,"LayoutItem");
+ qmlRegisterType<QDeclarativeListView>("Qt",4,7,"ListView");
+ qmlRegisterType<QDeclarativeLoader>("Qt",4,7,"Loader");
+ qmlRegisterType<QDeclarativeMouseArea>("Qt",4,7,"MouseArea");
+ qmlRegisterType<QDeclarativePath>("Qt",4,7,"Path");
+ qmlRegisterType<QDeclarativePathAttribute>("Qt",4,7,"PathAttribute");
+ qmlRegisterType<QDeclarativePathCubic>("Qt",4,7,"PathCubic");
+ qmlRegisterType<QDeclarativePathLine>("Qt",4,7,"PathLine");
+ qmlRegisterType<QDeclarativePathPercent>("Qt",4,7,"PathPercent");
+ qmlRegisterType<QDeclarativePathQuad>("Qt",4,7,"PathQuad");
+ qmlRegisterType<QDeclarativePathView>("Qt",4,7,"PathView");
+#ifndef QT_NO_VALIDATOR
+ qmlRegisterType<QIntValidator>("Qt",4,7,"IntValidator");
+ qmlRegisterType<QDoubleValidator>("Qt",4,7,"DoubleValidator");
+ qmlRegisterType<QRegExpValidator>("Qt",4,7,"RegExpValidator");
+#endif
+ qmlRegisterType<QDeclarativeRectangle>("Qt",4,7,"Rectangle");
+ qmlRegisterType<QDeclarativeRepeater>("Qt",4,7,"Repeater");
+ qmlRegisterType<QGraphicsRotation>("Qt",4,7,"Rotation");
+ qmlRegisterType<QDeclarativeRow>("Qt",4,7,"Row");
+ qmlRegisterType<QDeclarativeTranslate>("Qt",4,7,"Translate");
+ qmlRegisterType<QGraphicsScale>("Qt",4,7,"Scale");
+ qmlRegisterType<QDeclarativeText>("Qt",4,7,"Text");
+ qmlRegisterType<QDeclarativeTextEdit>("Qt",4,7,"TextEdit");
+#ifndef QT_NO_LINEEDIT
+ qmlRegisterType<QDeclarativeTextInput>("Qt",4,7,"TextInput");
+#endif
+ qmlRegisterType<QDeclarativeViewSection>("Qt",4,7,"ViewSection");
+ qmlRegisterType<QDeclarativeVisualDataModel>("Qt",4,7,"VisualDataModel");
+ qmlRegisterType<QDeclarativeVisualItemModel>("Qt",4,7,"VisualItemModel");
+
+ qmlRegisterType<QGraphicsWidget>("Qt",4,7,"QGraphicsWidget");
+ qmlRegisterExtendedType<QGraphicsWidget,QDeclarativeGraphicsWidget>("Qt",4,7,"QGraphicsWidget");
+
+ qmlRegisterUncreatableType<QDeclarativeKeyNavigationAttached>("Qt",4,7,"KeyNavigation",QDeclarativeKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
+ qmlRegisterUncreatableType<QDeclarativeKeysAttached>("Qt",4,7,"Keys",QDeclarativeKeysAttached::tr("Keys is only available via attached properties"));
+#endif
+}
diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule_p.h b/src/declarative/graphicsitems/qdeclarativeitemsmodule_p.h
new file mode 100644
index 0000000000..e3e7820a93
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEITEMMODULE_H
+#define QDECLARATIVEITEMMODULE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeItemModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEITEMMODULE_H
diff --git a/src/declarative/graphicsitems/qdeclarativelayoutitem.cpp b/src/declarative/graphicsitems/qdeclarativelayoutitem.cpp
new file mode 100644
index 0000000000..878ffce5b6
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativelayoutitem.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "private/qdeclarativelayoutitem_p.h"
+
+#include <QDebug>
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass LayoutItem QDeclarativeLayoutItem
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The LayoutItem element allows declarative UI elements to be placed inside Qt's Graphics View layouts.
+
+ LayoutItem is a variant of \l Item with additional size hint properties. These properties provide the size hints
+ necessary for items to work in conjunction with Qt \l{Graphics View Framework}{Graphics View} layout classes
+ such as QGraphicsLinearLayout and QGraphicsGridLayout. The Qt layout mechanisms will resize the LayoutItem as appropriate,
+ taking its size hints into account, and you can propagate this to the other elements in your UI via anchors and bindings.
+
+ This is a QGraphicsLayoutItem subclass, and its properties merely expose the QGraphicsLayoutItem functionality to QML.
+
+ The \l{declarative/cppextensions/qgraphicslayouts/layoutitem}{LayoutItem example}
+ demonstrates how a LayoutItem can be used within a \l{Graphics View Framework}{Graphics View}
+ scene.
+*/
+
+/*!
+ \qmlproperty QSizeF LayoutItem::maximumSize
+
+ The maximumSize property can be set to specify the maximum desired size of this LayoutItem
+*/
+
+/*!
+ \qmlproperty QSizeF LayoutItem::minimumSize
+
+ The minimumSize property can be set to specify the minimum desired size of this LayoutItem
+*/
+
+/*!
+ \qmlproperty QSizeF LayoutItem::preferredSize
+
+ The preferredSize property can be set to specify the preferred size of this LayoutItem
+*/
+
+QDeclarativeLayoutItem::QDeclarativeLayoutItem(QDeclarativeItem* parent)
+ : QDeclarativeItem(parent), m_maximumSize(INT_MAX,INT_MAX), m_minimumSize(0,0), m_preferredSize(0,0)
+{
+ setGraphicsItem(this);
+}
+
+void QDeclarativeLayoutItem::setGeometry(const QRectF & rect)
+{
+ setX(rect.x());
+ setY(rect.y());
+ setWidth(rect.width());
+ setHeight(rect.height());
+}
+
+QSizeF QDeclarativeLayoutItem::sizeHint(Qt::SizeHint w, const QSizeF &constraint) const
+{
+ Q_UNUSED(constraint);
+ if(w == Qt::MinimumSize){
+ return m_minimumSize;
+ }else if(w == Qt::MaximumSize){
+ return m_maximumSize;
+ }else{
+ return m_preferredSize;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativelayoutitem_p.h b/src/declarative/graphicsitems/qdeclarativelayoutitem_p.h
new file mode 100644
index 0000000000..5cf33f6d87
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativelayoutitem_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEGRAPHICSLAYOUTITEM_H
+#define QDECLARATIVEGRAPHICSLAYOUTITEM_H
+#include "qdeclarativeitem.h"
+
+#include <QGraphicsLayoutItem>
+#include <QSizeF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeLayoutItem : public QDeclarativeItem, public QGraphicsLayoutItem
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsLayoutItem)
+ Q_PROPERTY(QSizeF maximumSize READ maximumSize WRITE setMaximumSize NOTIFY maximumSizeChanged)
+ Q_PROPERTY(QSizeF minimumSize READ minimumSize WRITE setMinimumSize NOTIFY minimumSizeChanged)
+ Q_PROPERTY(QSizeF preferredSize READ preferredSize WRITE setPreferredSize NOTIFY preferredSizeChanged)
+public:
+ QDeclarativeLayoutItem(QDeclarativeItem* parent=0);
+
+ QSizeF maximumSize() const { return m_maximumSize; }
+ void setMaximumSize(const QSizeF &s) { if(s==m_maximumSize) return; m_maximumSize = s; emit maximumSizeChanged(); }
+
+ QSizeF minimumSize() const { return m_minimumSize; }
+ void setMinimumSize(const QSizeF &s) { if(s==m_minimumSize) return; m_minimumSize = s; emit minimumSizeChanged(); }
+
+ QSizeF preferredSize() const { return m_preferredSize; }
+ void setPreferredSize(const QSizeF &s) { if(s==m_preferredSize) return; m_preferredSize = s; emit preferredSizeChanged(); }
+
+ virtual void setGeometry(const QRectF & rect);
+protected:
+ virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+Q_SIGNALS:
+ void maximumSizeChanged();
+ void minimumSizeChanged();
+ void preferredSizeChanged();
+
+private:
+ QSizeF m_maximumSize;
+ QSizeF m_minimumSize;
+ QSizeF m_preferredSize;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeLayoutItem)
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp
new file mode 100644
index 0000000000..3190d7e209
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp
@@ -0,0 +1,3606 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativelistview_p.h"
+
+#include "private/qdeclarativeflickable_p_p.h"
+#include "private/qdeclarativevisualitemmodel_p.h"
+
+#include "private/qdeclarativesmoothedanimation_p_p.h"
+#include <qdeclarativeexpression.h>
+#include <qdeclarativeengine.h>
+#include <qdeclarativeguard_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <qlistmodelinterface_p.h>
+#include <qmath.h>
+#include <QKeyEvent>
+
+QT_BEGIN_NAMESPACE
+
+void QDeclarativeViewSection::setProperty(const QString &property)
+{
+ if (property != m_property) {
+ m_property = property;
+ emit propertyChanged();
+ }
+}
+
+void QDeclarativeViewSection::setCriteria(QDeclarativeViewSection::SectionCriteria criteria)
+{
+ if (criteria != m_criteria) {
+ m_criteria = criteria;
+ emit criteriaChanged();
+ }
+}
+
+void QDeclarativeViewSection::setDelegate(QDeclarativeComponent *delegate)
+{
+ if (delegate != m_delegate) {
+ m_delegate = delegate;
+ emit delegateChanged();
+ }
+}
+
+QString QDeclarativeViewSection::sectionString(const QString &value)
+{
+ if (m_criteria == FirstCharacter)
+ return value.isEmpty() ? QString() : value.at(0);
+ else
+ return value;
+}
+
+//----------------------------------------------------------------------------
+
+class FxListItem
+{
+public:
+ FxListItem(QDeclarativeItem *i, QDeclarativeListView *v) : item(i), section(0), view(v) {
+ attached = static_cast<QDeclarativeListViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeListView>(item));
+ if (attached)
+ attached->setView(view);
+ }
+ ~FxListItem() {}
+ qreal position() const {
+ if (section) {
+ if (view->orientation() == QDeclarativeListView::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() == QDeclarativeListView::Vertical)
+ return item->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
+ }
+ qreal size() const {
+ if (section)
+ return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->width());
+ else
+ return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
+ }
+ qreal itemSize() const {
+ return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
+ }
+ qreal sectionSize() const {
+ if (section)
+ return (view->orientation() == QDeclarativeListView::Vertical ? section->height() : section->width());
+ return 0.0;
+ }
+ qreal endPosition() const {
+ if (view->orientation() == QDeclarativeListView::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() == QDeclarativeListView::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() == QDeclarativeListView::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());
+ }
+
+ QDeclarativeItem *item;
+ QDeclarativeItem *section;
+ QDeclarativeListView *view;
+ QDeclarativeListViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QDeclarativeListViewPrivate : public QDeclarativeFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeListView)
+
+public:
+ QDeclarativeListViewPrivate()
+ : currentItem(0), orient(QDeclarativeListView::Vertical), layoutDirection(Qt::LeftToRight)
+ , visiblePos(0), visibleIndex(0)
+ , averageSize(100.0), currentIndex(-1), requestedIndex(-1)
+ , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , 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(QDeclarativeListView::NoHighlightRange)
+ , snapMode(QDeclarativeListView::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)
+ , minExtentDirty(true), maxExtentDirty(true)
+ {}
+
+ void init();
+ void clear();
+ FxListItem *createItem(int modelIndex);
+ void releaseItem(FxListItem *item);
+
+ FxListItem *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxListItem *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ FxListItem *firstVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItem *item = visibleItems.at(i);
+ if (item->index != -1 && item->endPosition() > pos)
+ return item;
+ }
+ return visibleItems.count() ? visibleItems.first() : 0;
+ }
+
+ FxListItem *nextVisibleItem() const {
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
+ bool foundFirst = false;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItem *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.
+ FxListItem *itemBefore(int modelIndex) const {
+ if (modelIndex < visibleIndex)
+ return 0;
+ int idx = 1;
+ int lastIndex = -1;
+ while (idx < visibleItems.count()) {
+ FxListItem *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(QDeclarativeListView);
+ if (q->isComponentComplete()) {
+ if (header) {
+ if (q->scene())
+ q->scene()->removeItem(header->item);
+ header->item->deleteLater();
+ delete header;
+ header = 0;
+ }
+ if (footer) {
+ if (q->scene())
+ q->scene()->removeItem(footer->item);
+ footer->item->deleteLater();
+ delete footer;
+ footer = 0;
+ }
+ updateHeader();
+ updateFooter();
+ clear();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QDeclarativeListView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ bool isRightToLeft() const {
+ Q_Q(const QDeclarativeListView);
+ return orient == QDeclarativeListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ qreal position() const {
+ Q_Q(const QDeclarativeListView);
+ return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX();
+ }
+
+ void setPosition(qreal pos) {
+ Q_Q(QDeclarativeListView);
+ if (orient == QDeclarativeListView::Vertical) {
+ q->QDeclarativeFlickable::setContentY(pos);
+ } else {
+ if (isRightToLeft())
+ q->QDeclarativeFlickable::setContentX(-pos-size());
+ else
+ q->QDeclarativeFlickable::setContentX(pos);
+ }
+ }
+ qreal size() const {
+ Q_Q(const QDeclarativeListView);
+ return orient == QDeclarativeListView::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 (FxListItem *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 (FxListItem *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 (FxListItem *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 (FxListItem *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();
+ }
+
+ FxListItem *snapItemAt(qreal pos) {
+ FxListItem *snapItem = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItem *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) {
+ FxListItem *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) {
+ FxListItem *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(QDeclarativeListView);
+ if (orient == QDeclarativeListView::Vertical) {
+ q->setContentHeight(endPosition() - startPosition() + 1);
+ } else {
+ q->setContentWidth(endPosition() - startPosition() + 1);
+ }
+ }
+
+ void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ Q_Q(QDeclarativeListView);
+ QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
+ if (!q->isComponentComplete())
+ return;
+ if (item != contentItem && (!highlight || item != highlight->item)) {
+ if ((orient == QDeclarativeListView::Vertical && newGeometry.height() != oldGeometry.height())
+ || (orient == QDeclarativeListView::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) {
+ FxListItem *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(FxListItem *);
+ 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(QDeclarativeFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
+
+ QDeclarativeGuard<QDeclarativeVisualModel> model;
+ QVariant modelVariant;
+ QList<FxListItem*> visibleItems;
+ QHash<QDeclarativeItem*,int> unrequestedItems;
+ FxListItem *currentItem;
+ QDeclarativeListView::Orientation orient;
+ Qt::LayoutDirection layoutDirection;
+ qreal visiblePos;
+ int visibleIndex;
+ qreal averageSize;
+ int currentIndex;
+ int requestedIndex;
+ int itemCount;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ bool highlightRangeStartValid;
+ bool highlightRangeEndValid;
+ QDeclarativeComponent *highlightComponent;
+ FxListItem *highlight;
+ FxListItem *trackedItem;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QSmoothedAnimation *highlightPosAnimator;
+ QSmoothedAnimation *highlightSizeAnimator;
+ QDeclarativeViewSection *sectionCriteria;
+ QString currentSection;
+ static const int sectionCacheSize = 4;
+ QDeclarativeItem *sectionCache[sectionCacheSize];
+ qreal spacing;
+ qreal highlightMoveSpeed;
+ int highlightMoveDuration;
+ qreal highlightResizeSpeed;
+ int highlightResizeDuration;
+ QDeclarativeListView::HighlightRangeMode highlightRange;
+ QDeclarativeListView::SnapMode snapMode;
+ qreal overshootDist;
+ QDeclarativeComponent *footerComponent;
+ FxListItem *footer;
+ QDeclarativeComponent *headerComponent;
+ FxListItem *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;
+ mutable bool minExtentDirty : 1;
+ mutable bool maxExtentDirty : 1;
+};
+
+void QDeclarativeListViewPrivate::init()
+{
+ Q_Q(QDeclarativeListView);
+ q->setFlag(QGraphicsItem::ItemIsFocusScope);
+ addItemChangeListener(this, Geometry);
+ QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
+ q->setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
+ ::memset(sectionCache, 0, sizeof(QDeclarativeItem*) * sectionCacheSize);
+}
+
+void QDeclarativeListViewPrivate::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;
+}
+
+FxListItem *QDeclarativeListViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QDeclarativeListView);
+ // create object
+ requestedIndex = modelIndex;
+ FxListItem *listItem = 0;
+ if (QDeclarativeItem *item = model->item(modelIndex, false)) {
+ listItem = new FxListItem(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 (FxListItem *item = itemBefore(modelIndex))
+ listItem->attached->m_prevSection = item->attached->section();
+ else
+ listItem->attached->m_prevSection = sectionAt(modelIndex-1);
+ }
+ if (modelIndex < model->count()-1) {
+ if (FxListItem *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->setZValue(1);
+ listItem->item->setParentItem(q->contentItem());
+ model->completeItem();
+ } else {
+ listItem->item->setParentItem(q->contentItem());
+ }
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::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 QDeclarativeListViewPrivate::releaseItem(FxListItem *item)
+{
+ Q_Q(QDeclarativeListView);
+ if (!item || !model)
+ return;
+ if (trackedItem == item)
+ trackedItem = 0;
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item->item));
+ itemPrivate->removeItemChangeListener(this, QDeclarativeItemPrivate::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 QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+{
+ Q_Q(QDeclarativeListView);
+ 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;
+ }
+
+ if (visibleItems.count() && (fillFrom > itemEnd+averageSize+spacing
+ || fillTo < visiblePos - averageSize - spacing)) {
+ // We've jumped more than a page. Estimate which items are now
+ // visible and fill from there.
+ int count = (fillFrom - itemEnd) / (averageSize + spacing);
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ modelIndex += count;
+ if (modelIndex >= model->count()) {
+ count -= modelIndex - model->count() + 1;
+ modelIndex = model->count() - 1;
+ } else if (modelIndex < 0) {
+ count -= modelIndex;
+ modelIndex = 0;
+ }
+ visibleIndex = modelIndex;
+ visiblePos = itemEnd + count * (averageSize + spacing) + 1;
+ itemEnd = visiblePos-1;
+ }
+
+ bool changed = false;
+ FxListItem *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 QDeclarativeListViewPrivate::scheduleLayout()
+{
+ Q_Q(QDeclarativeListView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
+ }
+}
+
+void QDeclarativeListViewPrivate::layout()
+{
+ Q_Q(QDeclarativeListView);
+ 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) {
+ FxListItem *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 QDeclarativeListViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QDeclarativeListView);
+ QHash<QDeclarativeItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QDeclarativeListViewPrivate::updateUnrequestedPositions()
+{
+ Q_Q(QDeclarativeListView);
+ if (unrequestedItems.count()) {
+ qreal pos = position();
+ QHash<QDeclarativeItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QDeclarativeItem *item = it.key();
+ if (orient == QDeclarativeListView::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 QDeclarativeListViewPrivate::updateTrackedItem()
+{
+ Q_Q(QDeclarativeListView);
+ FxListItem *item = currentItem;
+ if (highlight)
+ item = highlight;
+ trackedItem = item;
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QDeclarativeListViewPrivate::createHighlight()
+{
+ Q_Q(QDeclarativeListView);
+ 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) {
+ QDeclarativeItem *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<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QDeclarativeItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ highlight = new FxListItem(item, q);
+ if (currentItem && autoHighlight) {
+ if (orient == QDeclarativeListView::Vertical) {
+ highlight->item->setHeight(currentItem->item->height());
+ } else {
+ highlight->item->setWidth(currentItem->item->width());
+ }
+ highlight->setPosition(currentItem->itemPosition());
+ }
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ const QLatin1String posProp(orient == QDeclarativeListView::Vertical ? "y" : "x");
+ highlightPosAnimator = new QSmoothedAnimation(q);
+ highlightPosAnimator->target = QDeclarativeProperty(highlight->item, posProp);
+ highlightPosAnimator->velocity = highlightMoveSpeed;
+ highlightPosAnimator->userDuration = highlightMoveDuration;
+ const QLatin1String sizeProp(orient == QDeclarativeListView::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 QDeclarativeListViewPrivate::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 == QDeclarativeListView::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 QDeclarativeListViewPrivate::createSection(FxListItem *listItem)
+{
+ Q_Q(QDeclarativeListView);
+ 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<QDeclarativeItem *>(nobj);
+ if (!listItem->section) {
+ delete nobj;
+ } else {
+ listItem->section->setZValue(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 QDeclarativeListViewPrivate::updateSections()
+{
+ if (sectionCriteria && !visibleItems.isEmpty()) {
+ QString prevSection;
+ if (visibleIndex > 0)
+ prevSection = sectionAt(visibleIndex-1);
+ QDeclarativeListViewAttached *prevAtt = 0;
+ int idx = -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ QDeclarativeListViewAttached *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 QDeclarativeListViewPrivate::updateCurrentSection()
+{
+ Q_Q(QDeclarativeListView);
+ 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 QDeclarativeListViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QDeclarativeListView);
+ 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;
+ }
+ FxListItem *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 QDeclarativeListViewPrivate::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 QDeclarativeListViewPrivate::updateFooter()
+{
+ Q_Q(QDeclarativeListView);
+ if (!footer && footerComponent) {
+ QDeclarativeItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = footerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZValue(1);
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ footer = new FxListItem(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 QDeclarativeListViewPrivate::updateHeader()
+{
+ Q_Q(QDeclarativeListView);
+ if (!header && headerComponent) {
+ QDeclarativeItem *item = 0;
+ QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
+ QObject *nobj = headerComponent->create(context);
+ if (nobj) {
+ QDeclarative_setParent_noEvent(context, nobj);
+ item = qobject_cast<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete context;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ item->setParentItem(q->contentItem());
+ item->setZValue(1);
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ header = new FxListItem(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 QDeclarativeListViewPrivate::fixupPosition()
+{
+ if ((haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange)
+ || snapMode != QDeclarativeListView::NoSnap)
+ moveReason = Other;
+ if (orient == QDeclarativeListView::Vertical)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
+{
+ if ((orient == QDeclarativeListView::Horizontal && &data == &vData)
+ || (orient == QDeclarativeListView::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 == QDeclarativeListView::StrictlyEnforceRange
+ && moveReason != QDeclarativeListViewPrivate::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 != QDeclarativeListView::NoSnap && moveReason != QDeclarativeListViewPrivate::SetIndex) {
+ qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+ FxListItem *topItem = snapItemAt(tempPosition+highlightStart);
+ FxListItem *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 {
+ QDeclarativeFlickablePrivate::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 {
+ QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
+ }
+ data.inOvershoot = false;
+ fixupMode = Normal;
+}
+
+void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
+{
+ Q_Q(QDeclarativeListView);
+
+ data.fixingUp = false;
+ moveReason = Mouse;
+ if ((!haveHighlightRange || highlightRange != QDeclarativeListView::StrictlyEnforceRange) && snapMode == QDeclarativeListView::NoSnap) {
+ correctFlick = true;
+ QDeclarativeFlickablePrivate::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 == QDeclarativeListView::SnapOneItem) {
+ if (FxListItem *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(minExtent - data.move.value());
+ }
+ }
+ if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange)
+ data.flickTarget = minExtent;
+ } else {
+ if (data.move.value() > maxExtent) {
+ if (snapMode == QDeclarativeListView::SnapOneItem) {
+ if (FxListItem *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
+ } else {
+ maxDistance = qAbs(maxExtent - data.move.value());
+ }
+ }
+ if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange)
+ data.flickTarget = maxExtent;
+ }
+
+ bool overShoot = boundsBehavior == QDeclarativeFlickable::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 == QDeclarativeListView::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(vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(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(vSize);
+ data.flickTarget += overshootDist;
+ } else if (data.flickTarget <= maxExtent) {
+ overshootDist = overShootDistance(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 != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::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);
+ }
+}
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass ListView QDeclarativeListView
+ \ingroup qml-view-elements
+ \since 4.7
+ \inherits Flickable
+ \brief The ListView item provides a list view of items provided by a model.
+
+ A ListView displays data from models created from built-in QML elements like ListModel
+ and XmlListModel, or custom model classes defined in C++ that inherit from
+ QAbstractListModel.
+
+ A ListView has a \l model, which defines the data to be displayed, and
+ a \l delegate, which defines how the data should be displayed. Items in a
+ ListView are laid out horizontally or vertically. List views are inherently
+ flickable because ListView inherits from \l Flickable.
+
+ \section1 Example Usage
+
+ The following example shows the definition of a simple list model defined
+ in a file called \c ContactModel.qml:
+
+ \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0
+
+ Another component can display this model data in a ListView, like this:
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/listview/listview.qml classdocs simple
+
+ \image listview-simple.png
+
+ Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
+ for its delegate. The view will create a new \l Text component for each item in the model. Notice
+ the delegate is able to access the model's \c name and \c number data directly.
+
+ An improved list view is shown below. The delegate is visually improved and is moved
+ into a separate \c contactDelegate component.
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced
+ \image listview-highlight.png
+
+ The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
+ and \c focus is set to \c true to enable keyboard navigation for the list view.
+ The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
+
+ Delegates are instantiated as needed and may be destroyed at any time.
+ State should \e never be stored in a delegate.
+
+ ListView attaches a number of properties to the root item of the delegate, for example
+ \c {ListView.isCurrentItem}. In the following example, the root delegate item can access
+ this attached property directly as \c ListView.isCurrentItem, while the child
+ \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
+
+ \note Views do not enable \e clip automatically. If the view
+ is not clipped by another item or the screen, it will be necessary
+ to set \e {clip: true} in order to have the out of view items clipped
+ nicely.
+
+ \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
+*/
+
+QDeclarativeListView::QDeclarativeListView(QDeclarativeItem *parent)
+ : QDeclarativeFlickable(*(new QDeclarativeListViewPrivate), parent)
+{
+ Q_D(QDeclarativeListView);
+ d->init();
+}
+
+QDeclarativeListView::~QDeclarativeListView()
+{
+ Q_D(QDeclarativeListView);
+ d->clear();
+ if (d->ownModel)
+ delete d->model;
+ delete d->header;
+ delete d->footer;
+}
+
+/*!
+ \qmlattachedproperty bool ListView::isCurrentItem
+ This attached property is true if this delegate is the current item; otherwise false.
+
+ It is attached to each instance of the delegate.
+
+ This property may be used to adjust the appearance of the current item, for example:
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
+*/
+
+/*!
+ \qmlattachedproperty ListView ListView::view
+ This attached property holds the view that manages this delegate instance.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty string ListView::previousSection
+ This attached property holds the section of the previous element.
+
+ It is attached to each instance of the delegate.
+
+ The section is evaluated using the \l {ListView::section.property}{section} properties.
+*/
+
+/*!
+ \qmlattachedproperty string ListView::nextSection
+ This attached property holds the section of the next element.
+
+ It is attached to each instance of the delegate.
+
+ The section is evaluated using the \l {ListView::section.property}{section} properties.
+*/
+
+/*!
+ \qmlattachedproperty string ListView::section
+ This attached property holds the section of this element.
+
+ It is attached to each instance of the delegate.
+
+ The section is evaluated using the \l {ListView::section.property}{section} properties.
+*/
+
+/*!
+ \qmlattachedproperty bool ListView::delayRemove
+ This attached property holds whether the delegate may be destroyed.
+
+ It is attached to each instance of the delegate.
+
+ It is sometimes necessary to delay the destruction of an item
+ until an animation completes.
+
+ The example delegate below ensures that the animation completes before
+ the item is removed from the list.
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml delayRemove
+*/
+
+/*!
+ \qmlattachedsignal ListView::onAdd()
+ This attached handler is called immediately after an item is added to the view.
+*/
+
+/*!
+ \qmlattachedsignal ListView::onRemove()
+ This attached handler is called immediately before an item is removed from the view.
+*/
+
+/*!
+ \qmlproperty model ListView::model
+ This property holds the model providing data for the list.
+
+ The model provides the set of data that is used to create the items
+ in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
+ or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
+ used, it must be a subclass of \l QAbstractItemModel or a simple list.
+
+ \sa {qmlmodels}{Data Models}
+*/
+QVariant QDeclarativeListView::model() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->modelVariant;
+}
+
+void QDeclarativeListView::setModel(const QVariant &model)
+{
+ Q_D(QDeclarativeListView);
+ 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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ }
+ d->clear();
+ QDeclarativeVisualModel *oldModel = d->model;
+ d->model = 0;
+ d->setPosition(0);
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QDeclarativeVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete oldModel;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ } else {
+ d->model = oldModel;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ dataModel->setModel(model);
+ }
+ if (d->model) {
+ d->bufferMode = QDeclarativeListViewPrivate::BufferBefore | QDeclarativeListViewPrivate::BufferAfter;
+ if (isComponentComplete()) {
+ updateSections();
+ refill();
+ if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
+ setCurrentIndex(0);
+ } else {
+ d->moveReason = QDeclarativeListViewPrivate::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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ emit countChanged();
+ }
+ emit modelChanged();
+}
+
+/*!
+ \qmlproperty Component ListView::delegate
+
+ The delegate provides a template defining each item instantiated by the view.
+ The index is exposed as an accessible \c index property. Properties of the
+ model are also available depending upon the type of \l {qmlmodels}{Data Model}.
+
+ The number of elements in the delegate has a direct effect on the
+ flicking performance of the view. If at all possible, place functionality
+ that is not needed for the normal display of the delegate in a \l Loader which
+ can load additional elements when needed.
+
+ The ListView will lay out the items based on the size of the root item
+ in the delegate.
+
+ It is recommended that the delagate's size be a whole number to avoid sub-pixel
+ alignment of items.
+
+ \note Delegates are instantiated as needed and may be destroyed at any time.
+ State should \e never be stored in a delegate.
+*/
+QDeclarativeComponent *QDeclarativeListView::delegate() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->model) {
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QDeclarativeListView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QDeclarativeListView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(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 = QDeclarativeListViewPrivate::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();
+}
+
+/*!
+ \qmlproperty int ListView::currentIndex
+ \qmlproperty Item ListView::currentItem
+
+ The \c currentIndex property holds the index of the current item, and
+ \c currentItem holds the current item. Setting the currentIndex to -1
+ will clear the highlight and set currentItem to null.
+
+ If highlightFollowsCurrentItem is \c true, setting either of these
+ properties will smoothly scroll the ListView so that the current
+ item becomes visible.
+
+ Note that the position of the current item
+ may only be approximate until it becomes visible in the view.
+*/
+int QDeclarativeListView::currentIndex() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->currentIndex;
+}
+
+void QDeclarativeListView::setCurrentIndex(int index)
+{
+ Q_D(QDeclarativeListView);
+ if (d->requestedIndex >= 0) // currently creating item
+ return;
+ d->currentIndexCleared = (index == -1);
+ if (index == d->currentIndex)
+ return;
+ if (isComponentComplete() && d->isValid()) {
+ d->moveReason = QDeclarativeListViewPrivate::SetIndex;
+ d->updateCurrent(index);
+ } else if (d->currentIndex != index) {
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ }
+}
+
+QDeclarativeItem *QDeclarativeListView::currentItem()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->currentItem)
+ return 0;
+ return d->currentItem->item;
+}
+
+/*!
+ \qmlproperty Item ListView::highlightItem
+
+ This holds the highlight item created from the \l highlight component.
+
+ The \c highlightItem is managed by the view unless
+ \l highlightFollowsCurrentItem is set to false.
+
+ \sa highlight, highlightFollowsCurrentItem
+*/
+QDeclarativeItem *QDeclarativeListView::highlightItem()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->highlight)
+ return 0;
+ return d->highlight->item;
+}
+
+/*!
+ \qmlproperty int ListView::count
+ This property holds the number of items in the view.
+*/
+int QDeclarativeListView::count() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+/*!
+ \qmlproperty Component ListView::highlight
+ This property holds the component to use as the highlight.
+
+ An instance of the highlight component is created for each list.
+ The geometry of the resulting component instance is managed by the list
+ so as to stay with the current item, unless the highlightFollowsCurrentItem
+ property is false.
+
+ \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
+*/
+QDeclarativeComponent *QDeclarativeListView::highlight() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightComponent;
+}
+
+void QDeclarativeListView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QDeclarativeListView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ if (d->currentItem)
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool ListView::highlightFollowsCurrentItem
+ This property holds whether the highlight is managed by the view.
+
+ If this property is true (the default value), the highlight is moved smoothly
+ to follow the current item. Otherwise, the
+ highlight is not moved by the view, and any movement must be implemented
+ by the highlight.
+
+ Here is a highlight with its motion defined by a \l {SpringAnimation} item:
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml highlightFollowsCurrentItem
+
+ Note that the highlight animation also affects the way that the view
+ is scrolled. This is because the view moves to maintain the
+ highlight within the preferred highlight range (or visible viewport).
+
+ \sa highlight, highlightMoveSpeed
+*/
+bool QDeclarativeListView::highlightFollowsCurrentItem() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->autoHighlight;
+}
+
+void QDeclarativeListView::setHighlightFollowsCurrentItem(bool autoHighlight)
+{
+ Q_D(QDeclarativeListView);
+ 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?
+/*!
+ \qmlproperty real ListView::preferredHighlightBegin
+ \qmlproperty real ListView::preferredHighlightEnd
+ \qmlproperty enumeration ListView::highlightRangeMode
+
+ These properties define the preferred range of the highlight (for the current item)
+ within the view. The \c preferredHighlightBegin value must be less than the
+ \c preferredHighlightEnd value.
+
+ These properties affect the position of the current item when the list is scrolled.
+ For example, if the currently selected item should stay in the middle of the
+ list when the view is scrolled, set the \c preferredHighlightBegin and
+ \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
+ item would be. If the \c currentItem is changed programmatically, the list will
+ automatically scroll so that the current item is in the middle of the view.
+ Furthermore, the behavior of the current item index will occur whether or not a
+ highlight exists.
+
+ Valid values for \c highlightRangeMode are:
+
+ \list
+ \o ListView.ApplyRange - the view attempts to maintain the highlight within the range.
+ However, the highlight can move outside of the range at the ends of the list or due
+ to mouse interaction.
+ \o ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
+ The current item changes if a keyboard or mouse action would cause the highlight to move
+ outside of the range.
+ \o ListView.NoHighlightRange - this is the default value.
+ \endlist
+*/
+qreal QDeclarativeListView::preferredHighlightBegin() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightRangeStart;
+}
+
+void QDeclarativeListView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeStartValid = true;
+ if (d->highlightRangeStart == start)
+ return;
+ d->highlightRangeStart = start;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightBeginChanged();
+}
+
+void QDeclarativeListView::resetPreferredHighlightBegin()
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
+qreal QDeclarativeListView::preferredHighlightEnd() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightRangeEnd;
+}
+
+void QDeclarativeListView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeEndValid = true;
+ if (d->highlightRangeEnd == end)
+ return;
+ d->highlightRangeEnd = end;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit preferredHighlightEndChanged();
+}
+
+void QDeclarativeListView::resetPreferredHighlightEnd()
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
+QDeclarativeListView::HighlightRangeMode QDeclarativeListView::highlightRangeMode() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightRange;
+}
+
+void QDeclarativeListView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QDeclarativeListView);
+ if (d->highlightRange == mode)
+ return;
+ d->highlightRange = mode;
+ d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+/*!
+ \qmlproperty real ListView::spacing
+
+ This property holds the spacing between items.
+
+ The default value is 0.
+*/
+qreal QDeclarativeListView::spacing() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->spacing;
+}
+
+void QDeclarativeListView::setSpacing(qreal spacing)
+{
+ Q_D(QDeclarativeListView);
+ if (spacing != d->spacing) {
+ d->spacing = spacing;
+ d->layout();
+ emit spacingChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration ListView::orientation
+ This property holds the orientation of the list.
+
+ Possible values:
+
+ \list
+ \o ListView.Horizontal - Items are laid out horizontally
+ \o ListView.Vertical (default) - Items are laid out vertically
+ \endlist
+
+ \table
+ \row
+ \o Horizontal orientation:
+ \image ListViewHorizontal.png
+
+ \row
+ \o Vertical orientation:
+ \image listview-highlight.png
+ \endtable
+*/
+QDeclarativeListView::Orientation QDeclarativeListView::orientation() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->orient;
+}
+
+void QDeclarativeListView::setOrientation(QDeclarativeListView::Orientation orientation)
+{
+ Q_D(QDeclarativeListView);
+ if (d->orient != orientation) {
+ d->orient = orientation;
+ if (d->orient == QDeclarativeListView::Vertical) {
+ setContentWidth(-1);
+ setFlickableDirection(VerticalFlick);
+ setContentX(0);
+ } else {
+ setContentHeight(-1);
+ setFlickableDirection(HorizontalFlick);
+ setContentY(0);
+ }
+ d->regenerate();
+ emit orientationChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration ListView::layoutDirection
+ This property holds the layout direction of the horizontal list.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items will be laid out from left to right.
+ \o Qt.RightToLeft - Items will be laid out from right to let.
+ \endlist
+
+ \sa ListView::effectiveLayoutDirection
+*/
+
+Qt::LayoutDirection QDeclarativeListView::layoutDirection() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->layoutDirection;
+}
+
+void QDeclarativeListView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QDeclarativeListView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration ListView::effectiveLayoutDirection
+ This property holds the effective layout direction of the horizontal list.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the horizontal list will be mirrored. However, the
+ property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeListView::effectiveLayoutDirection() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+/*!
+ \qmlproperty bool ListView::keyNavigationWraps
+ This property holds whether the list wraps key navigation.
+
+ If this is true, key navigation that would move the current item selection
+ past the end of the list instead wraps around and moves the selection to
+ the start of the list, and vice-versa.
+
+ By default, key navigation is not wrapped.
+*/
+bool QDeclarativeListView::isWrapEnabled() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->wrap;
+}
+
+void QDeclarativeListView::setWrapEnabled(bool wrap)
+{
+ Q_D(QDeclarativeListView);
+ if (d->wrap == wrap)
+ return;
+ d->wrap = wrap;
+ emit keyNavigationWrapsChanged();
+}
+
+/*!
+ \qmlproperty int ListView::cacheBuffer
+ This property determines whether delegates are retained outside the
+ visible area of the view.
+
+ If this value is non-zero, the view keeps as many delegates
+ instantiated as it can fit within the buffer specified. For example,
+ if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
+ set to 40, then up to 2 delegates above and 2 delegates below the visible
+ area may be retained.
+
+ Note that cacheBuffer is not a pixel buffer - it only maintains additional
+ instantiated delegates.
+
+ Setting this value can improve the smoothness of scrolling behavior at the expense
+ of additional memory usage. It is not a substitute for creating efficient
+ delegates; the fewer elements in a delegate, the faster a view can be
+ scrolled.
+*/
+int QDeclarativeListView::cacheBuffer() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->buffer;
+}
+
+void QDeclarativeListView::setCacheBuffer(int b)
+{
+ Q_D(QDeclarativeListView);
+ if (d->buffer != b) {
+ d->buffer = b;
+ if (isComponentComplete()) {
+ d->bufferMode = QDeclarativeListViewPrivate::BufferBefore | QDeclarativeListViewPrivate::BufferAfter;
+ refill();
+ }
+ emit cacheBufferChanged();
+ }
+}
+
+/*!
+ \qmlproperty string ListView::section.property
+ \qmlproperty enumeration ListView::section.criteria
+ \qmlproperty Component ListView::section.delegate
+
+ These properties hold the expression to be evaluated for the \l section attached property.
+
+ The \l section attached property enables a ListView to be visually
+ separated into different parts. These properties determine how sections
+ are created.
+
+ \c section.property holds the name of the property that is the basis
+ of each section.
+
+ \c section.criteria holds the criteria for forming each section based on
+ \c section.property. This value can be one of:
+
+ \list
+ \o ViewSection.FullString (default) - sections are created based on the
+ \c section.property value.
+ \o ViewSection.FirstCharacter - sections are created based on the first
+ character of the \c section.property value (for example, 'A', 'B', 'C'
+ sections, etc. for an address book)
+ \endlist
+
+ \c section.delegate holds the delegate component for each section.
+
+ Each item in the list has attached properties named \c ListView.section,
+ \c ListView.previousSection and \c ListView.nextSection. These may be
+ used to place a section header for related items.
+
+ For example, here is a ListView that displays a list of animals, separated
+ into sections. Each item in the ListView is placed in a different section
+ depending on the "size" property of the model item. The \c sectionHeading
+ delegate component provides the light blue bar that marks the beginning of
+ each section.
+
+
+ \snippet examples/declarative/modelviews/listview/sections.qml 0
+
+ \image qml-listview-sections-example.png
+
+ \note Adding sections to a ListView does not automatically re-order the
+ list items by the section criteria.
+ If the model is not ordered by section, then it is possible that
+ the sections created will not be unique; each boundary between
+ differing sections will result in a section header being created
+ even if that section exists elsewhere.
+
+ \sa {declarative/modelviews/listview}{ListView examples}
+*/
+QDeclarativeViewSection *QDeclarativeListView::sectionCriteria()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->sectionCriteria) {
+ d->sectionCriteria = new QDeclarativeViewSection(this);
+ connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
+ }
+ return d->sectionCriteria;
+}
+
+/*!
+ \qmlproperty string ListView::currentSection
+ This property holds the section that is currently at the beginning of the view.
+*/
+QString QDeclarativeListView::currentSection() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->currentSection;
+}
+
+/*!
+ \qmlproperty real ListView::highlightMoveSpeed
+ \qmlproperty int ListView::highlightMoveDuration
+ \qmlproperty real ListView::highlightResizeSpeed
+ \qmlproperty int ListView::highlightResizeDuration
+
+ These properties hold the move and resize animation speed of the highlight delegate.
+
+ \l highlightFollowsCurrentItem must be true for these properties
+ to have effect.
+
+ The default value for the speed properties is 400 pixels/second.
+ The default value for the duration properties is -1, i.e. the
+ highlight will take as much time as necessary to move at the set speed.
+
+ These properties have the same characteristics as a SmoothedAnimation.
+
+ \sa highlightFollowsCurrentItem
+*/
+qreal QDeclarativeListView::highlightMoveSpeed() const
+{
+ Q_D(const QDeclarativeListView);\
+ return d->highlightMoveSpeed;
+}
+
+void QDeclarativeListView::setHighlightMoveSpeed(qreal speed)
+{
+ Q_D(QDeclarativeListView);\
+ if (d->highlightMoveSpeed != speed) {
+ d->highlightMoveSpeed = speed;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
+ emit highlightMoveSpeedChanged();
+ }
+}
+
+int QDeclarativeListView::highlightMoveDuration() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightMoveDuration;
+}
+
+void QDeclarativeListView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QDeclarativeListView);\
+ if (d->highlightMoveDuration != duration) {
+ d->highlightMoveDuration = duration;
+ if (d->highlightPosAnimator)
+ d->highlightPosAnimator->userDuration = d->highlightMoveDuration;
+ emit highlightMoveDurationChanged();
+ }
+}
+
+qreal QDeclarativeListView::highlightResizeSpeed() const
+{
+ Q_D(const QDeclarativeListView);\
+ return d->highlightResizeSpeed;
+}
+
+void QDeclarativeListView::setHighlightResizeSpeed(qreal speed)
+{
+ Q_D(QDeclarativeListView);\
+ if (d->highlightResizeSpeed != speed) {
+ d->highlightResizeSpeed = speed;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
+ emit highlightResizeSpeedChanged();
+ }
+}
+
+int QDeclarativeListView::highlightResizeDuration() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->highlightResizeDuration;
+}
+
+void QDeclarativeListView::setHighlightResizeDuration(int duration)
+{
+ Q_D(QDeclarativeListView);\
+ if (d->highlightResizeDuration != duration) {
+ d->highlightResizeDuration = duration;
+ if (d->highlightSizeAnimator)
+ d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ emit highlightResizeDurationChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration ListView::snapMode
+
+ This property determines how the view scrolling will settle following a drag or flick.
+ The possible values are:
+
+ \list
+ \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
+ \o ListView.SnapToItem - the view settles with an item aligned with the start of
+ the view.
+ \o ListView.SnapOneItem - the view settles no more than one item away from the first
+ visible item at the time the mouse button is released. This mode is particularly
+ useful for moving one page at a time.
+ \endlist
+
+ \c snapMode does not affect the \l currentIndex. To update the
+ \l currentIndex as the list is moved, set \l highlightRangeMode
+ to \c ListView.StrictlyEnforceRange.
+
+ \sa highlightRangeMode
+*/
+QDeclarativeListView::SnapMode QDeclarativeListView::snapMode() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->snapMode;
+}
+
+void QDeclarativeListView::setSnapMode(SnapMode mode)
+{
+ Q_D(QDeclarativeListView);
+ if (d->snapMode != mode) {
+ d->snapMode = mode;
+ emit snapModeChanged();
+ }
+}
+
+/*!
+ \qmlproperty Component ListView::footer
+ This property holds the component to use as the footer.
+
+ An instance of the footer component is created for each view. The
+ footer is positioned at the end of the view, after any items.
+
+ \sa header
+*/
+QDeclarativeComponent *QDeclarativeListView::footer() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->footerComponent;
+}
+
+void QDeclarativeListView::setFooter(QDeclarativeComponent *footer)
+{
+ Q_D(QDeclarativeListView);
+ if (d->footerComponent != footer) {
+ if (d->footer) {
+ if (scene())
+ scene()->removeItem(d->footer->item);
+ 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();
+ }
+}
+
+/*!
+ \qmlproperty Component ListView::header
+ This property holds the component to use as the header.
+
+ An instance of the header component is created for each view. The
+ header is positioned at the beginning of the view, before any items.
+
+ \sa footer
+*/
+QDeclarativeComponent *QDeclarativeListView::header() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->headerComponent;
+}
+
+void QDeclarativeListView::setHeader(QDeclarativeComponent *header)
+{
+ Q_D(QDeclarativeListView);
+ if (d->headerComponent != header) {
+ if (d->header) {
+ if (scene())
+ scene()->removeItem(d->header->item);
+ 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 QDeclarativeListView::setContentX(qreal pos)
+{
+ Q_D(QDeclarativeListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QDeclarativeListViewPrivate::Other;
+ QDeclarativeFlickable::setContentX(pos);
+}
+
+void QDeclarativeListView::setContentY(qreal pos)
+{
+ Q_D(QDeclarativeListView);
+ // Positioning the view manually should override any current movement state
+ d->moveReason = QDeclarativeListViewPrivate::Other;
+ QDeclarativeFlickable::setContentY(pos);
+}
+
+bool QDeclarativeListView::event(QEvent *event)
+{
+ Q_D(QDeclarativeListView);
+ if (event->type() == QEvent::User) {
+ d->layout();
+ return true;
+ }
+
+ return QDeclarativeFlickable::event(event);
+}
+
+void QDeclarativeListView::viewportMoved()
+{
+ Q_D(QDeclarativeListView);
+ QDeclarativeFlickable::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 = QDeclarativeListViewPrivate::Mouse;
+ if (d->moveReason != QDeclarativeListViewPrivate::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 (FxListItem *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() && !d->vData.inOvershoot) {
+ 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 = QDeclarativeListViewPrivate::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 = QDeclarativeListViewPrivate::BufferAfter;
+ }
+ }
+
+ if (xflick() && !d->hData.inOvershoot) {
+ 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()
+ ? QDeclarativeListViewPrivate::BufferAfter : QDeclarativeListViewPrivate::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()
+ ? QDeclarativeListViewPrivate::BufferBefore : QDeclarativeListViewPrivate::BufferAfter;
+ }
+ }
+ d->inFlickCorrection = false;
+ }
+ d->inViewportMoved = false;
+}
+
+qreal QDeclarativeListView::minYExtent() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->orient == QDeclarativeListView::Horizontal)
+ return QDeclarativeFlickable::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 QDeclarativeListView::maxYExtent() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->orient == QDeclarativeListView::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 QDeclarativeListView::minXExtent() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->orient == QDeclarativeListView::Vertical)
+ return QDeclarativeFlickable::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 QDeclarativeListView::maxXExtent() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->orient == QDeclarativeListView::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 QDeclarativeListView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeListView);
+ keyPressPreHandler(event);
+ if (event->isAccepted())
+ return;
+
+ if (d->model && d->model->count() && d->interactive) {
+ if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QDeclarativeListView::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->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QDeclarativeListView::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();
+ QDeclarativeFlickable::keyPressEvent(event);
+}
+
+void QDeclarativeListView::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeListView);
+ d->maxExtentDirty = true;
+ d->minExtentDirty = true;
+ if (d->isRightToLeft() && d->orient == QDeclarativeListView::Horizontal) {
+ // maintain position relative to the right edge
+ int dx = newGeometry.width() - oldGeometry.width();
+ setContentX(contentX() - dx);
+ }
+ QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+/*!
+ \qmlmethod ListView::incrementCurrentIndex()
+
+ Increments the current index. The current index will wrap
+ if keyNavigationWraps is true and it is currently at the end.
+ This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeListView::incrementCurrentIndex()
+{
+ Q_D(QDeclarativeListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() < count - 1 || d->wrap)) {
+ d->moveReason = QDeclarativeListViewPrivate::SetIndex;
+ int index = currentIndex()+1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+}
+
+/*!
+ \qmlmethod ListView::decrementCurrentIndex()
+
+ Decrements the current index. The current index will wrap
+ if keyNavigationWraps is true and it is currently at the beginning.
+ This method has no effect if the \l count is zero.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativeListView::decrementCurrentIndex()
+{
+ Q_D(QDeclarativeListView);
+ int count = d->model ? d->model->count() : 0;
+ if (count && (currentIndex() > 0 || d->wrap)) {
+ d->moveReason = QDeclarativeListViewPrivate::SetIndex;
+ int index = currentIndex()-1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+}
+
+void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QDeclarativeListView);
+ if (!isValid())
+ return;
+ if (mode < QDeclarativeListView::Beginning || mode > QDeclarativeListView::Contain)
+ return;
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = isRightToLeft() ? -position() - size() : position();
+ FxListItem *item = visibleItem(idx);
+ qreal maxExtent;
+ if (orient == QDeclarativeListView::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<FxListItem*> 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 QDeclarativeListView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header)
+ pos -= header->size();
+ break;
+ case QDeclarativeListView::Center:
+ pos = itemPos - (size() - item->size())/2;
+ break;
+ case QDeclarativeListView::End:
+ pos = itemPos - size() + item->size();
+ if (index >= model->count() && footer)
+ pos += footer->size();
+ break;
+ case QDeclarativeListView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + item->size();
+ else if (item->endPosition() < pos)
+ pos = itemPos;
+ break;
+ case QDeclarativeListView::Contain:
+ if (item->endPosition() > pos + size())
+ pos = itemPos - size() + item->size();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ pos = qMin(pos, maxExtent);
+ qreal minExtent;
+ if (orient == QDeclarativeListView::Vertical) {
+ minExtent = -q->minYExtent();
+ } else {
+ minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent();
+ }
+ pos = qMax(pos, minExtent);
+ moveReason = QDeclarativeListViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ if (highlight) {
+ if (autoHighlight) {
+ highlight->setPosition(currentItem->itemPosition());
+ highlight->setSize(currentItem->itemSize());
+ }
+ updateHighlight();
+ }
+ }
+ fixupPosition();
+}
+
+/*!
+ \qmlmethod ListView::positionViewAtIndex(int index, PositionMode mode)
+
+ Positions the view such that the \a index is at the position specified by
+ \a mode:
+
+ \list
+ \o ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
+ \o ListView.Center - position item in the center of the view.
+ \o ListView.End - position item at bottom (or right for horizontal orientation) of the view.
+ \o ListView.Visible - if any part of the item is visible then take no action, otherwise
+ bring the item into view.
+ \o ListView.Contain - ensure the entire item is visible. If the item is larger than
+ the view the item is positioned at the top (or left for horizontal orientation) of the view.
+ \endlist
+
+ If positioning the view at \a index would cause empty space to be displayed at
+ the beginning or end of the view, the view will be positioned at the boundary.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the list does not cause all other items to be repositioned, and because
+ the actual start of the view can vary based on the size of the delegates.
+ The correct way to bring an item into view is with \c positionViewAtIndex.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end:
+
+ \code
+ Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
+ \endcode
+*/
+void QDeclarativeListView::positionViewAtIndex(int index, int mode)
+{
+ Q_D(QDeclarativeListView);
+ if (!d->isValid() || index < 0 || index >= d->model->count())
+ return;
+ d->positionViewAtIndex(index, mode);
+}
+
+/*!
+ \qmlmethod ListView::positionViewAtBeginning()
+ \qmlmethod ListView::positionViewAtEnd()
+ \since Quick 1.1
+
+ Positions the view at the beginning or end, taking into account any header or footer.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the list does not cause all other items to be repositioned, and because
+ the actual start of the view can vary based on the size of the delegates.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end on startup:
+
+ \code
+ Component.onCompleted: positionViewAtEnd()
+ \endcode
+*/
+void QDeclarativeListView::positionViewAtBeginning()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(-1, Beginning);
+}
+
+void QDeclarativeListView::positionViewAtEnd()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
+}
+
+/*!
+ \qmlmethod int ListView::indexAt(int x, int y)
+
+ Returns the index of the visible item containing the point \a x, \a y in content
+ coordinates. If there is no item at the point specified, or the item is
+ not visible -1 is returned.
+
+ If the item is outside the visible area, -1 is returned, regardless of
+ whether an item will exist at that point when scrolled into view.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+int QDeclarativeListView::indexAt(qreal x, qreal y) const
+{
+ Q_D(const QDeclarativeListView);
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ const FxListItem *listItem = d->visibleItems.at(i);
+ if(listItem->contains(x, y))
+ return listItem->index;
+ }
+
+ return -1;
+}
+
+void QDeclarativeListView::componentComplete()
+{
+ Q_D(QDeclarativeListView);
+ QDeclarativeFlickable::componentComplete();
+ updateSections();
+ d->updateHeader();
+ d->updateFooter();
+ if (d->isValid()) {
+ refill();
+ d->moveReason = QDeclarativeListViewPrivate::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 = QDeclarativeListViewPrivate::Other;
+ d->fixupPosition();
+ }
+}
+
+void QDeclarativeListView::updateSections()
+{
+ Q_D(QDeclarativeListView);
+ 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 QDeclarativeListView::refill()
+{
+ Q_D(QDeclarativeListView);
+ if (d->isRightToLeft())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+void QDeclarativeListView::trackedPositionChanged()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->trackedItem || !d->currentItem)
+ return;
+ if (d->moveReason == QDeclarativeListViewPrivate::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 QDeclarativeListView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QDeclarativeListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+ d->moveReason = QDeclarativeListViewPrivate::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) {
+ FxListItem *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<FxListItem*> added;
+ bool addedVisible = false;
+ FxListItem *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;
+ }
+ FxListItem *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--) {
+ FxListItem *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--) {
+ FxListItem *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;
+ }
+ FxListItem *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) {
+ FxListItem *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 QDeclarativeListView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QDeclarativeListView);
+ if (!isComponentComplete())
+ return;
+ d->moveReason = QDeclarativeListViewPrivate::Other;
+ d->updateUnrequestedIndexes();
+ d->itemCount -= count;
+
+ FxListItem *firstVisible = d->firstVisibleItem();
+ int preRemovedSize = 0;
+ bool removedVisible = false;
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxListItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItem *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.
+ 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();
+ update();
+ } else {
+ if (modelIndex < d->visibleIndex)
+ d->visibleIndex = modelIndex+1;
+ d->visibleIndex = qMax(qMin(d->visibleIndex, d->itemCount-1), 0);
+ }
+ }
+
+ d->updateSections();
+ emit countChanged();
+}
+
+void QDeclarativeListView::destroyRemoved()
+{
+ Q_D(QDeclarativeListView);
+ for (QList<FxListItem*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxListItem *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 QDeclarativeListView::itemsMoved(int from, int to, int count)
+{
+ Q_D(QDeclarativeListView);
+ if (!isComponentComplete())
+ return;
+ d->updateUnrequestedIndexes();
+
+ if (d->visibleItems.isEmpty()) {
+ refill();
+ return;
+ }
+
+ d->moveReason = QDeclarativeListViewPrivate::Other;
+ FxListItem *firstVisible = d->firstVisibleItem();
+ qreal firstItemPos = firstVisible->position();
+ QHash<int,FxListItem*> moved;
+ int moveBy = 0;
+
+ QList<FxListItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItem *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()) {
+ FxListItem *item = *it;
+ if (remaining && item->index >= to && item->index < to + count) {
+ // place items in the target position, reusing any existing items
+ FxListItem *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 (FxListItem *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();
+ FxListItem *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 QDeclarativeListView::itemsChanged(int, int)
+{
+ Q_D(QDeclarativeListView);
+ d->updateSections();
+ d->layout();
+}
+
+void QDeclarativeListView::modelReset()
+{
+ Q_D(QDeclarativeListView);
+ d->moveReason = QDeclarativeListViewPrivate::SetIndex;
+ d->regenerate();
+ if (d->highlight && d->currentItem) {
+ if (d->autoHighlight)
+ d->highlight->setPosition(d->currentItem->position());
+ d->updateTrackedItem();
+ }
+ d->moveReason = QDeclarativeListViewPrivate::Other;
+ emit countChanged();
+}
+
+void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeListView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(contentItem());
+ d->unrequestedItems.insert(item, index);
+ if (d->orient == QDeclarativeListView::Vertical) {
+ item->setY(d->positionAt(index));
+ } else {
+ if (d->isRightToLeft())
+ item->setX(-d->positionAt(index)-item->width());
+ else
+ item->setX(d->positionAt(index));
+ }
+ }
+}
+
+void QDeclarativeListView::destroyingItem(QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeListView);
+ d->unrequestedItems.remove(item);
+}
+
+void QDeclarativeListView::animStopped()
+{
+ Q_D(QDeclarativeListView);
+ d->bufferMode = QDeclarativeListViewPrivate::NoBuffer;
+ if (d->haveHighlightRange && d->highlightRange == QDeclarativeListView::StrictlyEnforceRange)
+ d->updateHighlight();
+}
+
+QDeclarativeListViewAttached *QDeclarativeListView::qmlAttachedProperties(QObject *obj)
+{
+ return new QDeclarativeListViewAttached(obj);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h
new file mode 100644
index 0000000000..3b12225588
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVELISTVIEW_H
+#define QDECLARATIVELISTVIEW_H
+
+#include "private/qdeclarativeflickable_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QDeclarativeViewSection : 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:
+ QDeclarativeViewSection(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 QDeclarativeVisualModel;
+class QDeclarativeListViewAttached;
+class QDeclarativeListViewPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeListView : public QDeclarativeFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeListView)
+
+ 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(QDeclarativeItem *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(QDeclarativeItem *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 REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
+ Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+ Q_PROPERTY(QDeclarativeViewSection *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:
+ QDeclarativeListView(QDeclarativeItem *parent=0);
+ ~QDeclarativeListView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QDeclarativeItem *currentItem();
+ QDeclarativeItem *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);
+
+ QDeclarativeViewSection *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 QDeclarativeListViewAttached *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 Q_REVISION(1) void positionViewAtBeginning();
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void countChanged();
+ void spacingChanged();
+ void orientationChanged();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) 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 bool event(QEvent *event);
+ 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, QDeclarativeItem *item);
+ void destroyingItem(QDeclarativeItem *item);
+ void animStopped();
+};
+
+class QDeclarativeListViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeListViewAttached(QObject *parent)
+ : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {}
+ ~QDeclarativeListViewAttached() {}
+
+ Q_PROPERTY(QDeclarativeListView *view READ view NOTIFY viewChanged)
+ QDeclarativeListView *view() { return m_view; }
+ void setView(QDeclarativeListView *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<QDeclarativeListView> 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(QDeclarativeListView, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QDeclarativeListView)
+QML_DECLARE_TYPE(QDeclarativeViewSection)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativeloader.cpp b/src/declarative/graphicsitems/qdeclarativeloader.cpp
new file mode 100644
index 0000000000..6c1f1be0c2
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeloader.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 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/qdeclarativeloader_p_p.h"
+
+#include <qdeclarativeinfo.h>
+#include <qdeclarativeengine_p.h>
+#include <qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeLoaderPrivate::QDeclarativeLoaderPrivate()
+ : item(0), component(0), ownComponent(false), updatingSize(false),
+ itemWidthValid(false), itemHeightValid(false)
+{
+}
+
+QDeclarativeLoaderPrivate::~QDeclarativeLoaderPrivate()
+{
+}
+
+void QDeclarativeLoaderPrivate::itemGeometryChanged(QDeclarativeItem *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);
+ }
+ QDeclarativeItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+void QDeclarativeLoaderPrivate::clear()
+{
+ if (ownComponent) {
+ component->deleteLater();
+ component = 0;
+ ownComponent = false;
+ }
+ source = QUrl();
+
+ if (item) {
+ if (QDeclarativeItem *qmlItem = qobject_cast<QDeclarativeItem*>(item)) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(qmlItem));
+ p->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ }
+
+ // We can't delete immediately because our item may have triggered
+ // the Loader to load a different item.
+ if (item->scene()) {
+ item->scene()->removeItem(item);
+ } else {
+ item->setParentItem(0);
+ item->setVisible(false);
+ }
+ item->deleteLater();
+ item = 0;
+ }
+}
+
+void QDeclarativeLoaderPrivate::initResize()
+{
+ Q_Q(QDeclarativeLoader);
+ if (QDeclarativeItem *qmlItem = qobject_cast<QDeclarativeItem*>(item)) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(qmlItem));
+ p->addItemChangeListener(this, QDeclarativeItemPrivate::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;
+ } else if (item && item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget*>(item);
+ widget->installEventFilter(q);
+ }
+ _q_updateSize();
+}
+
+/*!
+ \qmlclass Loader QDeclarativeLoader
+ \ingroup qml-utility-elements
+ \since 4.7
+ \inherits Item
+
+ \brief The Loader item allows dynamically loading an Item-based
+ subtree from a URL or Component.
+
+ Loader is used to dynamically load visual QML components. It can load a
+ QML file (using the \l source property) or a \l Component object (using
+ the \l sourceComponent property). It is useful for delaying the creation
+ of a component until it is required: for example, when a component should
+ be created on demand, or when a component should not be created
+ unnecessarily for performance reasons.
+
+ Here is a Loader that loads "Page1.qml" as a component when the
+ \l MouseArea is clicked:
+
+ \snippet doc/src/snippets/declarative/loader/simple.qml 0
+
+ The loaded item can be accessed using the \l item property.
+
+ If the \l source or \l sourceComponent changes, any previously instantiated
+ items are destroyed. Setting \l source to an empty string or setting
+ \l sourceComponent to \c undefined destroys the currently loaded item,
+ freeing resources and leaving the Loader empty.
+
+ \section2 Loader sizing behavior
+
+ Loader is like any other visual item and must be positioned and sized
+ accordingly to become visible.
+
+ \list
+ \o If an explicit size is not specified for the Loader, the Loader
+ is automatically resized to the size of the loaded item once the
+ component is loaded.
+ \o If the size of the Loader is specified explicitly by setting
+ the width, height or by anchoring, the loaded item will be resized
+ to the size of the Loader.
+ \endlist
+
+ In both scenarios the size of the item and the Loader are identical.
+ This ensures that anchoring to the Loader is equivalent to anchoring
+ to the loaded item.
+
+ \table
+ \row
+ \o sizeloader.qml
+ \o sizeitem.qml
+ \row
+ \o \snippet doc/src/snippets/declarative/loader/sizeloader.qml 0
+ \o \snippet doc/src/snippets/declarative/loader/sizeitem.qml 0
+ \row
+ \o The red rectangle will be sized to the size of the root item.
+ \o The red rectangle will be 50x50, centered in the root item.
+ \endtable
+
+
+ \section2 Receiving signals from loaded items
+
+ Any signals emitted from the loaded item can be received using the
+ \l Connections element. For example, the following \c application.qml
+ loads \c MyItem.qml, and is able to receive the \c message signal from
+ the loaded item through a \l Connections object:
+
+ \table
+ \row
+ \o application.qml
+ \o MyItem.qml
+ \row
+ \o \snippet doc/src/snippets/declarative/loader/connections.qml 0
+ \o \snippet doc/src/snippets/declarative/loader/MyItem.qml 0
+ \endtable
+
+ Alternatively, since \c MyItem.qml is loaded within the scope of the
+ Loader, it could also directly call any function defined in the Loader or
+ its parent \l Item.
+
+
+ \section2 Focus and key events
+
+ Loader is a focus scope. Its \l {Item::}{focus} property must be set to
+ \c true for any of its children to get the \e {active focus}. (See
+ \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page}
+ for more details.) Any key events received in the loaded item should likely
+ also be \l {KeyEvent::}{accepted} so they are not propagated to the Loader.
+
+ For example, the following \c application.qml loads \c KeyReader.qml when
+ the \l MouseArea is clicked. Notice the \l {Item::}{focus} property is
+ set to \c true for the Loader as well as the \l Item in the dynamically
+ loaded object:
+
+ \table
+ \row
+ \o application.qml
+ \o KeyReader.qml
+ \row
+ \o \snippet doc/src/snippets/declarative/loader/focus.qml 0
+ \o \snippet doc/src/snippets/declarative/loader/KeyReader.qml 0
+ \endtable
+
+ Once \c KeyReader.qml is loaded, it accepts key events and sets
+ \c event.accepted to \c true so that the event is not propagated to the
+ parent \l Rectangle.
+
+ \sa {dynamic-object-creation}{Dynamic Object Creation}
+*/
+
+QDeclarativeLoader::QDeclarativeLoader(QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(*(new QDeclarativeLoaderPrivate), parent)
+{
+ Q_D(QDeclarativeLoader);
+ d->flags |= QGraphicsItem::ItemIsFocusScope;
+}
+
+QDeclarativeLoader::~QDeclarativeLoader()
+{
+ Q_D(QDeclarativeLoader);
+ if (d->item) {
+ if (QDeclarativeItem *qmlItem = qobject_cast<QDeclarativeItem*>(d->item)) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(qmlItem));
+ p->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
+ }
+ }
+}
+
+/*!
+ \qmlproperty url Loader::source
+ This property holds the URL of the QML component to instantiate.
+
+ Note the QML component must be an \l{Item}-based component. The loader
+ cannot load non-visual components.
+
+ To unload the currently loaded item, set this property to an empty string,
+ or set \l sourceComponent to \c undefined. Setting \c source to a
+ new URL will also cause the item created by the previous URL to be unloaded.
+
+ \sa sourceComponent, status, progress
+*/
+QUrl QDeclarativeLoader::source() const
+{
+ Q_D(const QDeclarativeLoader);
+ return d->source;
+}
+
+void QDeclarativeLoader::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeLoader);
+ 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();
+}
+
+/*!
+ \qmlproperty Component Loader::sourceComponent
+ This property holds the \l{Component} to instantiate.
+
+ \qml
+ Item {
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader { sourceComponent: redSquare }
+ Loader { sourceComponent: redSquare; x: 10 }
+ }
+ \endqml
+
+ To unload the currently loaded item, set this property to an empty string
+ or \c undefined.
+
+ \sa source, progress
+*/
+
+QDeclarativeComponent *QDeclarativeLoader::sourceComponent() const
+{
+ Q_D(const QDeclarativeLoader);
+ return d->component;
+}
+
+void QDeclarativeLoader::setSourceComponent(QDeclarativeComponent *comp)
+{
+ Q_D(QDeclarativeLoader);
+ 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 QDeclarativeLoader::resetSourceComponent()
+{
+ setSourceComponent(0);
+}
+
+void QDeclarativeLoaderPrivate::load()
+{
+ Q_Q(QDeclarativeLoader);
+
+ 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 QDeclarativeLoaderPrivate::_q_sourceLoaded()
+{
+ Q_Q(QDeclarativeLoader);
+
+ 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<QGraphicsObject *>(obj);
+ if (item) {
+ QDeclarative_setParent_noEvent(ctxt, obj);
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+// item->setFocus(true);
+ initResize();
+ } else {
+ qmlInfo(q) << QDeclarativeLoader::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();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Loader::status
+
+ This property holds the status of QML loading. It can be one of:
+ \list
+ \o Loader.Null - no QML source has been set
+ \o Loader.Ready - the QML source has been loaded
+ \o Loader.Loading - the QML source is currently being loaded
+ \o Loader.Error - an error occurred while loading the QML source
+ \endlist
+
+ Use this status to provide an update or respond to the status change in some way.
+ For example, you could:
+
+ \list
+ \o Trigger a state change:
+ \qml
+ State { name: 'loaded'; when: loader.status == Loader.Ready }
+ \endqml
+
+ \o Implement an \c onStatusChanged signal handler:
+ \qml
+ Loader {
+ id: loader
+ onStatusChanged: if (loader.status == Loader.Ready) console.log('Loaded')
+ }
+ \endqml
+
+ \o Bind to the status value:
+ \qml
+ Text { text: loader.status == Loader.Ready ? 'Loaded' : 'Not loaded' }
+ \endqml
+ \endlist
+
+ Note that if the source is a local file, the status will initially be Ready (or Error). While
+ there will be no onStatusChanged signal in that case, the onLoaded will still be invoked.
+
+ \sa progress
+*/
+
+QDeclarativeLoader::Status QDeclarativeLoader::status() const
+{
+ Q_D(const QDeclarativeLoader);
+
+ if (d->component)
+ return static_cast<QDeclarativeLoader::Status>(d->component->status());
+
+ if (d->item)
+ return Ready;
+
+ return d->source.isEmpty() ? Null : Error;
+}
+
+void QDeclarativeLoader::componentComplete()
+{
+ Q_D(QDeclarativeLoader);
+
+ QDeclarativeItem::componentComplete();
+ d->load();
+}
+
+
+/*!
+ \qmlsignal Loader::onLoaded()
+
+ This handler is called when the \l status becomes \c Loader.Ready, or on successful
+ initial load.
+*/
+
+
+/*!
+\qmlproperty real Loader::progress
+
+This property holds the progress of loading QML data from the network, from
+0.0 (nothing loaded) to 1.0 (finished). Most QML files are quite small, so
+this value will rapidly change from 0 to 1.
+
+\sa status
+*/
+qreal QDeclarativeLoader::progress() const
+{
+ Q_D(const QDeclarativeLoader);
+
+ if (d->item)
+ return 1.0;
+
+ if (d->component)
+ return d->component->progress();
+
+ return 0.0;
+}
+
+void QDeclarativeLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
+{
+ Q_Q(QDeclarativeLoader);
+ if (!item || updatingSize)
+ return;
+
+ updatingSize = true;
+ if (QDeclarativeItem *qmlItem = qobject_cast<QDeclarativeItem*>(item)) {
+ if (!itemWidthValid)
+ q->setImplicitWidth(qmlItem->implicitWidth());
+ else
+ q->setImplicitWidth(qmlItem->width());
+ if (loaderGeometryChanged && q->widthValid())
+ qmlItem->setWidth(q->width());
+ if (!itemHeightValid)
+ q->setImplicitHeight(qmlItem->implicitHeight());
+ else
+ q->setImplicitHeight(qmlItem->height());
+ if (loaderGeometryChanged && q->heightValid())
+ qmlItem->setHeight(q->height());
+ } else if (item && item->isWidget()) {
+ QGraphicsWidget *widget = static_cast<QGraphicsWidget*>(item);
+ QSizeF widgetSize = widget->size();
+ q->setImplicitWidth(widgetSize.width());
+ if (loaderGeometryChanged && q->widthValid())
+ widgetSize.setWidth(q->width());
+ q->setImplicitHeight(widgetSize.height());
+ if (loaderGeometryChanged && q->heightValid())
+ widgetSize.setHeight(q->height());
+ if (widget->size() != widgetSize)
+ widget->resize(widgetSize);
+ }
+ updatingSize = false;
+}
+
+/*!
+ \qmlproperty Item Loader::item
+ This property holds the top-level item that is currently loaded.
+*/
+QGraphicsObject *QDeclarativeLoader::item() const
+{
+ Q_D(const QDeclarativeLoader);
+ return d->item;
+}
+
+void QDeclarativeLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeLoader);
+ if (newGeometry != oldGeometry) {
+ d->_q_updateSize();
+ }
+ QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QVariant QDeclarativeLoader::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ Q_D(QDeclarativeLoader);
+ if (change == ItemSceneHasChanged) {
+ if (d->item && d->item->isWidget()) {
+ d->item->removeEventFilter(this);
+ d->item->installEventFilter(this);
+ }
+ }
+ return QDeclarativeItem::itemChange(change, value);
+}
+
+bool QDeclarativeLoader::eventFilter(QObject *watched, QEvent *e)
+{
+ Q_D(QDeclarativeLoader);
+ if (watched == d->item && e->type() == QEvent::GraphicsSceneResize) {
+ if (d->item && d->item->isWidget())
+ d->_q_updateSize(false);
+ }
+ return QDeclarativeItem::eventFilter(watched, e);
+}
+
+#include <moc_qdeclarativeloader_p.cpp>
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativeloader_p.h b/src/declarative/graphicsitems/qdeclarativeloader_p.h
new file mode 100644
index 0000000000..96b883c330
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeloader_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELOADER_H
+#define QDECLARATIVELOADER_H
+
+#include "qdeclarativeimplicitsizeitem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeLoaderPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeLoader : public QDeclarativeImplicitSizeItem
+{
+ 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(QGraphicsObject *item READ item NOTIFY itemChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+
+public:
+ QDeclarativeLoader(QDeclarativeItem *parent=0);
+ virtual ~QDeclarativeLoader();
+
+ 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;
+
+ QGraphicsObject *item() const;
+
+Q_SIGNALS:
+ void itemChanged();
+ void sourceChanged();
+ void statusChanged();
+ void progressChanged();
+ void loaded();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+ bool eventFilter(QObject *watched, QEvent *e);
+ void componentComplete();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeLoader)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeLoader)
+ Q_PRIVATE_SLOT(d_func(), void _q_sourceLoaded())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeLoader)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELOADER_H
diff --git a/src/declarative/graphicsitems/qdeclarativeloader_p_p.h b/src/declarative/graphicsitems/qdeclarativeloader_p_p.h
new file mode 100644
index 0000000000..4593dfc070
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativeloader_p_p.h
@@ -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 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 QDECLARATIVELOADER_P_H
+#define QDECLARATIVELOADER_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/qdeclarativeloader_p.h"
+
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+#include "private/qdeclarativeitemchangelistener_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QDeclarativeLoaderPrivate : public QDeclarativeImplicitSizeItemPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativeLoader)
+
+public:
+ QDeclarativeLoaderPrivate();
+ ~QDeclarativeLoaderPrivate();
+
+ void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void clear();
+ void initResize();
+ void load();
+
+ QUrl source;
+ QGraphicsObject *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 // QDECLARATIVELOADER_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
new file mode 100644
index 0000000000..d4e7f7b01e
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
@@ -0,0 +1,978 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativemousearea_p.h"
+#include "private/qdeclarativemousearea_p_p.h"
+
+#include "private/qdeclarativeevents_p_p.h"
+
+#include <QGraphicsSceneMouseEvent>
+
+#include <float.h>
+
+QT_BEGIN_NAMESPACE
+static const int PressAndHoldDelay = 800;
+
+QDeclarativeDrag::QDeclarativeDrag(QObject *parent)
+: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
+_active(false), _filterChildren(false)
+{
+}
+
+QDeclarativeDrag::~QDeclarativeDrag()
+{
+}
+
+QGraphicsObject *QDeclarativeDrag::target() const
+{
+ return _target;
+}
+
+void QDeclarativeDrag::setTarget(QGraphicsObject *t)
+{
+ if (_target == t)
+ return;
+ _target = t;
+ emit targetChanged();
+}
+
+void QDeclarativeDrag::resetTarget()
+{
+ if (!_target)
+ return;
+ _target = 0;
+ emit targetChanged();
+}
+
+QDeclarativeDrag::Axis QDeclarativeDrag::axis() const
+{
+ return _axis;
+}
+
+void QDeclarativeDrag::setAxis(QDeclarativeDrag::Axis a)
+{
+ if (_axis == a)
+ return;
+ _axis = a;
+ emit axisChanged();
+}
+
+qreal QDeclarativeDrag::xmin() const
+{
+ return _xmin;
+}
+
+void QDeclarativeDrag::setXmin(qreal m)
+{
+ if (_xmin == m)
+ return;
+ _xmin = m;
+ emit minimumXChanged();
+}
+
+qreal QDeclarativeDrag::xmax() const
+{
+ return _xmax;
+}
+
+void QDeclarativeDrag::setXmax(qreal m)
+{
+ if (_xmax == m)
+ return;
+ _xmax = m;
+ emit maximumXChanged();
+}
+
+qreal QDeclarativeDrag::ymin() const
+{
+ return _ymin;
+}
+
+void QDeclarativeDrag::setYmin(qreal m)
+{
+ if (_ymin == m)
+ return;
+ _ymin = m;
+ emit minimumYChanged();
+}
+
+qreal QDeclarativeDrag::ymax() const
+{
+ return _ymax;
+}
+
+void QDeclarativeDrag::setYmax(qreal m)
+{
+ if (_ymax == m)
+ return;
+ _ymax = m;
+ emit maximumYChanged();
+}
+
+bool QDeclarativeDrag::active() const
+{
+ return _active;
+}
+
+void QDeclarativeDrag::setActive(bool drag)
+{
+ if (_active == drag)
+ return;
+ _active = drag;
+ emit activeChanged();
+}
+
+bool QDeclarativeDrag::filterChildren() const
+{
+ return _filterChildren;
+}
+
+void QDeclarativeDrag::setFilterChildren(bool filter)
+{
+ if (_filterChildren == filter)
+ return;
+ _filterChildren = filter;
+ emit filterChildrenChanged();
+}
+
+QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate()
+{
+ delete drag;
+}
+
+/*!
+ \qmlclass MouseArea QDeclarativeMouseArea
+ \ingroup qml-basic-interaction-elements
+ \since 4.7
+ \brief The MouseArea item enables simple mouse handling.
+ \inherits Item
+
+ A MouseArea is an invisible item that is typically used in conjunction with
+ a visible item in order to provide mouse handling for that item.
+ By effectively acting as a proxy, the logic for mouse handling can be
+ contained within a MouseArea item.
+
+ For basic key handling, see the \l{Keys}{Keys attached property}.
+
+ The \l enabled property is used to enable and disable mouse handling for
+ the proxied item. When disabled, the mouse area becomes transparent to
+ mouse events.
+
+ The \l pressed read-only property indicates whether or not the user is
+ holding down a mouse button over the mouse area. This property is often
+ used in bindings between properties in a user interface. The containsMouse
+ read-only property indicates the presence of the mouse cursor over the
+ mouse area but, by default, only when a mouse button is held down; see below
+ for further details.
+
+ Information about the mouse position and button clicks are provided via
+ signals for which event handler properties are defined. The most commonly
+ used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
+ onPressed, onReleased and onPressAndHold.
+
+ By default, MouseArea items only report mouse clicks and not changes to the
+ position of the mouse cursor. Setting the hoverEnabled property ensures that
+ handlers defined for onPositionChanged, onEntered and onExited are used and
+ that the containsMouse property is updated even when no mouse buttons are
+ pressed.
+
+ \section1 Example Usage
+
+ \div {class="float-right"}
+ \inlineimage qml-mousearea-snippet.png
+ \enddiv
+
+ The following example uses a MouseArea in a \l Rectangle that changes
+ the \l Rectangle color to red when clicked:
+
+ \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro
+
+ \clearfloat
+ Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
+ additional information about the mouse event, such as the position, button,
+ and any key modifiers.
+
+ Here is an extension of the previous example that produces a different
+ color when the area is right clicked:
+
+ \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended
+
+ \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
+*/
+
+/*!
+ \qmlsignal MouseArea::onEntered()
+
+ This handler is called when the mouse enters the mouse area.
+
+ By default the onEntered handler is only called while a button is
+ pressed. Setting hoverEnabled to true enables handling of
+ onEntered when no mouse button is pressed.
+
+ \sa hoverEnabled
+*/
+
+/*!
+ \qmlsignal MouseArea::onExited()
+
+ This handler is called when the mouse exists the mouse area.
+
+ By default the onExited handler is only called while a button is
+ pressed. Setting hoverEnabled to true enables handling of
+ onExited when no mouse button is pressed.
+
+ \sa hoverEnabled
+*/
+
+/*!
+ \qmlsignal MouseArea::onPositionChanged(MouseEvent mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
+ position, and any buttons currently pressed.
+
+ The \e accepted property of the MouseEvent parameter is ignored in this handler.
+
+ By default the onPositionChanged handler is only called while a button is
+ pressed. Setting hoverEnabled to true enables handling of
+ onPositionChanged when no mouse button is pressed.
+*/
+
+/*!
+ \qmlsignal MouseArea::onClicked(MouseEvent mouse)
+
+ This handler is called when there is a click. A click is defined as a press followed by a release,
+ both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
+ releasing is also considered a click).
+
+ The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click was held.
+
+ The \e accepted property of the MouseEvent parameter is ignored in this handler.
+*/
+
+/*!
+ \qmlsignal MouseArea::onPressed(MouseEvent mouse)
+
+ This handler is called when there is a press.
+ The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ position and which button was pressed.
+
+ The \e accepted property of the MouseEvent parameter determines whether this MouseArea
+ will handle the press and all future mouse events until release. The default is to accept
+ the event and not allow other MouseArea beneath this one to handle the event. If \e accepted
+ is set to false, no further events will be sent to this MouseArea until the button is next
+ pressed.
+*/
+
+/*!
+ \qmlsignal MouseArea::onReleased(MouseEvent mouse)
+
+ This handler is called when there is a release.
+ The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click was held.
+
+ The \e accepted property of the MouseEvent parameter is ignored in this handler.
+
+ \sa onCanceled
+*/
+
+/*!
+ \qmlsignal MouseArea::onPressAndHold(MouseEvent mouse)
+
+ This handler is called when there is a long press (currently 800ms).
+ The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ position of the press, and which button is pressed.
+
+ The \e accepted property of the MouseEvent parameter is ignored in this handler.
+*/
+
+/*!
+ \qmlsignal MouseArea::onDoubleClicked(MouseEvent mouse)
+
+ This handler is called when there is a double-click (a press followed by a release followed by a press).
+ The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click was held.
+
+ If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
+ in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
+ click; otherwise they are suppressed. The accepted property defaults to true.
+*/
+
+/*!
+ \qmlsignal MouseArea::onCanceled()
+
+ This handler is called when mouse events have been canceled, either because an event was not accepted, or
+ because another element stole the mouse event handling.
+
+ This signal is for advanced use: it is useful when there is more than one MouseArea
+ that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
+ case, if you execute some logic on the pressed signal and then start dragging, the
+ \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
+ the logic when the MouseArea has lost the mouse handling to the \l Flickable,
+ \c onCanceled should be used in addition to onReleased.
+*/
+
+QDeclarativeMouseArea::QDeclarativeMouseArea(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativeMouseAreaPrivate), parent)
+{
+ Q_D(QDeclarativeMouseArea);
+ d->init();
+}
+
+QDeclarativeMouseArea::~QDeclarativeMouseArea()
+{
+}
+
+/*!
+ \qmlproperty real MouseArea::mouseX
+ \qmlproperty real MouseArea::mouseY
+ These properties hold the coordinates of the mouse cursor.
+
+ If the hoverEnabled property is false then these properties will only be valid
+ while a button is pressed, and will remain valid as long as the button is held
+ down even if the mouse is moved outside the area.
+
+ By default, this property is false.
+
+ If hoverEnabled is true then these properties will be valid when:
+ \list
+ \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
+ \i a button is pressed and held, even if it has since moved out of the area.
+ \endlist
+
+ The coordinates are relative to the MouseArea.
+*/
+qreal QDeclarativeMouseArea::mouseX() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->lastPos.x();
+}
+
+qreal QDeclarativeMouseArea::mouseY() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->lastPos.y();
+}
+
+/*!
+ \qmlproperty bool MouseArea::enabled
+ This property holds whether the item accepts mouse events.
+
+ By default, this property is true.
+*/
+bool QDeclarativeMouseArea::isEnabled() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->absorb;
+}
+
+void QDeclarativeMouseArea::setEnabled(bool a)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool MouseArea::preventStealing
+ \since Quick 1.1
+ This property holds whether the mouse events may be stolen from this
+ MouseArea.
+
+ If a MouseArea is placed within an item that filters child mouse
+ events, such as Flickable, the mouse
+ events may be stolen from the MouseArea if a gesture is recognized
+ by the parent element, e.g. a flick gesture. If preventStealing is
+ set to true, no element will steal the mouse events.
+
+ Note that setting preventStealing to true once an element has started
+ stealing events will have no effect until the next press event.
+
+ By default this property is false.
+*/
+bool QDeclarativeMouseArea::preventStealing() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->preventStealing;
+}
+
+void QDeclarativeMouseArea::setPreventStealing(bool prevent)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (prevent != d->preventStealing) {
+ d->preventStealing = prevent;
+ setKeepMouseGrab(d->preventStealing && d->absorb);
+ emit preventStealingChanged();
+ }
+}
+
+/*!
+ \qmlproperty MouseButtons MouseArea::pressedButtons
+ This property holds the mouse buttons currently pressed.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MiddleButton
+ \endlist
+
+ The code below displays "right" when the right mouse buttons is pressed:
+
+ \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
+
+ \sa acceptedButtons
+*/
+Qt::MouseButtons QDeclarativeMouseArea::pressedButtons() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->lastButtons;
+}
+
+void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ d->moved = false;
+ d->stealMouse = d->preventStealing;
+ if (!d->absorb)
+ QDeclarativeItem::mousePressEvent(event);
+ else {
+ d->longPress = false;
+ d->saveEvent(event);
+ if (d->drag) {
+ d->dragX = drag()->axis() & QDeclarativeDrag::XAxis;
+ d->dragY = drag()->axis() & QDeclarativeDrag::YAxis;
+ }
+ if (d->drag)
+ d->drag->setActive(false);
+ setHovered(true);
+ d->startScene = event->scenePos();
+ // we should only start timer if pressAndHold is connected to.
+ if (d->isPressAndHoldConnected())
+ d->pressAndHoldTimer.start(PressAndHoldDelay, this);
+ setKeepMouseGrab(d->stealMouse);
+ event->setAccepted(setPressed(true));
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+ }
+}
+
+void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb) {
+ QDeclarativeItem::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;
+ }
+ QDeclarativeMouseEvent 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);
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+}
+
+
+void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QDeclarativeItem::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);
+ QGraphicsScene *s = scene();
+ if (s && s->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+
+ if(!event->isAccepted() && d->forwardToList.count())
+ d->forwardEvent(event);
+ }
+ d->doubleClick = false;
+}
+
+void QDeclarativeMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb) {
+ QDeclarativeItem::mouseDoubleClickEvent(event);
+ } else {
+ if (d->isDoubleClickConnected())
+ d->doubleClick = true;
+ d->saveEvent(event);
+ QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ me.setAccepted(d->isDoubleClickConnected());
+ emit this->doubleClicked(&me);
+ QDeclarativeItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QDeclarativeMouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb)
+ QDeclarativeItem::hoverEnterEvent(event);
+ else {
+ d->lastPos = event->pos();
+ setHovered(true);
+ QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
+ emit mousePositionChanged(&me);
+ }
+}
+
+void QDeclarativeMouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb) {
+ QDeclarativeItem::hoverMoveEvent(event);
+ } else {
+ d->lastPos = event->pos();
+ QDeclarativeMouseEvent 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 QDeclarativeMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb)
+ QDeclarativeItem::hoverLeaveEvent(event);
+ else
+ setHovered(false);
+}
+
+bool QDeclarativeMouseArea::sceneEvent(QEvent *event)
+{
+ bool rv = QDeclarativeItem::sceneEvent(event);
+ if (event->type() == QEvent::UngrabMouse) {
+ Q_D(QDeclarativeMouseArea);
+ 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();
+ }
+ }
+ }
+ return rv;
+}
+
+bool QDeclarativeMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
+
+ QGraphicsScene *s = scene();
+ QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->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 = qobject_cast<QDeclarativeItem*>(s->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 (s && s->mouseGrabberItem() == this)
+ ungrabMouse();
+ emit canceled();
+ emit pressedChanged();
+ if (d->hovered) {
+ d->hovered = false;
+ emit hoveredChanged();
+ }
+ }
+ }
+ return false;
+}
+
+bool QDeclarativeMouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
+ return QDeclarativeItem::sceneEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QDeclarativeItem::sceneEventFilter(i, e);
+}
+
+void QDeclarativeMouseArea::timerEvent(QTimerEvent *event)
+{
+ Q_D(QDeclarativeMouseArea);
+ 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;
+ QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ emit pressAndHold(&me);
+ }
+ }
+}
+
+void QDeclarativeMouseArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeMouseArea);
+ QDeclarativeItem::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);
+}
+
+QVariant QDeclarativeMouseArea::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ Q_D(QDeclarativeMouseArea);
+ switch (change) {
+ case ItemVisibleHasChanged:
+ if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
+ setHovered(!d->hovered);
+ break;
+ default:
+ break;
+ }
+
+ return QDeclarativeItem::itemChange(change, value);
+}
+
+/*!
+ \qmlproperty bool MouseArea::hoverEnabled
+ This property holds whether hover events are handled.
+
+ By default, mouse events are only handled in response to a button event, or when a button is
+ pressed. Hover enables handling of all mouse events even when no mouse button is
+ pressed.
+
+ This property affects the containsMouse property and the onEntered, onExited and
+ onPositionChanged signals.
+*/
+bool QDeclarativeMouseArea::hoverEnabled() const
+{
+ return acceptHoverEvents();
+}
+
+void QDeclarativeMouseArea::setHoverEnabled(bool h)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (h == acceptHoverEvents())
+ return;
+
+ setAcceptHoverEvents(h);
+ emit hoverEnabledChanged();
+ if (d->hovered != isUnderMouse())
+ setHovered(!d->hovered);
+}
+
+/*!
+ \qmlproperty bool MouseArea::containsMouse
+ This property holds whether the mouse is currently inside the mouse area.
+
+ \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
+ In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
+*/
+bool QDeclarativeMouseArea::hovered() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->hovered;
+}
+
+/*!
+ \qmlproperty bool MouseArea::pressed
+ This property holds whether the mouse area is currently pressed.
+*/
+bool QDeclarativeMouseArea::pressed() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->pressed;
+}
+
+void QDeclarativeMouseArea::setHovered(bool h)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (d->hovered != h) {
+ d->hovered = h;
+ emit hoveredChanged();
+ d->hovered ? emit entered() : emit exited();
+ }
+}
+
+/*!
+ \qmlproperty Qt::MouseButtons MouseArea::acceptedButtons
+ This property holds the mouse buttons that the mouse area reacts to.
+
+ The available buttons are:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MiddleButton
+ \endlist
+
+ To accept more than one button the flags can be combined with the
+ "|" (or) operator:
+
+ \code
+ MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
+ \endcode
+
+ The default value is \c Qt.LeftButton.
+*/
+Qt::MouseButtons QDeclarativeMouseArea::acceptedButtons() const
+{
+ return acceptedMouseButtons();
+}
+
+void QDeclarativeMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
+{
+ if (buttons != acceptedMouseButtons()) {
+ setAcceptedMouseButtons(buttons);
+ emit acceptedButtonsChanged();
+ }
+}
+
+bool QDeclarativeMouseArea::setPressed(bool p)
+{
+ Q_D(QDeclarativeMouseArea);
+ 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;
+ QDeclarativeMouseEvent 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)
+ emit clicked(&me);
+ }
+
+ return me.isAccepted();
+ }
+ return false;
+}
+
+QDeclarativeDrag *QDeclarativeMouseArea::drag()
+{
+ Q_D(QDeclarativeMouseArea);
+ if (!d->drag)
+ d->drag = new QDeclarativeDrag;
+ return d->drag;
+}
+
+/*!
+ \qmlproperty Item MouseArea::drag.target
+ \qmlproperty bool MouseArea::drag.active
+ \qmlproperty enumeration MouseArea::drag.axis
+ \qmlproperty real MouseArea::drag.minimumX
+ \qmlproperty real MouseArea::drag.maximumX
+ \qmlproperty real MouseArea::drag.minimumY
+ \qmlproperty real MouseArea::drag.maximumY
+ \qmlproperty bool MouseArea::drag.filterChildren
+
+ \c drag provides a convenient way to make an item draggable.
+
+ \list
+ \i \c drag.target specifies the id of the item to drag.
+ \i \c drag.active specifies if the target item is currently being dragged.
+ \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
+ \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
+ \endlist
+
+ The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
+ of the rectangle is reduced when it is dragged to the right.
+
+ \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
+
+ \note Items cannot be dragged if they are anchored for the requested
+ \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
+ for \c rect in the above example, it cannot be dragged along the X-axis.
+ This can be avoided by settng the anchor value to \c undefined in
+ an \l onPressed handler.
+
+ If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas. This
+ enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
+
+ \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
+
+*/
+
+QDeclarativeListProperty<QGraphicsObject> QDeclarativeMouseArea::forwardTo()
+{
+ Q_D(QDeclarativeMouseArea);
+ return d->forwardTo;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
new file mode 100644
index 0000000000..351d4dee10
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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 QDECLARATIVEMOUSEAREA_H
+#define QDECLARATIVEMOUSEAREA_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QDeclarativeDrag : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QGraphicsObject *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:
+ QDeclarativeDrag(QObject *parent=0);
+ ~QDeclarativeDrag();
+
+ QGraphicsObject *target() const;
+ void setTarget(QGraphicsObject *);
+ 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:
+ QGraphicsObject *_target;
+ Axis _axis;
+ qreal _xmin;
+ qreal _xmax;
+ qreal _ymin;
+ qreal _ymax;
+ bool _active : 1;
+ bool _filterChildren: 1;
+ Q_DISABLE_COPY(QDeclarativeDrag)
+};
+
+class QDeclarativeMouseEvent;
+class QDeclarativeMouseAreaPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeMouseArea : public QDeclarativeItem
+{
+ 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(QDeclarativeDrag *drag READ drag CONSTANT) //### add flicking to QDeclarativeDrag or add a QDeclarativeFlick ???
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1)
+ Q_PROPERTY(QDeclarativeListProperty<QGraphicsObject> forwardTo READ forwardTo);
+
+public:
+ QDeclarativeMouseArea(QDeclarativeItem *parent=0);
+ ~QDeclarativeMouseArea();
+
+ 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);
+
+ QDeclarativeDrag *drag();
+
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
+ QDeclarativeListProperty<QGraphicsObject> forwardTo();
+
+Q_SIGNALS:
+ void hoveredChanged();
+ void pressedChanged();
+ void enabledChanged();
+ void acceptedButtonsChanged();
+ void hoverEnabledChanged();
+ void positionChanged(QDeclarativeMouseEvent *mouse);
+ void mousePositionChanged(QDeclarativeMouseEvent *mouse);
+ Q_REVISION(1) void preventStealingChanged();
+
+ void pressed(QDeclarativeMouseEvent *mouse);
+ void pressAndHold(QDeclarativeMouseEvent *mouse);
+ void released(QDeclarativeMouseEvent *mouse);
+ void clicked(QDeclarativeMouseEvent *mouse);
+ void doubleClicked(QDeclarativeMouseEvent *mouse);
+ void entered();
+ void exited();
+ void canceled();
+
+protected:
+ void setHovered(bool);
+ bool setPressed(bool);
+
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ bool sceneEvent(QEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEventFilter(QGraphicsItem *i, QEvent *e);
+ void timerEvent(QTimerEvent *event);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant& value);
+
+private:
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeMouseArea)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeMouseArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeDrag)
+QML_DECLARE_TYPE(QDeclarativeMouseArea)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEMOUSEAREA_H
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
new file mode 100644
index 0000000000..7248c92777
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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 QDECLARATIVEMOUSEREGION_P_H
+#define QDECLARATIVEMOUSEREGION_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/qdeclarativeitem_p.h"
+
+#include <qdatetime.h>
+#include <qbasictimer.h>
+#include <qgraphicssceneevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeMouseAreaPrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeMouseArea)
+
+public:
+ QDeclarativeMouseAreaPrivate()
+ : absorb(true), hovered(false), pressed(false), longPress(false),
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
+ {
+ Q_Q(QDeclarativeMouseArea);
+ forwardTo = QDeclarativeListProperty<QGraphicsObject>(q, forwardToList);
+ }
+
+ ~QDeclarativeMouseAreaPrivate();
+
+ void init()
+ {
+ Q_Q(QDeclarativeMouseArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFiltersChildEvents(true);
+ }
+
+ void saveEvent(QGraphicsSceneMouseEvent *event) {
+ lastPos = event->pos();
+ lastScenePos = event->scenePos();
+ lastButton = event->button();
+ lastButtons = event->buttons();
+ lastModifiers = event->modifiers();
+ }
+
+ void forwardEvent(QGraphicsSceneMouseEvent* event)
+ {
+ Q_Q(QDeclarativeMouseArea);
+ for(int i=0; i < forwardToList.count(); i++){
+ event->setPos(forwardToList[i]->mapFromScene(event->scenePos()));
+ forwardToList[i]->scene()->sendEvent(forwardToList[i], event);
+ if(event->isAccepted())
+ break;
+ }
+ event->setPos(q->mapFromScene(event->scenePos()));
+ }
+
+ bool isPressAndHoldConnected() {
+ Q_Q(QDeclarativeMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QDeclarativeMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+ }
+
+ bool isDoubleClickConnected() {
+ Q_Q(QDeclarativeMouseArea);
+ static int idx = QObjectPrivate::get(q)->signalIndex("doubleClicked(QDeclarativeMouseEvent*)");
+ return QObjectPrivate::get(q)->isSignalConnected(idx);
+ }
+
+ 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;
+ QDeclarativeDrag *drag;
+ QPointF startScene;
+ qreal startX;
+ qreal startY;
+ QPointF lastPos;
+ QDeclarativeNullableValue<QPointF> lastScenePos;
+ Qt::MouseButton lastButton;
+ Qt::MouseButtons lastButtons;
+ Qt::KeyboardModifiers lastModifiers;
+ QBasicTimer pressAndHoldTimer;
+
+ QDeclarativeListProperty<QGraphicsObject> forwardTo;
+ QList<QGraphicsObject*> forwardToList;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEMOUSEREGION_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativepainteditem.cpp b/src/declarative/graphicsitems/qdeclarativepainteditem.cpp
new file mode 100644
index 0000000000..4327eae773
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepainteditem.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepainteditem_p.h"
+#include "private/qdeclarativepainteditem_p_p.h"
+
+#include <QDebug>
+#include <QPen>
+#include <QEvent>
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QPainter>
+#include <QPaintEngine>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativePaintedItem
+ \brief The QDeclarativePaintedItem class is an abstract base class for QDeclarativeView items that want cached painting.
+ \internal
+
+ This is a convenience class for implementing items that cache their painting.
+ The contents of the item are cached behind the scenes.
+ The dirtyCache() function should be called if the contents change to
+ ensure the cache is refreshed the next time painting occurs.
+
+ To subclass QDeclarativePaintedItem, you must reimplement drawContents() to draw
+ the contents of the item.
+*/
+
+/*!
+ \fn void QDeclarativePaintedItem::drawContents(QPainter *painter, const QRect &rect)
+
+ This function is called when the cache needs to be refreshed. When
+ sub-classing QDeclarativePaintedItem this function should be implemented so as to
+ paint the contents of the item using the given \a painter for the
+ area of the contents specified by \a rect.
+*/
+
+/*!
+ \property QDeclarativePaintedItem::contentsSize
+ \brief The size of the contents
+
+ The contents size is the size of the item in regards to how it is painted
+ using the drawContents() function. This is distinct from the size of the
+ item in regards to height() and width().
+*/
+
+// XXX bug in WebKit - can call repaintRequested and other cache-changing functions from within render!
+static int inpaint=0;
+static int inpaint_clearcache=0;
+
+extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
+
+/*!
+ Marks areas of the cache that intersect with the given \a rect as dirty and
+ in need of being refreshed.
+
+ \sa clearCache()
+*/
+void QDeclarativePaintedItem::dirtyCache(const QRect& rect)
+{
+ Q_D(QDeclarativePaintedItem);
+ QRect srect(qCeil(rect.x()*d->contentsScale),
+ qCeil(rect.y()*d->contentsScale),
+ qCeil(rect.width()*d->contentsScale),
+ qCeil(rect.height()*d->contentsScale));
+ for (int i=0; i < d->imagecache.count(); ) {
+ QDeclarativePaintedItemPrivate::ImageCacheItem *c = d->imagecache[i];
+ QRect isect = (c->area & srect) | c->dirty;
+ if (isect == c->area && !inpaint) {
+ delete d->imagecache.takeAt(i);
+ } else {
+ c->dirty = isect;
+ ++i;
+ }
+ }
+}
+
+/*!
+ Marks the entirety of the contents cache as dirty.
+
+ \sa dirtyCache()
+*/
+void QDeclarativePaintedItem::clearCache()
+{
+ if (inpaint) {
+ inpaint_clearcache=1;
+ return;
+ }
+ Q_D(QDeclarativePaintedItem);
+ qDeleteAll(d->imagecache);
+ d->imagecache.clear();
+}
+
+/*!
+ Returns the size of the contents.
+
+ \sa setContentsSize()
+*/
+QSize QDeclarativePaintedItem::contentsSize() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ return d->contentsSize;
+}
+
+/*!
+ Sets the size of the contents to the given \a size.
+
+ \sa contentsSize()
+*/
+void QDeclarativePaintedItem::setContentsSize(const QSize &size)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (d->contentsSize == size) return;
+ prepareGeometryChange();
+ d->contentsSize = size;
+ clearCache();
+ update();
+ emit contentsSizeChanged();
+}
+
+qreal QDeclarativePaintedItem::contentsScale() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ return d->contentsScale;
+}
+
+void QDeclarativePaintedItem::setContentsScale(qreal scale)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (d->contentsScale == scale) return;
+ d->contentsScale = scale;
+ clearCache();
+ update();
+ emit contentsScaleChanged();
+}
+
+
+/*!
+ Constructs a new QDeclarativePaintedItem with the given \a parent.
+*/
+QDeclarativePaintedItem::QDeclarativePaintedItem(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativePaintedItemPrivate), parent)
+{
+}
+
+/*!
+ \internal
+ Constructs a new QDeclarativePaintedItem with the given \a parent and
+ initialized private data member \a dd.
+*/
+QDeclarativePaintedItem::QDeclarativePaintedItem(QDeclarativePaintedItemPrivate &dd, QDeclarativeItem *parent)
+ : QDeclarativeItem(dd, parent)
+{
+}
+
+/*!
+ Destroys the image item.
+*/
+QDeclarativePaintedItem::~QDeclarativePaintedItem()
+{
+ clearCache();
+}
+
+void QDeclarativePaintedItem::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width() ||
+ newGeometry.height() != oldGeometry.height())
+ clearCache();
+
+ QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QVariant QDeclarativePaintedItem::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ if (change == ItemVisibleHasChanged)
+ clearCache();
+
+ return QDeclarativeItem::itemChange(change, value);
+}
+
+void QDeclarativePaintedItem::setCacheFrozen(bool frozen)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (d->cachefrozen == frozen)
+ return;
+ d->cachefrozen = frozen;
+ // XXX clear cache?
+}
+
+QRectF QDeclarativePaintedItem::boundingRect() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ qreal w = d->mWidth;
+ QSizeF sz = d->contentsSize * d->contentsScale;
+ if (w < sz.width())
+ w = sz.width();
+ qreal h = d->mHeight;
+ if (h < sz.height())
+ h = sz.height();
+ return QRectF(0.0,0.0,w,h);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativePaintedItem::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ Q_D(QDeclarativePaintedItem);
+ const QRect content = boundingRect().toRect();
+ if (content.width() <= 0 || content.height() <= 0)
+ return;
+
+ ++inpaint;
+
+ const QTransform &x = p->deviceTransform();
+ QTransform xinv = x.inverted();
+ QRegion effectiveClip;
+ QRegion sysClip = p->paintEngine()->systemClip();
+ if (xinv.type() <= QTransform::TxScale && sysClip.numRects() < 5) {
+ // simple transform, region gets no more complicated...
+ effectiveClip = xinv.map(sysClip);
+ } else {
+ // do not make complicated regions...
+ effectiveClip = xinv.mapRect(sysClip.boundingRect());
+ }
+
+ QRegion topaint = p->clipRegion();
+ if (topaint.isEmpty()) {
+ if (effectiveClip.isEmpty())
+ topaint = QRect(0,0,p->device()->width(),p->device()->height());
+ else
+ topaint = effectiveClip;
+ } else if (!effectiveClip.isEmpty()) {
+ topaint &= effectiveClip;
+ }
+
+ topaint &= content;
+ QRegion uncached(content);
+ p->setRenderHints(QPainter::SmoothPixmapTransform, d->smooth);
+
+ int cachesize=0;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ QRect area = d->imagecache[i]->area;
+ if (topaint.contains(area)) {
+ QRectF target(area.x(), area.y(), area.width(), area.height());
+ if (!d->cachefrozen) {
+ if (!d->imagecache[i]->dirty.isNull() && topaint.contains(d->imagecache[i]->dirty)) {
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter qp(&d->imagecache[i]->image);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+ qp.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, d->smoothCache);
+ qp.translate(-area.x(), -area.y());
+ qp.scale(d->contentsScale,d->contentsScale);
+ QRect clip = d->imagecache[i]->dirty;
+ QRect sclip(qFloor(clip.x()/d->contentsScale),
+ qFloor(clip.y()/d->contentsScale),
+ qCeil(clip.width()/d->contentsScale+clip.x()/d->contentsScale-qFloor(clip.x()/d->contentsScale)),
+ qCeil(clip.height()/d->contentsScale+clip.y()/d->contentsScale-qFloor(clip.y()/d->contentsScale)));
+ qp.setClipRect(sclip);
+ if (d->fillColor.isValid()){
+ if(d->fillColor.alpha() < 255){
+ // ### Might not work outside of raster paintengine
+ QPainter::CompositionMode prev = qp.compositionMode();
+ qp.setCompositionMode(QPainter::CompositionMode_Source);
+ qp.fillRect(sclip,d->fillColor);
+ qp.setCompositionMode(prev);
+ }else{
+ qp.fillRect(sclip,d->fillColor);
+ }
+ }
+ drawContents(&qp, sclip);
+ d->imagecache[i]->dirty = QRect();
+ }
+ }
+ p->drawPixmap(target.toRect(), d->imagecache[i]->image);
+ topaint -= area;
+ d->imagecache[i]->age=0;
+ } else {
+ d->imagecache[i]->age++;
+ }
+ cachesize += area.width()*area.height();
+ uncached -= area;
+ }
+
+ if (!topaint.isEmpty()) {
+ if (!d->cachefrozen) {
+ // Find a sensible larger area, otherwise will paint lots of tiny images.
+ QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128);
+ cachesize += biggerrect.width() * biggerrect.height();
+ while (d->imagecache.count() && cachesize > d->max_imagecache_size) {
+ int oldest=-1;
+ int age=-1;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ int a = d->imagecache[i]->age;
+ if (a > age) {
+ oldest = i;
+ age = a;
+ }
+ }
+ cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height();
+ uncached += d->imagecache[oldest]->area;
+ delete d->imagecache.takeAt(oldest);
+ }
+ const QRegion bigger = QRegion(biggerrect) & uncached;
+ const QVector<QRect> rects = bigger.rects();
+ for (int i = 0; i < rects.count(); ++i) {
+ const QRect &r = rects.at(i);
+ QPixmap img(r.size());
+ if (d->fillColor.isValid())
+ img.fill(d->fillColor);
+ {
+#ifdef Q_WS_MAC
+ bool oldSmooth = qt_applefontsmoothing_enabled;
+ qt_applefontsmoothing_enabled = false;
+#endif
+ QPainter qp(&img);
+#ifdef Q_WS_MAC
+ qt_applefontsmoothing_enabled = oldSmooth;
+#endif
+ qp.setRenderHints(QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform, d->smoothCache);
+
+ qp.translate(-r.x(),-r.y());
+ qp.scale(d->contentsScale,d->contentsScale);
+ QRect sclip(qFloor(r.x()/d->contentsScale),
+ qFloor(r.y()/d->contentsScale),
+ qCeil(r.width()/d->contentsScale+r.x()/d->contentsScale-qFloor(r.x()/d->contentsScale)),
+ qCeil(r.height()/d->contentsScale+r.y()/d->contentsScale-qFloor(r.y()/d->contentsScale)));
+ drawContents(&qp, sclip);
+ }
+ QDeclarativePaintedItemPrivate::ImageCacheItem *newitem = new QDeclarativePaintedItemPrivate::ImageCacheItem;
+ newitem->area = r;
+ newitem->image = img;
+ d->imagecache.append(newitem);
+ p->drawPixmap(r, newitem->image);
+ }
+ } else {
+ const QVector<QRect> rects = uncached.rects();
+ for (int i = 0; i < rects.count(); ++i)
+ p->fillRect(rects.at(i), Qt::lightGray);
+ }
+ }
+
+ if (inpaint_clearcache) {
+ clearCache();
+ inpaint_clearcache = 0;
+ }
+
+ --inpaint;
+}
+
+/*!
+ \qmlproperty int PaintedItem::pixelCacheSize
+
+ This property holds the maximum number of pixels of image cache to
+ allow. The default is 0.1 megapixels. The cache will not be larger
+ than the (unscaled) size of the WebView.
+*/
+/*!
+ \property QDeclarativePaintedItem::pixelCacheSize
+
+ The maximum number of pixels of image cache to allow. The default
+ is 0.1 megapixels. The cache will not be larger than the (unscaled)
+ size of the QDeclarativePaintedItem.
+*/
+int QDeclarativePaintedItem::pixelCacheSize() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ return d->max_imagecache_size;
+}
+
+void QDeclarativePaintedItem::setPixelCacheSize(int pixels)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (pixels < d->max_imagecache_size) {
+ int cachesize=0;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ QRect area = d->imagecache[i]->area;
+ cachesize += area.width()*area.height();
+ }
+ while (d->imagecache.count() && cachesize > pixels) {
+ int oldest=-1;
+ int age=-1;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ int a = d->imagecache[i]->age;
+ if (a > age) {
+ oldest = i;
+ age = a;
+ }
+ }
+ cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height();
+ delete d->imagecache.takeAt(oldest);
+ }
+ }
+ d->max_imagecache_size = pixels;
+}
+
+
+
+/*!
+ \property QDeclarativePaintedItem::fillColor
+
+ The color to be used to fill the item prior to calling drawContents().
+ By default, this is Qt::transparent.
+
+ Performance improvements can be achieved if subclasses call this with either an
+ invalid color (QColor()), or an appropriate solid color.
+*/
+void QDeclarativePaintedItem::setFillColor(const QColor& c)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (d->fillColor == c)
+ return;
+ d->fillColor = c;
+ emit fillColorChanged();
+ update();
+}
+
+QColor QDeclarativePaintedItem::fillColor() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ return d->fillColor;
+}
+
+/*!
+ \qmlproperty bool PaintedItem::smoothCache
+
+ Controls whether the cached tiles of which the item is composed are
+ rendered smoothly when they are generated.
+
+ This is in addition toe Item::smooth, which controls the smooth painting of
+ the already-painted cached tiles under transformation.
+*/
+bool QDeclarativePaintedItem::smoothCache() const
+{
+ Q_D(const QDeclarativePaintedItem);
+ return d->smoothCache;
+}
+
+void QDeclarativePaintedItem::setSmoothCache(bool on)
+{
+ Q_D(QDeclarativePaintedItem);
+ if (d->smoothCache != on) {
+ d->smoothCache = on;
+ clearCache();
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativepainteditem_p.h b/src/declarative/graphicsitems/qdeclarativepainteditem_p.h
new file mode 100644
index 0000000000..63f0a8ac7b
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepainteditem_p.h
@@ -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 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 QDECLARATIVEIMAGEITEM_H
+#define QDECLARATIVEIMAGEITEM_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePaintedItemPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePaintedItem : public QDeclarativeItem
+{
+ Q_OBJECT
+
+ 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)
+
+
+public:
+ QDeclarativePaintedItem(QDeclarativeItem *parent=0);
+ ~QDeclarativePaintedItem();
+
+ QSize contentsSize() const;
+ void setContentsSize(const QSize &);
+
+ 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&);
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+protected:
+ QDeclarativePaintedItem(QDeclarativePaintedItemPrivate &dd, QDeclarativeItem *parent);
+
+ virtual void drawContents(QPainter *p, const QRect &) = 0;
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual QVariant itemChange(GraphicsItemChange change,
+ const QVariant &value);
+
+ void setCacheFrozen(bool);
+ QRectF boundingRect() const;
+
+Q_SIGNALS:
+ void fillColorChanged();
+ void contentsSizeChanged();
+ void contentsScaleChanged();
+
+protected Q_SLOTS:
+ void dirtyCache(const QRect &);
+ void clearCache();
+
+private:
+ Q_DISABLE_COPY(QDeclarativePaintedItem)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativePaintedItem)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePaintedItem)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativepainteditem_p_p.h b/src/declarative/graphicsitems/qdeclarativepainteditem_p_p.h
new file mode 100644
index 0000000000..5cec9558db
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepainteditem_p_p.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 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 QDECLARATIVEIMAGEITEM_P_H
+#define QDECLARATIVEIMAGEITEM_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/qdeclarativeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePaintedItemPrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePaintedItem)
+
+public:
+ QDeclarativePaintedItemPrivate()
+ : max_imagecache_size(100000), contentsScale(1.0), fillColor(Qt::transparent), cachefrozen(false), smoothCache(true)
+ {
+ }
+
+ struct ImageCacheItem {
+ ImageCacheItem() : age(0) {}
+ ~ImageCacheItem() { }
+ int age;
+ QRect area;
+ QRect dirty; // one dirty area (allows optimization of common cases)
+ QPixmap image;
+ };
+
+ QList<ImageCacheItem*> imagecache;
+
+ int max_imagecache_size;
+ QSize contentsSize;
+ qreal contentsScale;
+ QColor fillColor;
+ bool cachefrozen;
+ bool smoothCache;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativepath.cpp b/src/declarative/graphicsitems/qdeclarativepath.cpp
new file mode 100644
index 0000000000..48e3f660c7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepath.cpp
@@ -0,0 +1,922 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepath_p.h"
+#include "private/qdeclarativepath_p_p.h"
+
+#include <QSet>
+#include <QTime>
+
+#include <private/qbezier_p.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass PathElement QDeclarativePathElement
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief PathElement is the base path type.
+
+ This type is the base for all path types. It cannot
+ be instantiated.
+
+ \sa Path, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+
+/*!
+ \qmlclass Path QDeclarativePath
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief A Path object defines a path for use by \l PathView.
+
+ A Path is composed of one or more path segments - PathLine, PathQuad,
+ PathCubic.
+
+ The spacing of the items along the Path can be adjusted via a
+ PathPercent object.
+
+ PathAttribute allows named attributes with values to be defined
+ along the path.
+
+ \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+QDeclarativePath::QDeclarativePath(QObject *parent)
+ : QObject(*(new QDeclarativePathPrivate), parent)
+{
+}
+
+QDeclarativePath::~QDeclarativePath()
+{
+}
+
+/*!
+ \qmlproperty real Path::startX
+ \qmlproperty real Path::startY
+ These properties hold the starting position of the path.
+*/
+qreal QDeclarativePath::startX() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startX;
+}
+
+void QDeclarativePath::setStartX(qreal x)
+{
+ Q_D(QDeclarativePath);
+ if (qFuzzyCompare(x, d->startX))
+ return;
+ d->startX = x;
+ emit startXChanged();
+ processPath();
+}
+
+qreal QDeclarativePath::startY() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startY;
+}
+
+void QDeclarativePath::setStartY(qreal y)
+{
+ Q_D(QDeclarativePath);
+ if (qFuzzyCompare(y, d->startY))
+ return;
+ d->startY = y;
+ emit startYChanged();
+ processPath();
+}
+
+/*!
+ \qmlproperty bool Path::closed
+ This property holds whether the start and end of the path are identical.
+*/
+bool QDeclarativePath::isClosed() const
+{
+ Q_D(const QDeclarativePath);
+ return d->closed;
+}
+
+/*!
+ \qmlproperty list<PathElement> Path::pathElements
+ This property holds the objects composing the path.
+
+ \default
+
+ A path can contain the following path objects:
+ \list
+ \i \l PathLine - a straight line to a given position.
+ \i \l PathQuad - a quadratic Bezier curve to a given position with a control point.
+ \i \l PathCubic - a cubic Bezier curve to a given position with two control points.
+ \i \l PathAttribute - an attribute at a given position in the path.
+ \i \l PathPercent - a way to spread out items along various segments of the path.
+ \endlist
+
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 2
+*/
+
+QDeclarativeListProperty<QDeclarativePathElement> QDeclarativePath::pathElements()
+{
+ Q_D(QDeclarativePath);
+ return QDeclarativeListProperty<QDeclarativePathElement>(this, d->_pathElements);
+}
+
+void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
+{
+ Q_D(QDeclarativePath);
+ if (!idx)
+ return;
+
+ qreal lastValue = 0;
+ qreal lastPercent = 0;
+ int search = idx - 1;
+ while(search >= 0) {
+ const AttributePoint &point = d->_attributePoints.at(search);
+ if (point.values.contains(name)) {
+ lastValue = point.values.value(name);
+ lastPercent = point.origpercent;
+ break;
+ }
+ --search;
+ }
+
+ ++search;
+
+ const AttributePoint &curPoint = d->_attributePoints.at(idx);
+
+ for (int ii = search; ii < idx; ++ii) {
+ AttributePoint &point = d->_attributePoints[ii];
+
+ qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
+ point.values.insert(name, val);
+ }
+}
+
+void QDeclarativePath::endpoint(const QString &name)
+{
+ Q_D(QDeclarativePath);
+ const AttributePoint &first = d->_attributePoints.first();
+ qreal val = first.values.value(name);
+ for (int ii = d->_attributePoints.count() - 1; ii >= 0; ii--) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if (point.values.contains(name)) {
+ for (int jj = ii + 1; jj < d->_attributePoints.count(); ++jj) {
+ AttributePoint &setPoint = d->_attributePoints[jj];
+ setPoint.values.insert(name, val);
+ }
+ return;
+ }
+ }
+}
+
+void QDeclarativePath::processPath()
+{
+ Q_D(QDeclarativePath);
+
+ if (!d->componentComplete)
+ return;
+
+ d->_pointCache.clear();
+ d->_attributePoints.clear();
+ d->_path = QPainterPath();
+
+ AttributePoint first;
+ for (int ii = 0; ii < d->_attributes.count(); ++ii)
+ first.values[d->_attributes.at(ii)] = 0;
+ d->_attributePoints << first;
+
+ d->_path.moveTo(d->startX, d->startY);
+
+ QDeclarativeCurve *lastCurve = 0;
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativeCurve *curve = qobject_cast<QDeclarativeCurve *>(pathElement)) {
+ curve->addToPath(d->_path);
+ AttributePoint p;
+ p.origpercent = d->_path.length();
+ d->_attributePoints << p;
+ lastCurve = curve;
+ } else if (QDeclarativePathAttribute *attribute = qobject_cast<QDeclarativePathAttribute *>(pathElement)) {
+ AttributePoint &point = d->_attributePoints.last();
+ point.values[attribute->name()] = attribute->value();
+ interpolate(d->_attributePoints.count() - 1, attribute->name(), attribute->value());
+ } else if (QDeclarativePathPercent *percent = qobject_cast<QDeclarativePathPercent *>(pathElement)) {
+ AttributePoint &point = d->_attributePoints.last();
+ point.values[QLatin1String("_qfx_percent")] = percent->value();
+ interpolate(d->_attributePoints.count() - 1, QLatin1String("_qfx_percent"), percent->value());
+ }
+ }
+
+ // Fixup end points
+ const AttributePoint &last = d->_attributePoints.last();
+ for (int ii = 0; ii < d->_attributes.count(); ++ii) {
+ if (!last.values.contains(d->_attributes.at(ii)))
+ endpoint(d->_attributes.at(ii));
+ }
+
+ // Adjust percent
+ qreal length = d->_path.length();
+ qreal prevpercent = 0;
+ qreal prevorigpercent = 0;
+ for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if (point.values.contains(QLatin1String("_qfx_percent"))) { //special string for QDeclarativePathPercent
+ if ( ii > 0) {
+ qreal scale = (d->_attributePoints[ii].origpercent/length - prevorigpercent) /
+ (point.values.value(QLatin1String("_qfx_percent"))-prevpercent);
+ d->_attributePoints[ii].scale = scale;
+ }
+ d->_attributePoints[ii].origpercent /= length;
+ d->_attributePoints[ii].percent = point.values.value(QLatin1String("_qfx_percent"));
+ prevorigpercent = d->_attributePoints[ii].origpercent;
+ prevpercent = d->_attributePoints[ii].percent;
+ } else {
+ d->_attributePoints[ii].origpercent /= length;
+ d->_attributePoints[ii].percent = d->_attributePoints[ii].origpercent;
+ }
+ }
+
+ d->closed = lastCurve && d->startX == lastCurve->x() && d->startY == lastCurve->y();
+
+ emit changed();
+}
+
+void QDeclarativePath::classBegin()
+{
+ Q_D(QDeclarativePath);
+ d->componentComplete = false;
+}
+
+void QDeclarativePath::componentComplete()
+{
+ Q_D(QDeclarativePath);
+ QSet<QString> attrs;
+ d->componentComplete = true;
+
+ // First gather up all the attributes
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativePathAttribute *attribute =
+ qobject_cast<QDeclarativePathAttribute *>(pathElement))
+ attrs.insert(attribute->name());
+ }
+ d->_attributes = attrs.toList();
+
+ processPath();
+
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements)
+ connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
+}
+
+QPainterPath QDeclarativePath::path() const
+{
+ Q_D(const QDeclarativePath);
+ return d->_path;
+}
+
+QStringList QDeclarativePath::attributes() const
+{
+ Q_D(const QDeclarativePath);
+ if (!d->componentComplete) {
+ QSet<QString> attrs;
+
+ // First gather up all the attributes
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativePathAttribute *attribute =
+ qobject_cast<QDeclarativePathAttribute *>(pathElement))
+ attrs.insert(attribute->name());
+ }
+ return attrs.toList();
+ }
+ return d->_attributes;
+}
+
+static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bezLength)
+{
+ const int lastElement = path.elementCount() - 1;
+ for (int i=*from; i <= lastElement; ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+
+ switch (e.type) {
+ case QPainterPath::MoveToElement:
+ break;
+ case QPainterPath::LineToElement:
+ {
+ QLineF line(path.elementAt(i-1), e);
+ *bezLength = line.length();
+ QPointF a = path.elementAt(i-1);
+ QPointF delta = e - a;
+ *from = i+1;
+ return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
+ }
+ case QPainterPath::CurveToElement:
+ {
+ QBezier b = QBezier::fromPoints(path.elementAt(i-1),
+ e,
+ path.elementAt(i+1),
+ path.elementAt(i+2));
+ *bezLength = b.length();
+ *from = i+3;
+ return b;
+ }
+ default:
+ break;
+ }
+ }
+ *from = lastElement;
+ *bezLength = 0;
+ return QBezier();
+}
+
+void QDeclarativePath::createPointCache() const
+{
+ Q_D(const QDeclarativePath);
+ qreal pathLength = d->_path.length();
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return;
+ // more points means less jitter between items as they move along the
+ // path, but takes longer to generate
+ const int points = qCeil(pathLength*5);
+ const int lastElement = d->_path.elementCount() - 1;
+ d->_pointCache.resize(points+1);
+
+ int currElement = 0;
+ qreal bezLength = 0;
+ QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
+ qreal currLength = bezLength;
+ qreal epc = currLength / pathLength;
+
+ for (int i = 0; i < d->_pointCache.size(); i++) {
+ //find which set we are in
+ qreal prevPercent = 0;
+ qreal prevOrigPercent = 0;
+ for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ qreal percent = qreal(i)/points;
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if (percent < point.percent || ii == d->_attributePoints.count() - 1) { //### || is special case for very last item
+ qreal elementPercent = (percent - prevPercent);
+
+ qreal spc = prevOrigPercent + elementPercent * point.scale;
+
+ while (spc > epc) {
+ if (currElement > lastElement)
+ break;
+ currBez = nextBezier(d->_path, &currElement, &bezLength);
+ if (bezLength == 0.0) {
+ currLength = pathLength;
+ epc = 1.0;
+ break;
+ }
+ currLength += bezLength;
+ epc = currLength / pathLength;
+ }
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+ d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ break;
+ }
+ prevOrigPercent = point.origpercent;
+ prevPercent = point.percent;
+ }
+ }
+}
+
+QPointF QDeclarativePath::pointAt(qreal p) const
+{
+ Q_D(const QDeclarativePath);
+ if (d->_pointCache.isEmpty()) {
+ createPointCache();
+ if (d->_pointCache.isEmpty())
+ return QPointF();
+ }
+ int idx = qRound(p*d->_pointCache.size());
+ if (idx >= d->_pointCache.size())
+ idx = d->_pointCache.size() - 1;
+ else if (idx < 0)
+ idx = 0;
+ return d->_pointCache.at(idx);
+}
+
+qreal QDeclarativePath::attributeAt(const QString &name, qreal percent) const
+{
+ Q_D(const QDeclarativePath);
+ if (percent < 0 || percent > 1)
+ return 0;
+
+ for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+
+ if (point.percent == percent) {
+ return point.values.value(name);
+ } else if (point.percent > percent) {
+ qreal lastValue =
+ ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
+ qreal lastPercent =
+ ii?(d->_attributePoints.at(ii - 1).percent):0;
+ qreal curValue = point.values.value(name);
+ qreal curPercent = point.percent;
+
+ return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+qreal QDeclarativeCurve::x() const
+{
+ return _x;
+}
+
+void QDeclarativeCurve::setX(qreal x)
+{
+ if (_x != x) {
+ _x = x;
+ emit xChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativeCurve::y() const
+{
+ return _y;
+}
+
+void QDeclarativeCurve::setY(qreal y)
+{
+ if (_y != y) {
+ _y = y;
+ emit yChanged();
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathAttribute QDeclarativePathAttribute
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathAttribute allows setting an attribute at a given position in a Path.
+
+ The PathAttribute object allows attributes consisting of a name and
+ a value to be specified for various points along a path. The
+ attributes are exposed to the delegate as
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Properties}.
+ The value of an attribute at any particular point along the path is interpolated
+ from the PathAttributes bounding that point.
+
+ The example below shows a path with the items scaled to 30% with
+ opacity 50% at the top of the path and scaled 100% with opacity
+ 100% at the bottom. Note the use of the PathView.iconScale and
+ PathView.iconOpacity attached properties to set the scale and opacity
+ of the delegate.
+
+ \table
+ \row
+ \o \image declarative-pathattribute.png
+ \o
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 0
+ (see the PathView documentation for the specification of ContactModel.qml
+ used for ContactModel above.)
+ \endtable
+
+
+ \sa Path
+*/
+
+/*!
+ \qmlproperty string PathAttribute::name
+ This property holds the name of the attribute to change.
+
+ This attribute will be available to the delegate as PathView.<name>
+
+ Note that using an existing Item property name such as "opacity" as an
+ attribute is allowed. This is because path attributes add a new
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
+ which in no way clashes with existing properties.
+*/
+
+/*!
+ the name of the attribute to change.
+*/
+
+QString QDeclarativePathAttribute::name() const
+{
+ return _name;
+}
+
+void QDeclarativePathAttribute::setName(const QString &name)
+{
+ if (_name == name)
+ return;
+ _name = name;
+ emit nameChanged();
+}
+
+/*!
+ \qmlproperty real PathAttribute::value
+ This property holds the value for the attribute.
+
+ The value specified can be used to influence the visual appearance
+ of an item along the path. For example, the following Path specifies
+ an attribute named \e itemRotation, which has the value \e 0 at the
+ beginning of the path, and the value 90 at the end of the path.
+
+ \qml
+ Path {
+ startX: 0
+ startY: 0
+ PathAttribute { name: "itemRotation"; value: 0 }
+ PathLine { x: 100; y: 100 }
+ PathAttribute { name: "itemRotation"; value: 90 }
+ }
+ \endqml
+
+ In our delegate, we can then bind the \e rotation property to the
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
+ \e PathView.itemRotation created for this attribute.
+
+ \qml
+ Rectangle {
+ width: 10; height: 10
+ rotation: PathView.itemRotation
+ }
+ \endqml
+
+ As each item is positioned along the path, it will be rotated accordingly:
+ an item at the beginning of the path with be not be rotated, an item at
+ the end of the path will be rotated 90 degrees, and an item mid-way along
+ the path will be rotated 45 degrees.
+*/
+
+/*!
+ the new value of the attribute.
+*/
+qreal QDeclarativePathAttribute::value() const
+{
+ return _value;
+}
+
+void QDeclarativePathAttribute::setValue(qreal value)
+{
+ if (_value != value) {
+ _value = value;
+ emit valueChanged();
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathLine QDeclarativePathLine
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathLine defines a straight line.
+
+ The example below creates a path consisting of a straight line from
+ 0,100 to 200,100:
+
+ \qml
+ Path {
+ startX: 0; startY: 100
+ PathLine { x: 200; y: 100 }
+ }
+ \endqml
+
+ \sa Path, PathQuad, PathCubic
+*/
+
+/*!
+ \qmlproperty real PathLine::x
+ \qmlproperty real PathLine::y
+
+ Defines the end point of the line.
+*/
+
+void QDeclarativePathLine::addToPath(QPainterPath &path)
+{
+ path.lineTo(x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathQuad QDeclarativePathQuad
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathQuad defines a quadratic Bezier curve with a control point.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathquad.png
+ \o
+ \qml
+ Path {
+ startX: 0; startY: 0
+ PathQuad { x: 200; y: 0; controlX: 100; controlY: 150 }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathCubic, PathLine
+*/
+
+/*!
+ \qmlproperty real PathQuad::x
+ \qmlproperty real PathQuad::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real PathQuad::controlX
+ \qmlproperty real PathQuad::controlY
+
+ Defines the position of the control point.
+*/
+
+/*!
+ the x position of the control point.
+*/
+qreal QDeclarativePathQuad::controlX() const
+{
+ return _controlX;
+}
+
+void QDeclarativePathQuad::setControlX(qreal x)
+{
+ if (_controlX != x) {
+ _controlX = x;
+ emit controlXChanged();
+ emit changed();
+ }
+}
+
+
+/*!
+ the y position of the control point.
+*/
+qreal QDeclarativePathQuad::controlY() const
+{
+ return _controlY;
+}
+
+void QDeclarativePathQuad::setControlY(qreal y)
+{
+ if (_controlY != y) {
+ _controlY = y;
+ emit controlYChanged();
+ emit changed();
+ }
+}
+
+void QDeclarativePathQuad::addToPath(QPainterPath &path)
+{
+ path.quadTo(controlX(), controlY(), x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathCubic QDeclarativePathCubic
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathCubic defines a cubic Bezier curve with two control points.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathcubic.png
+ \o
+ \qml
+ Path {
+ startX: 20; startY: 0
+ PathCubic {
+ x: 180; y: 0
+ control1X: -10; control1Y: 90
+ control2X: 210; control2Y: 90
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathQuad, PathLine
+*/
+
+/*!
+ \qmlproperty real PathCubic::x
+ \qmlproperty real PathCubic::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real PathCubic::control1X
+ \qmlproperty real PathCubic::control1Y
+
+ Defines the position of the first control point.
+*/
+qreal QDeclarativePathCubic::control1X() const
+{
+ return _control1X;
+}
+
+void QDeclarativePathCubic::setControl1X(qreal x)
+{
+ if (_control1X != x) {
+ _control1X = x;
+ emit control1XChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathCubic::control1Y() const
+{
+ return _control1Y;
+}
+
+void QDeclarativePathCubic::setControl1Y(qreal y)
+{
+ if (_control1Y != y) {
+ _control1Y = y;
+ emit control1YChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty real PathCubic::control2X
+ \qmlproperty real PathCubic::control2Y
+
+ Defines the position of the second control point.
+*/
+qreal QDeclarativePathCubic::control2X() const
+{
+ return _control2X;
+}
+
+void QDeclarativePathCubic::setControl2X(qreal x)
+{
+ if (_control2X != x) {
+ _control2X = x;
+ emit control2XChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathCubic::control2Y() const
+{
+ return _control2Y;
+}
+
+void QDeclarativePathCubic::setControl2Y(qreal y)
+{
+ if (_control2Y != y) {
+ _control2Y = y;
+ emit control2YChanged();
+ emit changed();
+ }
+}
+
+void QDeclarativePathCubic::addToPath(QPainterPath &path)
+{
+ path.cubicTo(control1X(), control1Y(), control2X(), control2Y(), x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathPercent QDeclarativePathPercent
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathPercent manipulates the way a path is interpreted.
+
+ PathPercent allows you to manipulate the spacing between items on a
+ PathView's path. You can use it to bunch together items on part of
+ the path, and spread them out on other parts of the path.
+
+ The examples below show the normal distrubution of items along a path
+ compared to a distribution which places 50% of the items along the
+ PathLine section of the path.
+ \table
+ \row
+ \o \image declarative-nopercent.png
+ \o
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathLine { x: 150; y: 80 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-percent.png
+ \o
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathPercent { value: 0.25 }
+ PathLine { x: 150; y: 80 }
+ PathPercent { value: 0.75 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ PathPercent { value: 1 }
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa Path
+*/
+
+/*!
+ \qmlproperty real PathPercent::value
+ The proporation of items that should be laid out up to this point.
+
+ This value should always be higher than the last value specified
+ by a PathPercent at a previous position in the Path.
+
+ In the following example we have a Path made up of three PathLines.
+ Normally, the items of the PathView would be laid out equally along
+ this path, with an equal number of items per line segment. PathPercent
+ allows us to specify that the first and third lines should each hold
+ 10% of the laid out items, while the second line should hold the remaining
+ 80%.
+
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 0; startY: 0
+ PathLine { x:100; y: 0; }
+ PathPercent { value: 0.1 }
+ PathLine { x: 100; y: 100 }
+ PathPercent { value: 0.9 }
+ PathLine { x: 100; y: 0 }
+ PathPercent { value: 1 }
+ }
+ }
+ \endqml
+*/
+
+qreal QDeclarativePathPercent::value() const
+{
+ return _value;
+}
+
+void QDeclarativePathPercent::setValue(qreal value)
+{
+ if (_value != value) {
+ _value = value;
+ emit valueChanged();
+ emit changed();
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativepath_p.h b/src/declarative/graphicsitems/qdeclarativepath_p.h
new file mode 100644
index 0000000000..5210aebb47
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepath_p.h
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPATH_H
+#define QDECLARATIVEPATH_H
+
+#include "qdeclarativeitem.h"
+
+#include <qdeclarative.h>
+
+#include <QtCore/QObject>
+#include <QtGui/QPainterPath>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_AUTOTEST_EXPORT QDeclarativePathElement : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativePathElement(QObject *parent=0) : QObject(parent) {}
+Q_SIGNALS:
+ void changed();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathAttribute : public QDeclarativePathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+public:
+ QDeclarativePathAttribute(QObject *parent=0) : QDeclarativePathElement(parent), _value(0) {}
+
+
+ QString name() const;
+ void setName(const QString &name);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+Q_SIGNALS:
+ void nameChanged();
+ void valueChanged();
+
+private:
+ QString _name;
+ qreal _value;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeCurve : public QDeclarativePathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+public:
+ QDeclarativeCurve(QObject *parent=0) : QDeclarativePathElement(parent), _x(0), _y(0) {}
+
+ qreal x() const;
+ void setX(qreal x);
+
+ qreal y() const;
+ void setY(qreal y);
+
+ virtual void addToPath(QPainterPath &) {}
+
+Q_SIGNALS:
+ void xChanged();
+ void yChanged();
+
+private:
+ qreal _x;
+ qreal _y;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathLine : public QDeclarativeCurve
+{
+ Q_OBJECT
+public:
+ QDeclarativePathLine(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ void addToPath(QPainterPath &path);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathQuad : public QDeclarativeCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal controlX READ controlX WRITE setControlX NOTIFY controlXChanged)
+ Q_PROPERTY(qreal controlY READ controlY WRITE setControlY NOTIFY controlYChanged)
+public:
+ QDeclarativePathQuad(QObject *parent=0) : QDeclarativeCurve(parent), _controlX(0), _controlY(0) {}
+
+ qreal controlX() const;
+ void setControlX(qreal x);
+
+ qreal controlY() const;
+ void setControlY(qreal y);
+
+ void addToPath(QPainterPath &path);
+
+Q_SIGNALS:
+ void controlXChanged();
+ void controlYChanged();
+
+private:
+ qreal _controlX;
+ qreal _controlY;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathCubic : public QDeclarativeCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal control1X READ control1X WRITE setControl1X NOTIFY control1XChanged)
+ Q_PROPERTY(qreal control1Y READ control1Y WRITE setControl1Y NOTIFY control1YChanged)
+ Q_PROPERTY(qreal control2X READ control2X WRITE setControl2X NOTIFY control2XChanged)
+ Q_PROPERTY(qreal control2Y READ control2Y WRITE setControl2Y NOTIFY control2YChanged)
+public:
+ QDeclarativePathCubic(QObject *parent=0) : QDeclarativeCurve(parent), _control1X(0), _control1Y(0), _control2X(0), _control2Y(0) {}
+
+ qreal control1X() const;
+ void setControl1X(qreal x);
+
+ qreal control1Y() const;
+ void setControl1Y(qreal y);
+
+ qreal control2X() const;
+ void setControl2X(qreal x);
+
+ qreal control2Y() const;
+ void setControl2Y(qreal y);
+
+ void addToPath(QPainterPath &path);
+
+Q_SIGNALS:
+ void control1XChanged();
+ void control1YChanged();
+ void control2XChanged();
+ void control2YChanged();
+
+private:
+ qreal _control1X;
+ qreal _control1Y;
+ qreal _control2X;
+ qreal _control2Y;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathPercent : public QDeclarativePathElement
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+public:
+ QDeclarativePathPercent(QObject *parent=0) : QDeclarativePathElement(parent) {}
+
+ qreal value() const;
+ void setValue(qreal value);
+
+signals:
+ void valueChanged();
+
+private:
+ qreal _value;
+};
+
+class QDeclarativePathPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePath : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativePathElement> pathElements READ pathElements)
+ Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged)
+ Q_PROPERTY(qreal startY READ startY WRITE setStartY NOTIFY startYChanged)
+ Q_PROPERTY(bool closed READ isClosed NOTIFY changed)
+ Q_CLASSINFO("DefaultProperty", "pathElements")
+ Q_INTERFACES(QDeclarativeParserStatus)
+public:
+ QDeclarativePath(QObject *parent=0);
+ ~QDeclarativePath();
+
+ QDeclarativeListProperty<QDeclarativePathElement> pathElements();
+
+ qreal startX() const;
+ void setStartX(qreal x);
+
+ qreal startY() const;
+ void setStartY(qreal y);
+
+ bool isClosed() const;
+
+ QPainterPath path() const;
+ QStringList attributes() const;
+ qreal attributeAt(const QString &, qreal) const;
+ QPointF pointAt(qreal) const;
+
+Q_SIGNALS:
+ void changed();
+ void startXChanged();
+ void startYChanged();
+
+protected:
+ virtual void componentComplete();
+ virtual void classBegin();
+
+private Q_SLOTS:
+ void processPath();
+
+private:
+ struct AttributePoint {
+ AttributePoint() : percent(0), scale(1), origpercent(0) {}
+ AttributePoint(const AttributePoint &other)
+ : percent(other.percent), scale(other.scale), origpercent(other.origpercent), values(other.values) {}
+ AttributePoint &operator=(const AttributePoint &other) {
+ percent = other.percent; scale = other.scale; origpercent = other.origpercent; values = other.values; return *this;
+ }
+ qreal percent; //massaged percent along the painter path
+ qreal scale;
+ qreal origpercent; //'real' percent along the painter path
+ QHash<QString, qreal> values;
+ };
+
+ void interpolate(int idx, const QString &name, qreal value);
+ void endpoint(const QString &name);
+ void createPointCache() const;
+
+private:
+ Q_DISABLE_COPY(QDeclarativePath)
+ Q_DECLARE_PRIVATE(QDeclarativePath)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePathElement)
+QML_DECLARE_TYPE(QDeclarativePathAttribute)
+QML_DECLARE_TYPE(QDeclarativeCurve)
+QML_DECLARE_TYPE(QDeclarativePathLine)
+QML_DECLARE_TYPE(QDeclarativePathQuad)
+QML_DECLARE_TYPE(QDeclarativePathCubic)
+QML_DECLARE_TYPE(QDeclarativePathPercent)
+QML_DECLARE_TYPE(QDeclarativePath)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPATH_H
diff --git a/src/declarative/graphicsitems/qdeclarativepath_p_p.h b/src/declarative/graphicsitems/qdeclarativepath_p_p.h
new file mode 100644
index 0000000000..0e52a1ed87
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepath_p_p.h
@@ -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 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 QDECLARATIVEPATH_P_H
+#define QDECLARATIVEPATH_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/qdeclarativepath_p.h"
+
+#include <qdeclarative.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+class QDeclarativePathPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePath)
+
+public:
+ QDeclarativePathPrivate() : startX(0), startY(0), closed(false), componentComplete(true) { }
+
+ QPainterPath _path;
+ QList<QDeclarativePathElement*> _pathElements;
+ mutable QVector<QPointF> _pointCache;
+ QList<QDeclarativePath::AttributePoint> _attributePoints;
+ QStringList _attributes;
+ int startX;
+ int startY;
+ bool closed;
+ bool componentComplete;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp
new file mode 100644
index 0000000000..aed849bd39
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp
@@ -0,0 +1,1724 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepathview_p.h"
+#include "private/qdeclarativepathview_p_p.h"
+
+#include <qdeclarativestate_p.h>
+#include <qdeclarativeopenmetaobject_p.h>
+#include <QDebug>
+#include <QEvent>
+#include <qlistmodelinterface_p.h>
+#include <QGraphicsSceneEvent>
+
+#include <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;
+
+QDeclarativePathViewAttached::QDeclarativePathViewAttached(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);
+ }
+}
+
+QDeclarativePathViewAttached::~QDeclarativePathViewAttached()
+{
+}
+
+QVariant QDeclarativePathViewAttached::value(const QByteArray &name) const
+{
+ return m_metaobject->value(name);
+}
+void QDeclarativePathViewAttached::setValue(const QByteArray &name, const QVariant &val)
+{
+ m_metaobject->setValue(name, val);
+}
+
+
+void QDeclarativePathViewPrivate::init()
+{
+ Q_Q(QDeclarativePathView);
+ offset = 0;
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QGraphicsItem::ItemIsFocusScope);
+ q->setFiltersChildEvents(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 = QDeclarativePathView::staticMetaObject.indexOfSlot("movementEnding()");
+ }
+ QMetaObject::connect(&tl, timelineCompletedIdx,
+ q, movementEndingIdx, Qt::DirectConnection);
+}
+
+QDeclarativeItem *QDeclarativePathViewPrivate::getItem(int modelIndex)
+{
+ Q_Q(QDeclarativePathView);
+ requestedIndex = modelIndex;
+ QDeclarativeItem *item = model->item(modelIndex, false);
+ if (item) {
+ if (!attType) {
+ // pre-create one metatype to share with all attached objects
+ attType = new QDeclarativeOpenMetaObjectType(&QDeclarativePathViewAttached::staticMetaObject, qmlEngine(q));
+ foreach(const QString &attr, path->attributes())
+ attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = attType;
+ QDeclarativePathViewAttached *att = static_cast<QDeclarativePathViewAttached *>(qmlAttachedPropertiesObject<QDeclarativePathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = q;
+ att->setOnPath(true);
+ }
+ item->setParentItem(q);
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ }
+ requestedIndex = -1;
+ return item;
+}
+
+void QDeclarativePathViewPrivate::releaseItem(QDeclarativeItem *item)
+{
+ if (!item || !model)
+ return;
+ QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
+ itemPrivate->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ if (model->release(item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->setOnPath(false);
+ }
+}
+
+QDeclarativePathViewAttached *QDeclarativePathViewPrivate::attached(QDeclarativeItem *item)
+{
+ return static_cast<QDeclarativePathViewAttached *>(qmlAttachedPropertiesObject<QDeclarativePathView>(item, false));
+}
+
+void QDeclarativePathViewPrivate::clear()
+{
+ for (int i=0; i<items.count(); i++){
+ QDeclarativeItem *p = items[i];
+ releaseItem(p);
+ }
+ items.clear();
+}
+
+void QDeclarativePathViewPrivate::updateMappedRange()
+{
+ if (model && pathItems != -1 && pathItems < modelCount)
+ mappedRange = qreal(pathItems)/modelCount;
+ else
+ mappedRange = 1.0;
+}
+
+qreal QDeclarativePathViewPrivate::positionOfIndex(qreal index) const
+{
+ qreal pos = -1.0;
+
+ if (model && index >= 0 && index < modelCount) {
+ qreal start = 0.0;
+ if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::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 QDeclarativePathViewPrivate::createHighlight()
+{
+ Q_Q(QDeclarativePathView);
+ if (!q->isComponentComplete())
+ return;
+
+ bool changed = false;
+ if (highlightItem) {
+ delete highlightItem;
+ highlightItem = 0;
+ changed = true;
+ }
+
+ QDeclarativeItem *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<QDeclarativeItem *>(nobj);
+ if (!item)
+ delete nobj;
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QDeclarativeItem;
+ }
+ if (item) {
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+ highlightItem = item;
+ changed = true;
+ }
+ if (changed)
+ emit q->highlightItemChanged();
+}
+
+void QDeclarativePathViewPrivate::updateHighlight()
+{
+ Q_Q(QDeclarativePathView);
+ if (!q->isComponentComplete() || !isValid())
+ return;
+ if (highlightItem) {
+ if (haveHighlightRange && highlightRangeMode == QDeclarativePathView::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 QDeclarativePathViewPrivate::setHighlightPosition(qreal pos)
+{
+ if (pos != highlightPosition) {
+ qreal start = 0.0;
+ qreal end = 1.0;
+ if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::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 (QDeclarativePathViewAttached *att = attached(highlightItem))
+ att->setOnPath(pathPos != -1.0);
+ }
+}
+
+void QDeclarativePathView::pathUpdated()
+{
+ Q_D(QDeclarativePathView);
+ QList<QDeclarativeItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ QDeclarativeItem *item = *it;
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->m_percent = -1;
+ ++it;
+ }
+ refill();
+}
+
+void QDeclarativePathViewPrivate::updateItem(QDeclarativeItem *item, qreal percent)
+{
+ if (QDeclarativePathViewAttached *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 QDeclarativePathViewPrivate::regenerate()
+{
+ Q_Q(QDeclarativePathView);
+ if (!q->isComponentComplete())
+ return;
+
+ clear();
+
+ if (!isValid())
+ return;
+
+ firstIndex = -1;
+ updateMappedRange();
+ q->refill();
+}
+
+/*!
+ \qmlclass PathView QDeclarativePathView
+ \ingroup qml-view-elements
+ \since 4.7
+ \brief The PathView element lays out model-provided items on a path.
+ \inherits Item
+
+ A PathView displays data from models created from built-in QML elements like ListModel
+ and XmlListModel, or custom model classes defined in C++ that inherit from
+ QAbstractListModel.
+
+ The view has a \l model, which defines the data to be displayed, and
+ a \l delegate, which defines how the data should be displayed.
+ The \l delegate is instantiated for each item on the \l path.
+ The items may be flicked to move them along the path.
+
+ For example, if there is a simple list model defined in a file \c ContactModel.qml like this:
+
+ \snippet doc/src/snippets/declarative/pathview/ContactModel.qml 0
+
+ This data can be represented as a PathView, like this:
+
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 0
+
+ \image pathview.gif
+
+ (Note the above example uses PathAttribute to scale and modify the
+ opacity of the items as they rotate. This additional code can be seen in the
+ PathAttribute documentation.)
+
+ PathView does not automatically handle keyboard navigation. This is because
+ the keys to use for navigation will depend upon the shape of the path. Navigation
+ can be added quite simply by setting \c focus to \c true and calling
+ \l decrementCurrentIndex() or \l incrementCurrentIndex(), for example to navigate
+ using the left and right arrow keys:
+
+ \qml
+ PathView {
+ // ...
+ focus: true
+ Keys.onLeftPressed: decrementCurrentIndex()
+ Keys.onRightPressed: incrementCurrentIndex()
+ }
+ \endqml
+
+ The path view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
+
+ Delegates are instantiated as needed and may be destroyed at any time.
+ State should \e never be stored in a delegate.
+
+ PathView attaches a number of properties to the root item of the delegate, for example
+ \c {PathView.isCurrentItem}. In the following example, the root delegate item can access
+ this attached property directly as \c PathView.isCurrentItem, while the child
+ \c nameText object must refer to this property as \c wrapper.PathView.isCurrentItem.
+
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 1
+
+ \bold Note that views do not enable \e clip automatically. If the view
+ is not clipped by another item or the screen, it will be necessary
+ to set \e {clip: true} in order to have the out of view items clipped
+ nicely.
+
+ \sa Path, {declarative/modelviews/pathview}{PathView example}
+*/
+
+QDeclarativePathView::QDeclarativePathView(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativePathViewPrivate), parent)
+{
+ Q_D(QDeclarativePathView);
+ d->init();
+}
+
+QDeclarativePathView::~QDeclarativePathView()
+{
+ Q_D(QDeclarativePathView);
+ d->clear();
+ if (d->attType)
+ d->attType->release();
+ if (d->ownModel)
+ delete d->model;
+}
+
+/*!
+ \qmlattachedproperty PathView PathView::view
+ This attached property holds the view that manages this delegate instance.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty bool PathView::onPath
+ This attached property holds whether the item is currently on the path.
+
+ If a pathItemCount has been set, it is possible that some items may
+ be instantiated, but not considered to be currently on the path.
+ Usually, these items would be set invisible, for example:
+
+ \qml
+ Component {
+ Rectangle {
+ visible: PathView.onPath
+ // ...
+ }
+ }
+ \endqml
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty bool PathView::isCurrentItem
+ This attached property is true if this delegate is the current item; otherwise false.
+
+ It is attached to each instance of the delegate.
+
+ This property may be used to adjust the appearance of the current item.
+
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 1
+*/
+
+/*!
+ \qmlproperty model PathView::model
+ This property holds the model providing data for the view.
+
+ The model provides a set of data that is used to create the items for the view.
+ For large or dynamic datasets the model is usually provided by a C++ model object.
+ Models can also be created directly in QML, using the ListModel element.
+
+ \sa {qmlmodels}{Data Models}
+*/
+QVariant QDeclarativePathView::model() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->modelVariant;
+}
+
+void QDeclarativePathView::setModel(const QVariant &model)
+{
+ Q_D(QDeclarativePathView);
+ 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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ for (int i=0; i<d->items.count(); i++){
+ QDeclarativeItem *p = d->items[i];
+ d->model->release(p);
+ }
+ d->items.clear();
+ }
+
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QDeclarativeVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ 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();
+}
+
+/*!
+ \qmlproperty int PathView::count
+ This property holds the number of items in the model.
+*/
+int QDeclarativePathView::count() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->model ? d->modelCount : 0;
+}
+
+/*!
+ \qmlproperty Path PathView::path
+ This property holds the path used to lay out the items.
+ For more information see the \l Path documentation.
+*/
+QDeclarativePath *QDeclarativePathView::path() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->path;
+}
+
+void QDeclarativePathView::setPath(QDeclarativePath *path)
+{
+ Q_D(QDeclarativePathView);
+ 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();
+}
+
+/*!
+ \qmlproperty int PathView::currentIndex
+ This property holds the index of the current item.
+*/
+int QDeclarativePathView::currentIndex() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->currentIndex;
+}
+
+void QDeclarativePathView::setCurrentIndex(int idx)
+{
+ Q_D(QDeclarativePathView);
+ 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 (QDeclarativeItem *item = d->items.at(itemIndex)) {
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ }
+ d->currentItem = 0;
+ d->moveReason = QDeclarativePathViewPrivate::SetIndex;
+ d->currentIndex = idx;
+ if (d->modelCount) {
+ if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::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 (QDeclarativePathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ d->currentItemOffset = d->positionOfIndex(d->currentIndex);
+ d->updateHighlight();
+ }
+ emit currentIndexChanged();
+ }
+}
+
+/*!
+ \qmlmethod PathView::incrementCurrentIndex()
+
+ Increments the current index.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativePathView::incrementCurrentIndex()
+{
+ Q_D(QDeclarativePathView);
+ d->moveDirection = QDeclarativePathViewPrivate::Positive;
+ setCurrentIndex(currentIndex()+1);
+}
+
+
+/*!
+ \qmlmethod PathView::decrementCurrentIndex()
+
+ Decrements the current index.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+void QDeclarativePathView::decrementCurrentIndex()
+{
+ Q_D(QDeclarativePathView);
+ if (d->model && d->modelCount) {
+ int idx = currentIndex()-1;
+ if (idx < 0)
+ idx = d->modelCount - 1;
+ d->moveDirection = QDeclarativePathViewPrivate::Negative;
+ setCurrentIndex(idx);
+ }
+}
+
+/*!
+ \qmlproperty real PathView::offset
+
+ The offset specifies how far along the path the items are from their initial positions.
+ This is a real number that ranges from 0.0 to the count of items in the model.
+*/
+qreal QDeclarativePathView::offset() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->offset;
+}
+
+void QDeclarativePathView::setOffset(qreal offset)
+{
+ Q_D(QDeclarativePathView);
+ d->setOffset(offset);
+ d->updateCurrent();
+}
+
+void QDeclarativePathViewPrivate::setOffset(qreal o)
+{
+ Q_Q(QDeclarativePathView);
+ 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 QDeclarativePathViewPrivate::setAdjustedOffset(qreal o)
+{
+ setOffset(o+offsetAdj);
+}
+
+/*!
+ \qmlproperty Component PathView::highlight
+ This property holds the component to use as the highlight.
+
+ An instance of the highlight component will be created for each view.
+ The geometry of the resultant component instance will be managed by the view
+ so as to stay with the current item.
+
+ The below example demonstrates how to make a simple highlight. Note the use
+ of the \l{PathView::onPath}{PathView.onPath} attached property to ensure that
+ the highlight is hidden when flicked away from the path.
+
+ \qml
+ Component {
+ Rectangle {
+ visible: PathView.onPath
+ // ...
+ }
+ }
+ \endqml
+
+ \sa highlightItem, highlightRangeMode
+*/
+
+QDeclarativeComponent *QDeclarativePathView::highlight() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightComponent;
+}
+
+void QDeclarativePathView::setHighlight(QDeclarativeComponent *highlight)
+{
+ Q_D(QDeclarativePathView);
+ if (highlight != d->highlightComponent) {
+ d->highlightComponent = highlight;
+ d->createHighlight();
+ d->updateHighlight();
+ emit highlightChanged();
+ }
+}
+
+/*!
+ \qmlproperty Item PathView::highlightItem
+
+ \c highlightItem holds the highlight item, which was created
+ from the \l highlight component.
+
+ \sa highlight
+*/
+QDeclarativeItem *QDeclarativePathView::highlightItem()
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightItem;
+}
+/*!
+ \qmlproperty real PathView::preferredHighlightBegin
+ \qmlproperty real PathView::preferredHighlightEnd
+ \qmlproperty enumeration PathView::highlightRangeMode
+
+ These properties set the preferred range of the highlight (current item)
+ within the view. The preferred values must be in the range 0.0-1.0.
+
+ If highlightRangeMode is set to \e PathView.NoHighlightRange
+
+ If highlightRangeMode is set to \e PathView.ApplyRange the view will
+ attempt to maintain the highlight within the range, however
+ the highlight can move outside of the range at the ends of the path
+ or due to a mouse interaction.
+
+ If highlightRangeMode is set to \e PathView.StrictlyEnforceRange the highlight will never
+ move outside of the range. This means that the current item will change
+ if a keyboard or mouse action would cause the highlight to move
+ outside of the range.
+
+ Note that this is the correct way to influence where the
+ current item ends up when the view moves. For example, if you want the
+ currently selected item to be in the middle of the path, then set the
+ highlight range to be 0.5,0.5 and highlightRangeMode to PathView.StrictlyEnforceRange.
+ Then, when the path scrolls,
+ the currently selected item will be the item at that position. This also applies to
+ when the currently selected item changes - it will scroll to within the preferred
+ highlight range. Furthermore, the behaviour of the current item index will occur
+ whether or not a highlight exists.
+
+ The default value is \e PathView.StrictlyEnforceRange.
+
+ Note that a valid range requires preferredHighlightEnd to be greater
+ than or equal to preferredHighlightBegin.
+*/
+qreal QDeclarativePathView::preferredHighlightBegin() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightRangeStart;
+}
+
+void QDeclarativePathView::setPreferredHighlightBegin(qreal start)
+{
+ Q_D(QDeclarativePathView);
+ 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 QDeclarativePathView::preferredHighlightEnd() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightRangeEnd;
+}
+
+void QDeclarativePathView::setPreferredHighlightEnd(qreal end)
+{
+ Q_D(QDeclarativePathView);
+ 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();
+}
+
+QDeclarativePathView::HighlightRangeMode QDeclarativePathView::highlightRangeMode() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightRangeMode;
+}
+
+void QDeclarativePathView::setHighlightRangeMode(HighlightRangeMode mode)
+{
+ Q_D(QDeclarativePathView);
+ if (d->highlightRangeMode == mode)
+ return;
+ d->highlightRangeMode = mode;
+ d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ emit highlightRangeModeChanged();
+}
+
+
+/*!
+ \qmlproperty int PathView::highlightMoveDuration
+ This property holds the move animation duration of the highlight delegate.
+
+ If the highlightRangeMode is StrictlyEnforceRange then this property
+ determines the speed that the items move along the path.
+
+ The default value for the duration is 300ms.
+*/
+int QDeclarativePathView::highlightMoveDuration() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->highlightMoveDuration;
+}
+
+void QDeclarativePathView::setHighlightMoveDuration(int duration)
+{
+ Q_D(QDeclarativePathView);
+ if (d->highlightMoveDuration == duration)
+ return;
+ d->highlightMoveDuration = duration;
+ emit highlightMoveDurationChanged();
+}
+
+/*!
+ \qmlproperty real PathView::dragMargin
+ This property holds the maximum distance from the path that initiate mouse dragging.
+
+ By default the path can only be dragged by clicking on an item. If
+ dragMargin is greater than zero, a drag can be initiated by clicking
+ within dragMargin pixels of the path.
+*/
+qreal QDeclarativePathView::dragMargin() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->dragMargin;
+}
+
+void QDeclarativePathView::setDragMargin(qreal dragMargin)
+{
+ Q_D(QDeclarativePathView);
+ if (d->dragMargin == dragMargin)
+ return;
+ d->dragMargin = dragMargin;
+ emit dragMarginChanged();
+}
+
+/*!
+ \qmlproperty real PathView::flickDeceleration
+ This property holds the rate at which a flick will decelerate.
+
+ The default is 100.
+*/
+qreal QDeclarativePathView::flickDeceleration() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->deceleration;
+}
+
+void QDeclarativePathView::setFlickDeceleration(qreal dec)
+{
+ Q_D(QDeclarativePathView);
+ if (d->deceleration == dec)
+ return;
+ d->deceleration = dec;
+ emit flickDecelerationChanged();
+}
+
+/*!
+ \qmlproperty bool PathView::interactive
+
+ A user cannot drag or flick a PathView that is not interactive.
+
+ This property is useful for temporarily disabling flicking. This allows
+ special interaction with PathView's children.
+*/
+bool QDeclarativePathView::isInteractive() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->interactive;
+}
+
+void QDeclarativePathView::setInteractive(bool interactive)
+{
+ Q_D(QDeclarativePathView);
+ if (interactive != d->interactive) {
+ d->interactive = interactive;
+ if (!interactive)
+ d->tl.clear();
+ emit interactiveChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool PathView::moving
+
+ This property holds whether the view is currently moving
+ due to the user either dragging or flicking the view.
+*/
+bool QDeclarativePathView::isMoving() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->moving;
+}
+
+/*!
+ \qmlproperty bool PathView::flicking
+
+ This property holds whether the view is currently moving
+ due to the user flicking the view.
+*/
+bool QDeclarativePathView::isFlicking() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->flicking;
+}
+
+/*!
+ \qmlsignal PathView::onMovementStarted()
+
+ This handler is called when the view begins moving due to user
+ interaction.
+*/
+
+/*!
+ \qmlsignal PathView::onMovementEnded()
+
+ This handler is called when the view stops moving due to user
+ interaction. If a flick was generated, this handler will
+ be triggered once the flick stops. If a flick was not
+ generated, the handler will be triggered when the
+ user stops dragging - i.e. a mouse or touch release.
+*/
+
+/*!
+ \qmlsignal PathView::onFlickStarted()
+
+ This handler is called when the view is flicked. A flick
+ starts from the point that the mouse or touch is released,
+ while still in motion.
+*/
+
+/*!
+ \qmlsignal PathView::onFlickEnded()
+
+ This handler is called when the view stops moving due to a flick.
+*/
+
+/*!
+ \qmlproperty Component PathView::delegate
+
+ The delegate provides a template defining each item instantiated by the view.
+ The index is exposed as an accessible \c index property. Properties of the
+ model are also available depending upon the type of \l {qmlmodels}{Data Model}.
+
+ The number of elements in the delegate has a direct effect on the
+ flicking performance of the view when pathItemCount is specified. If at all possible, place functionality
+ that is not needed for the normal display of the delegate in a \l Loader which
+ can load additional elements when needed.
+
+ Note that the PathView will layout the items based on the size of the root
+ item in the delegate.
+
+ Here is an example delegate:
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 1
+*/
+QDeclarativeComponent *QDeclarativePathView::delegate() const
+{
+ Q_D(const QDeclarativePathView);
+ if (d->model) {
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QDeclarativePathView::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QDeclarativePathView);
+ if (delegate == this->delegate())
+ return;
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ d->modelCount = dataModel->count();
+ d->regenerate();
+ emit delegateChanged();
+ }
+}
+
+/*!
+ \qmlproperty int PathView::pathItemCount
+ This property holds the number of items visible on the path at any one time.
+*/
+int QDeclarativePathView::pathItemCount() const
+{
+ Q_D(const QDeclarativePathView);
+ return d->pathItems;
+}
+
+void QDeclarativePathView::setPathItemCount(int i)
+{
+ Q_D(QDeclarativePathView);
+ if (i == d->pathItems)
+ return;
+ if (i < 1)
+ i = 1;
+ d->pathItems = i;
+ d->updateMappedRange();
+ if (d->isValid() && isComponentComplete()) {
+ d->regenerate();
+ }
+ emit pathItemCountChanged();
+}
+
+QPointF QDeclarativePathViewPrivate::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 QDeclarativePathView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePathView);
+ if (d->interactive) {
+ d->handleMousePressEvent(event);
+ event->accept();
+ } else {
+ QDeclarativeItem::mousePressEvent(event);
+ }
+}
+
+void QDeclarativePathViewPrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativePathView);
+ 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)->mapToScene(rect).boundingRect();
+ 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;
+ QDeclarativeItemPrivate::start(lastPosTime);
+ tl.clear();
+}
+
+void QDeclarativePathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePathView);
+ if (d->interactive) {
+ d->handleMouseMoveEvent(event);
+ if (d->stealMouse)
+ setKeepMouseGrab(true);
+ event->accept();
+ } else {
+ QDeclarativeItem::mouseMoveEvent(event);
+ }
+}
+
+void QDeclarativePathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QDeclarativePathView);
+ 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 = QDeclarativePathViewPrivate::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 = QDeclarativeItemPrivate::restart(lastPosTime);
+ lastDist = diff;
+ startPc = newPc;
+ }
+ if (!moving) {
+ moving = true;
+ emit q->movingChanged();
+ emit q->movementStarted();
+ }
+ }
+}
+
+void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePathView);
+ if (d->interactive) {
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+ ungrabMouse();
+ } else {
+ QDeclarativeItem::mouseReleaseEvent(event);
+ }
+}
+
+void QDeclarativePathViewPrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_Q(QDeclarativePathView);
+ stealMouse = false;
+ q->setKeepMouseGrab(false);
+ if (!interactive || !lastPosTime.isValid())
+ return;
+
+ qreal elapsed = qreal(lastElapsed + QDeclarativeItemPrivate::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 == QDeclarativePathView::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 QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePathView);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
+ QGraphicsScene *s = scene();
+ QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->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 = qobject_cast<QDeclarativeItem*>(s->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 QDeclarativePathView::sceneEventFilter(QGraphicsItem *i, QEvent *e)
+{
+ Q_D(QDeclarativePathView);
+ if (!isVisible() || !d->interactive)
+ return QDeclarativeItem::sceneEventFilter(i, e);
+
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ default:
+ break;
+ }
+
+ return QDeclarativeItem::sceneEventFilter(i, e);
+}
+
+bool QDeclarativePathView::event(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+ refill();
+ return true;
+ }
+
+ return QDeclarativeItem::event(event);
+}
+
+void QDeclarativePathView::componentComplete()
+{
+ Q_D(QDeclarativePathView);
+ QDeclarativeItem::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 QDeclarativePathView::refill()
+{
+ Q_D(QDeclarativePathView);
+ 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<QDeclarativeItem*>::iterator it = d->items.begin();
+ while (it != d->items.end()) {
+ qreal pos = d->positionOfIndex(idx);
+ QDeclarativeItem *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 != QDeclarativePathView::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;
+ QDeclarativeItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZValue(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QDeclarativePathViewAttached *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;
+ QDeclarativeItem *item = d->getItem(idx);
+ if (d->model->completePending())
+ item->setZValue(idx+1);
+ if (d->currentIndex == idx) {
+ item->setFocus(true);
+ if (QDeclarativePathViewAttached *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 == QDeclarativePathView::StrictlyEnforceRange) {
+ d->updateItem(d->highlightItem, d->highlightRangeStart);
+ if (QDeclarativePathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(true);
+ } else if (d->highlightItem && d->moveReason != QDeclarativePathViewPrivate::SetIndex) {
+ d->updateItem(d->highlightItem, d->currentItemOffset);
+ if (QDeclarativePathViewAttached *att = d->attached(d->highlightItem))
+ att->setOnPath(currentVisible);
+ }
+ while (d->itemCache.count())
+ d->releaseItem(d->itemCache.takeLast());
+}
+
+void QDeclarativePathView::itemsInserted(int modelIndex, int count)
+{
+ //XXX support animated insertion
+ Q_D(QDeclarativePathView);
+ 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 QDeclarativePathView::itemsRemoved(int modelIndex, int count)
+{
+ //XXX support animated removal
+ Q_D(QDeclarativePathView);
+ 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 (QDeclarativePathViewAttached *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);
+ update();
+ } else {
+ d->regenerate();
+ d->updateCurrent();
+ if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange)
+ d->snapToCurrent();
+ }
+ if (changedOffset)
+ emit offsetChanged();
+ if (currentChanged)
+ emit currentIndexChanged();
+ emit countChanged();
+}
+
+void QDeclarativePathView::itemsMoved(int /*from*/, int /*to*/, int /*count*/)
+{
+ Q_D(QDeclarativePathView);
+ if (!d->isValid() || !isComponentComplete())
+ return;
+
+ QList<QDeclarativeItem *> 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 QDeclarativePathView::modelReset()
+{
+ Q_D(QDeclarativePathView);
+ d->modelCount = d->model->count();
+ d->regenerate();
+ emit countChanged();
+}
+
+void QDeclarativePathView::createdItem(int index, QDeclarativeItem *item)
+{
+ Q_D(QDeclarativePathView);
+ if (d->requestedIndex != index) {
+ if (!d->attType) {
+ // pre-create one metatype to share with all attached objects
+ d->attType = new QDeclarativeOpenMetaObjectType(&QDeclarativePathViewAttached::staticMetaObject, qmlEngine(this));
+ foreach(const QString &attr, d->path->attributes())
+ d->attType->createProperty(attr.toUtf8());
+ }
+ qPathViewAttachedType = d->attType;
+ QDeclarativePathViewAttached *att = static_cast<QDeclarativePathViewAttached *>(qmlAttachedPropertiesObject<QDeclarativePathView>(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 QDeclarativePathView::destroyingItem(QDeclarativeItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QDeclarativePathView::ticked()
+{
+ Q_D(QDeclarativePathView);
+ d->updateCurrent();
+}
+
+void QDeclarativePathView::movementEnding()
+{
+ Q_D(QDeclarativePathView);
+ 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 QDeclarativePathViewPrivate::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 QDeclarativePathViewPrivate::updateCurrent()
+{
+ Q_Q(QDeclarativePathView);
+ if (moveReason != Mouse)
+ return;
+ if (!modelCount || !haveHighlightRange || highlightRangeMode != QDeclarativePathView::StrictlyEnforceRange)
+ return;
+
+ int idx = calcCurrentIndex();
+ if (model && idx != currentIndex) {
+ int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ if (QDeclarativeItem *item = items.at(itemIndex)) {
+ if (QDeclarativePathViewAttached *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 (QDeclarativePathViewAttached *att = attached(currentItem))
+ att->setIsCurrentItem(true);
+ }
+ emit q->currentIndexChanged();
+ }
+}
+
+void QDeclarativePathViewPrivate::fixOffsetCallback(void *d)
+{
+ ((QDeclarativePathViewPrivate *)d)->fixOffset();
+}
+
+void QDeclarativePathViewPrivate::fixOffset()
+{
+ Q_Q(QDeclarativePathView);
+ if (model && items.count()) {
+ if (haveHighlightRange && highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) {
+ int curr = calcCurrentIndex();
+ if (curr != currentIndex)
+ q->setCurrentIndex(curr);
+ else
+ snapToCurrent();
+ }
+ }
+}
+
+void QDeclarativePathViewPrivate::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;
+}
+
+QDeclarativePathViewAttached *QDeclarativePathView::qmlAttachedProperties(QObject *obj)
+{
+ return new QDeclarativePathViewAttached(obj);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/graphicsitems/qdeclarativepathview_p.h b/src/declarative/graphicsitems/qdeclarativepathview_p.h
new file mode 100644
index 0000000000..fdd535d722
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepathview_p.h
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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_H
+#define QDECLARATIVEPATHVIEW_H
+
+#include "qdeclarativeitem.h"
+#include "private/qdeclarativepath_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePathViewPrivate;
+class QDeclarativePathViewAttached;
+class Q_AUTOTEST_EXPORT QDeclarativePathView : public QDeclarativeItem
+{
+ 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(QDeclarativeItem *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:
+ QDeclarativePathView(QDeclarativeItem *parent=0);
+ virtual ~QDeclarativePathView();
+
+ 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);
+ QDeclarativeItem *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 QDeclarativePathViewAttached *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:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEventFilter(QGraphicsItem *, QEvent *);
+ bool event(QEvent *event);
+ 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, QDeclarativeItem *item);
+ void destroyingItem(QDeclarativeItem *item);
+ void pathUpdated();
+
+private:
+ friend class QDeclarativePathViewAttached;
+ Q_DISABLE_COPY(QDeclarativePathView)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativePathView)
+};
+
+class QDeclarativeOpenMetaObject;
+class QDeclarativePathViewAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativePathView *view READ view CONSTANT)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged)
+ Q_PROPERTY(bool onPath READ isOnPath NOTIFY pathChanged)
+
+public:
+ QDeclarativePathViewAttached(QObject *parent);
+ ~QDeclarativePathViewAttached();
+
+ QDeclarativePathView *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 QDeclarativePathViewPrivate;
+ friend class QDeclarativePathView;
+ QDeclarativePathView *m_view;
+ QDeclarativeOpenMetaObject *m_metaobject;
+ bool m_onPath : 1;
+ bool m_isCurrent : 1;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePathView)
+QML_DECLARE_TYPEINFO(QDeclarativePathView, QML_HAS_ATTACHED_PROPERTIES)
+QT_END_HEADER
+
+#endif // QDECLARATIVEPATHVIEW_H
diff --git a/src/declarative/graphicsitems/qdeclarativepathview_p_p.h b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h
new file mode 100644
index 0000000000..d10819fba7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "private/qdeclarativepathview_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+#include "private/qdeclarativevisualitemmodel_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativeanimation_p_p.h>
+#include <qdeclarativeguard_p.h>
+
+#include <qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeOpenMetaObjectType;
+class QDeclarativePathViewAttached;
+class QDeclarativePathViewPrivate : public QDeclarativeItemPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativePathView)
+
+public:
+ QDeclarativePathViewPrivate()
+ : 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, &QDeclarativePathViewPrivate::setAdjustedOffset)
+ , firstIndex(-1), pathItems(-1), requestedIndex(-1)
+ , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0)
+ , moveHighlight(this, &QDeclarativePathViewPrivate::setHighlightPosition)
+ , highlightPosition(0)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeMode(QDeclarativePathView::StrictlyEnforceRange)
+ , highlightMoveDuration(300), modelCount(0)
+ {
+ }
+
+ void init();
+
+ void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
+ if ((newGeometry.size() != oldGeometry.size())
+ && (!highlightItem || item != highlightItem)) {
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->m_percent = -1;
+ scheduleLayout();
+ }
+ }
+
+ void scheduleLayout() {
+ Q_Q(QDeclarativePathView);
+ if (!layoutScheduled) {
+ layoutScheduled = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
+ }
+ }
+
+ QDeclarativeItem *getItem(int modelIndex);
+ void releaseItem(QDeclarativeItem *item);
+ QDeclarativePathViewAttached *attached(QDeclarativeItem *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(QDeclarativeItem *, qreal);
+ void snapToCurrent();
+ QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
+
+ QDeclarativePath *path;
+ int currentIndex;
+ QDeclarativeGuard<QDeclarativeItem> 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<QDeclarativePathViewPrivate> moveOffset;
+ int firstIndex;
+ int pathItems;
+ int requestedIndex;
+ QList<QDeclarativeItem *> items;
+ QList<QDeclarativeItem *> itemCache;
+ QDeclarativeGuard<QDeclarativeVisualModel> model;
+ QVariant modelVariant;
+ enum MovementReason { Other, SetIndex, Mouse };
+ MovementReason moveReason;
+ enum MovementDirection { Shortest, Negative, Positive };
+ MovementDirection moveDirection;
+ QDeclarativeOpenMetaObjectType *attType;
+ QDeclarativeComponent *highlightComponent;
+ QDeclarativeItem *highlightItem;
+ QDeclarativeTimeLineValueProxy<QDeclarativePathViewPrivate> moveHighlight;
+ qreal highlightPosition;
+ qreal highlightRangeStart;
+ qreal highlightRangeEnd;
+ QDeclarativePathView::HighlightRangeMode highlightRangeMode;
+ int highlightMoveDuration;
+ int modelCount;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea.cpp b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
new file mode 100644
index 0000000000..b5e13cbf82
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
@@ -0,0 +1,607 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativepincharea_p.h"
+#include "qdeclarativepincharea_p_p.h"
+
+#include <QApplication>
+#include <QGraphicsScene>
+
+#include <float.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \qmlclass PinchEvent QDeclarativePinchEvent
+ \ingroup qml-event-elements
+ \brief The PinchEvent object provides information about a pinch event.
+
+ \bold {The PinchEvent element was added in QtQuick 1.1}
+
+ The \c center, \c startCenter, \c previousCenter properties provide the center position between the two touch points.
+
+ The \c scale and \c previousScale properties provide the scale factor.
+
+ The \c angle, \c previousAngle and \c rotation properties provide the angle between the two points and the amount of rotation.
+
+ The \c point1, \c point2, \c startPoint1, \c startPoint2 properties provide the positions of the touch points.
+
+ The \c accepted property may be set to false in the \c onPinchStarted handler if the gesture should not
+ be handled.
+
+ \sa PinchArea
+*/
+
+/*!
+ \qmlproperty QPointF PinchEvent::center
+ \qmlproperty QPointF PinchEvent::startCenter
+ \qmlproperty QPointF PinchEvent::previousCenter
+
+ These properties hold the position of the center point between the two touch points.
+
+ \list
+ \o \c center is the current center point
+ \o \c previousCenter is the center point of the previous event.
+ \o \c startCenter is the center point when the gesture began
+ \endlist
+*/
+
+/*!
+ \qmlproperty real PinchEvent::scale
+ \qmlproperty real PinchEvent::previousScale
+
+ These properties hold the scale factor determined by the change in distance between the two touch points.
+
+ \list
+ \o \c scale is the current scale factor.
+ \o \c previousScale is the scale factor of the previous event.
+ \endlist
+
+ When a pinch gesture is started, the scale is 1.0.
+*/
+
+/*!
+ \qmlproperty real PinchEvent::angle
+ \qmlproperty real PinchEvent::previousAngle
+ \qmlproperty real PinchEvent::rotation
+
+ These properties hold the angle between the two touch points.
+
+ \list
+ \o \c angle is the current angle between the two points in the range -180 to 180.
+ \o \c previousAngle is the angle of the previous event.
+ \o \c rotation is the total rotation since the pinch gesture started.
+ \endlist
+
+ When a pinch gesture is started, the rotation is 0.0.
+*/
+
+/*!
+ \qmlproperty QPointF PinchEvent::point1
+ \qmlproperty QPointF PinchEvent::startPoint1
+ \qmlproperty QPointF PinchEvent::point2
+ \qmlproperty QPointF PinchEvent::startPoint2
+
+ These properties provide the actual touch points generating the pinch.
+
+ \list
+ \o \c point1 and \c point2 hold the current positions of the points.
+ \o \c startPoint1 and \c startPoint2 hold the positions of the points when the second point was touched.
+ \endlist
+*/
+
+/*!
+ \qmlproperty bool PinchEvent::accepted
+
+ Setting this property to false in the \c PinchArea::onPinchStarted handler
+ will result in no further pinch events being generated, and the gesture
+ ignored.
+*/
+
+/*!
+ \qmlproperty int PinchEvent::pointCount
+
+ Holds the number of points currently touched. The PinchArea will not react
+ until two touch points have initited a gesture, but will remain active until
+ all touch points have been released.
+*/
+
+QDeclarativePinch::QDeclarativePinch()
+ : 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)
+{
+}
+
+QDeclarativePinchAreaPrivate::~QDeclarativePinchAreaPrivate()
+{
+ delete pinch;
+}
+
+/*!
+ \qmlclass PinchArea QDeclarativePinchArea
+ \brief The PinchArea item enables simple pinch gesture handling.
+ \inherits Item
+
+ \bold {The PinchArea element was added in QtQuick 1.1}
+
+ A PinchArea is an invisible item that is typically used in conjunction with
+ a visible item in order to provide pinch gesture handling for that item.
+
+ The \l enabled property is used to enable and disable pinch handling for
+ the proxied item. When disabled, the pinch area becomes transparent to
+ mouse/touch events.
+
+ PinchArea can be used in two ways:
+
+ \list
+ \o setting a \c pinch.target to provide automatic interaction with an element
+ \o using the onPinchStarted, onPinchUpdated and onPinchFinished handlers
+ \endlist
+
+ \sa PinchEvent
+*/
+
+/*!
+ \qmlsignal PinchArea::onPinchStarted()
+
+ This handler is called when the pinch area detects that a pinch gesture has started.
+
+ The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
+ including the scale, center and angle of the pinch.
+
+ To ignore this gesture set the \c pinch.accepted property to false. The gesture
+ will be cancelled and no further events will be sent.
+*/
+
+/*!
+ \qmlsignal PinchArea::onPinchUpdated()
+
+ This handler is called when the pinch area detects that a pinch gesture has changed.
+
+ The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
+ including the scale, center and angle of the pinch.
+*/
+
+/*!
+ \qmlsignal PinchArea::onPinchFinished()
+
+ This handler is called when the pinch area detects that a pinch gesture has finished.
+
+ The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
+ including the scale, center and angle of the pinch.
+*/
+
+
+/*!
+ \qmlproperty Item PinchArea::pinch.target
+ \qmlproperty bool PinchArea::pinch.active
+ \qmlproperty real PinchArea::pinch.minimumScale
+ \qmlproperty real PinchArea::pinch.maximumScale
+ \qmlproperty real PinchArea::pinch.minimumRotation
+ \qmlproperty real PinchArea::pinch.maximumRotation
+ \qmlproperty enumeration PinchArea::pinch.dragAxis
+ \qmlproperty real PinchArea::pinch.minimumX
+ \qmlproperty real PinchArea::pinch.maximumX
+ \qmlproperty real PinchArea::pinch.minimumY
+ \qmlproperty real PinchArea::pinch.maximumY
+
+ \c pinch provides a convenient way to make an item react to pinch gestures.
+
+ \list
+ \i \c pinch.target specifies the id of the item to drag.
+ \i \c pinch.active specifies if the target item is currently being dragged.
+ \i \c pinch.minimumScale and \c pinch.maximumScale limit the range of the Item::scale property.
+ \i \c pinch.minimumRotation and \c pinch.maximumRotation limit the range of the Item::rotation property.
+ \i \c pinch.dragAxis specifies whether dragging in not allowed (\c Pinch.NoDrag), can be done horizontally (\c Pinch.XAxis), vertically (\c Pinch.YAxis), or both (\c Pinch.XandYAxis)
+ \i \c pinch.minimum and \c pinch.maximum limit how far the target can be dragged along the corresponding axes.
+ \endlist
+*/
+
+QDeclarativePinchArea::QDeclarativePinchArea(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativePinchAreaPrivate), parent)
+{
+ Q_D(QDeclarativePinchArea);
+ d->init();
+}
+
+QDeclarativePinchArea::~QDeclarativePinchArea()
+{
+}
+
+/*!
+ \qmlproperty bool PinchArea::enabled
+ This property holds whether the item accepts pinch gestures.
+
+ This property defaults to true.
+*/
+bool QDeclarativePinchArea::isEnabled() const
+{
+ Q_D(const QDeclarativePinchArea);
+ return d->absorb;
+}
+
+void QDeclarativePinchArea::setEnabled(bool a)
+{
+ Q_D(QDeclarativePinchArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+bool QDeclarativePinchArea::event(QEvent *event)
+{
+ Q_D(QDeclarativePinchArea);
+ if (!d->absorb || !isVisible())
+ return QDeclarativeItem::event(event);
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate: {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(event);
+ 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 true;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ return QDeclarativeItem::event(event);
+ }
+
+ return QDeclarativeItem::event(event);
+}
+
+void QDeclarativePinchArea::updatePinch()
+{
+ Q_D(QDeclarativePinchArea);
+ if (d->touchPoints.count() == 0) {
+ if (d->inPinch) {
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QDeclarativePinchEvent 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(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ emit pinchFinished(&pe);
+ d->pinchStartDist = 0;
+ d->pinchActivated = false;
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ return;
+ }
+ QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
+ QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
+ if (d->touchPoints.count() == 2
+ && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
+ d->id1 = touchPoint1.id();
+ d->sceneStartPoint1 = touchPoint1.scenePos();
+ d->sceneStartPoint2 = touchPoint2.scenePos();
+ d->inPinch = false;
+ d->pinchRejected = false;
+ d->pinchActivated = true;
+ } else if (d->pinchActivated && !d->pinchRejected) {
+ const int dragThreshold = QApplication::startDragDistance();
+ QPointF p1 = touchPoint1.scenePos();
+ QPointF p2 = touchPoint2.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 (d->touchPoints.count() == 1) {
+ // If we only have one point then just move the center
+ if (d->id1 == touchPoint1.id())
+ sceneCenter = d->sceneLastCenter + touchPoint1.scenePos() - d->lastPoint1;
+ else
+ sceneCenter = d->sceneLastCenter + touchPoint2.scenePos() - d->lastPoint2;
+ angle = d->pinchLastAngle;
+ }
+ d->id1 = touchPoint1.id();
+ if (angle > 180)
+ angle -= 360;
+ if (!d->inPinch) {
+ if (d->touchPoints.count() >= 2
+ && (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 = p1;
+ d->lastPoint2 = p2;
+ QDeclarativePinchEvent 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(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ pe.setPointCount(d->touchPoints.count());
+ emit pinchStarted(&pe);
+ if (pe.accepted()) {
+ d->inPinch = true;
+ d->stealMouse = true;
+ QGraphicsScene *s = scene();
+ if (s && s->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 ? dist / d->pinchStartDist : d->pinchLastScale;
+ qreal da = d->pinchLastAngle - angle;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ d->pinchRotation += da;
+ QPointF pinchCenter = mapFromScene(sceneCenter);
+ QDeclarativePinchEvent 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(touchPoint1.pos());
+ pe.setPoint2(touchPoint2.pos());
+ pe.setPointCount(d->touchPoints.count());
+ d->pinchLastScale = scale;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchLastAngle = angle;
+ d->lastPoint1 = touchPoint1.scenePos();
+ d->lastPoint2 = touchPoint2.scenePos();
+ 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() & QDeclarativePinch::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() & QDeclarativePinch::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 QDeclarativePinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePinchArea);
+ d->stealMouse = false;
+ if (!d->absorb)
+ QDeclarativeItem::mousePressEvent(event);
+ else {
+ setKeepMouseGrab(false);
+ event->setAccepted(true);
+ }
+}
+
+void QDeclarativePinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePinchArea);
+ if (!d->absorb) {
+ QDeclarativeItem::mouseMoveEvent(event);
+ return;
+ }
+}
+
+void QDeclarativePinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePinchArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QDeclarativeItem::mouseReleaseEvent(event);
+ } else {
+ QGraphicsScene *s = scene();
+ if (s && s->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+}
+
+bool QDeclarativePinchArea::sceneEvent(QEvent *event)
+{
+ bool rv = QDeclarativeItem::sceneEvent(event);
+ if (event->type() == QEvent::UngrabMouse) {
+ setKeepMouseGrab(false);
+ }
+ return rv;
+}
+
+bool QDeclarativePinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativePinchArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
+
+ QGraphicsScene *s = scene();
+ QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->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 = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->stealMouse = false;
+ if (s && s->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+ return false;
+}
+
+bool QDeclarativePinchArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
+{
+ Q_D(QDeclarativePinchArea);
+ if (!d->absorb || !isVisible())
+ return QDeclarativeItem::sceneEventFilter(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 QDeclarativeItem::sceneEventFilter(i, e);
+}
+
+void QDeclarativePinchArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+QVariant QDeclarativePinchArea::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ return QDeclarativeItem::itemChange(change, value);
+}
+
+QDeclarativePinch *QDeclarativePinchArea::pinch()
+{
+ Q_D(QDeclarativePinchArea);
+ if (!d->pinch)
+ d->pinch = new QDeclarativePinch;
+ return d->pinch;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p.h
new file mode 100644
index 0000000000..09682c3ae8
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepincharea_p.h
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPINCHAREA_H
+#define QDECLARATIVEPINCHAREA_H
+
+#include <qdeclarativeitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QDeclarativePinch : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(Axis)
+ Q_PROPERTY(QGraphicsObject *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:
+ QDeclarativePinch();
+
+ QGraphicsObject *target() const { return m_target; }
+ void setTarget(QGraphicsObject *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:
+ QGraphicsObject *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 QDeclarativePinchEvent : 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(int pointCount READ pointCount)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+
+public:
+ QDeclarativePinchEvent(QPointF c, qreal s, qreal a, qreal r)
+ : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r)
+ , m_pointCount(0), 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; }
+ int pointCount() const { return m_pointCount; }
+ void setPointCount(int count) { m_pointCount = count; }
+
+ 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;
+ int m_pointCount;
+ bool m_accepted;
+};
+
+
+class QDeclarativeMouseEvent;
+class QDeclarativePinchAreaPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePinchArea : public QDeclarativeItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QDeclarativePinch *pinch READ pinch CONSTANT)
+
+public:
+ QDeclarativePinchArea(QDeclarativeItem *parent=0);
+ ~QDeclarativePinchArea();
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ QDeclarativePinch *pinch();
+
+Q_SIGNALS:
+ void enabledChanged();
+ void pinchStarted(QDeclarativePinchEvent *pinch);
+ void pinchUpdated(QDeclarativePinchEvent *pinch);
+ void pinchFinished(QDeclarativePinchEvent *pinch);
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEvent(QEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool sceneEventFilter(QGraphicsItem *i, QEvent *e);
+ bool event(QEvent *);
+
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant& value);
+
+private:
+ void updatePinch();
+ void handlePress();
+ void handleRelease();
+
+private:
+ Q_DISABLE_COPY(QDeclarativePinchArea)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativePinchArea)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePinch)
+QML_DECLARE_TYPE(QDeclarativePinchEvent)
+QML_DECLARE_TYPE(QDeclarativePinchArea)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPINCHAREA_H
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
new file mode 100644
index 0000000000..a66c3968d7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
@@ -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 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 QDECLARATIVEPINCHAREA_P_H
+#define QDECLARATIVEPINCHAREA_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 <qdatetime.h>
+#include <qbasictimer.h>
+#include <qevent.h>
+#include <qgraphicssceneevent.h>
+#include "qdeclarativeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePinch;
+class QDeclarativePinchAreaPrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePinchArea)
+public:
+ QDeclarativePinchAreaPrivate()
+ : absorb(true), stealMouse(false), inPinch(false)
+ , pinchRejected(false), pinchActivated(false)
+ , pinch(0), pinchStartDist(0), pinchStartScale(1.0)
+ , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0)
+ , pinchLastAngle(0.0), pinchRotation(0.0)
+ {
+ }
+
+ ~QDeclarativePinchAreaPrivate();
+
+ void init()
+ {
+ Q_Q(QDeclarativePinchArea);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setAcceptTouchEvents(true);
+ q->setFiltersChildEvents(true);
+ }
+
+ bool absorb : 1;
+ bool stealMouse : 1;
+ bool inPinch : 1;
+ bool pinchRejected : 1;
+ bool pinchActivated : 1;
+ QDeclarativePinch *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;
+ int id1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEPINCHAREA_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativepositioners.cpp b/src/declarative/graphicsitems/qdeclarativepositioners.cpp
new file mode 100644
index 0000000000..e76fc03cd2
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepositioners.cpp
@@ -0,0 +1,1392 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepositioners_p.h"
+#include "private/qdeclarativepositioners_p_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativestate_p.h>
+#include <qdeclarativestategroup_p.h>
+#include <qdeclarativestateoperations_p.h>
+#include <qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+
+#include <QDebug>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+static const QDeclarativeItemPrivate::ChangeTypes watchedChanges
+ = QDeclarativeItemPrivate::Geometry
+ | QDeclarativeItemPrivate::SiblingOrder
+ | QDeclarativeItemPrivate::Visibility
+ | QDeclarativeItemPrivate::Opacity
+ | QDeclarativeItemPrivate::Destroyed;
+
+void QDeclarativeBasePositionerPrivate::watchChanges(QGraphicsObject *other)
+{
+ if (QGraphicsItemPrivate::get(other)->isDeclarativeItem) {
+ QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
+ otherPrivate->addItemChangeListener(this, watchedChanges);
+ } else {
+ Q_Q(QDeclarativeBasePositioner);
+ QObject::connect(other, SIGNAL(widthChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::connect(other, SIGNAL(heightChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::connect(other, SIGNAL(opacityChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::connect(other, SIGNAL(visibleChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ }
+}
+
+void QDeclarativeBasePositionerPrivate::unwatchChanges(QGraphicsObject* other)
+{
+ if (QGraphicsItemPrivate::get(other)->isDeclarativeItem) {
+ QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
+ } else {
+ Q_Q(QDeclarativeBasePositioner);
+ QObject::disconnect(other, SIGNAL(widthChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::disconnect(other, SIGNAL(heightChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::disconnect(other, SIGNAL(opacityChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ QObject::disconnect(other, SIGNAL(visibleChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
+ }
+}
+
+void QDeclarativeBasePositioner::graphicsWidgetGeometryChanged()
+{
+ prePositioning();
+}
+
+/*!
+ \internal
+ \class QDeclarativeBasePositioner
+ \brief The QDeclarativeBasePositioner class provides a base for QDeclarativeGraphics layouts.
+
+ To create a QDeclarativeGraphics Positioner, simply subclass QDeclarativeBasePositioner and implement
+ doLayout(), which is automatically called when the layout might need
+ updating. In doLayout() use the setX and setY functions from QDeclarativeBasePositioner, and the
+ base class will apply the positions along with the appropriate transitions. The items to
+ position are provided in order as the protected member positionedItems.
+
+ You also need to set a PositionerType, to declare whether you are positioning the x, y or both
+ for the child items. Depending on the chosen type, only x or y changes will be applied.
+
+ Note that the subclass is responsible for adding the spacing in between items.
+*/
+QDeclarativeBasePositioner::QDeclarativeBasePositioner(PositionerType at, QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(*(new QDeclarativeBasePositionerPrivate), parent)
+{
+ Q_D(QDeclarativeBasePositioner);
+ d->init(at);
+}
+
+QDeclarativeBasePositioner::QDeclarativeBasePositioner(QDeclarativeBasePositionerPrivate &dd, PositionerType at, QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(dd, parent)
+{
+ Q_D(QDeclarativeBasePositioner);
+ d->init(at);
+}
+
+QDeclarativeBasePositioner::~QDeclarativeBasePositioner()
+{
+ Q_D(QDeclarativeBasePositioner);
+ for (int i = 0; i < positionedItems.count(); ++i)
+ d->unwatchChanges(positionedItems.at(i).item);
+ positionedItems.clear();
+}
+
+int QDeclarativeBasePositioner::spacing() const
+{
+ Q_D(const QDeclarativeBasePositioner);
+ return d->spacing;
+}
+
+void QDeclarativeBasePositioner::setSpacing(int s)
+{
+ Q_D(QDeclarativeBasePositioner);
+ if (s==d->spacing)
+ return;
+ d->spacing = s;
+ prePositioning();
+ emit spacingChanged();
+}
+
+QDeclarativeTransition *QDeclarativeBasePositioner::move() const
+{
+ Q_D(const QDeclarativeBasePositioner);
+ return d->moveTransition;
+}
+
+void QDeclarativeBasePositioner::setMove(QDeclarativeTransition *mt)
+{
+ Q_D(QDeclarativeBasePositioner);
+ if (mt == d->moveTransition)
+ return;
+ d->moveTransition = mt;
+ emit moveChanged();
+}
+
+QDeclarativeTransition *QDeclarativeBasePositioner::add() const
+{
+ Q_D(const QDeclarativeBasePositioner);
+ return d->addTransition;
+}
+
+void QDeclarativeBasePositioner::setAdd(QDeclarativeTransition *add)
+{
+ Q_D(QDeclarativeBasePositioner);
+ if (add == d->addTransition)
+ return;
+
+ d->addTransition = add;
+ emit addChanged();
+}
+
+void QDeclarativeBasePositioner::componentComplete()
+{
+ Q_D(QDeclarativeBasePositioner);
+ QDeclarativeItem::componentComplete();
+ positionedItems.reserve(d->QGraphicsItemPrivate::children.count());
+ prePositioning();
+ reportConflictingAnchors();
+}
+
+QVariant QDeclarativeBasePositioner::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ Q_D(QDeclarativeBasePositioner);
+ if (change == ItemChildAddedChange){
+ QGraphicsItem* item = value.value<QGraphicsItem*>();
+ QGraphicsObject* child = 0;
+ if(item)
+ child = item->toGraphicsObject();
+ if (child)
+ prePositioning();
+ } else if (change == ItemChildRemovedChange) {
+ QGraphicsItem* item = value.value<QGraphicsItem*>();
+ QGraphicsObject* child = 0;
+ if(item)
+ child = item->toGraphicsObject();
+ if (child) {
+ QDeclarativeBasePositioner::PositionedItem posItem(child);
+ int idx = positionedItems.find(posItem);
+ if (idx >= 0) {
+ d->unwatchChanges(child);
+ positionedItems.remove(idx);
+ }
+ prePositioning();
+ }
+ }
+ return QDeclarativeItem::itemChange(change, value);
+}
+
+void QDeclarativeBasePositioner::prePositioning()
+{
+ Q_D(QDeclarativeBasePositioner);
+ 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<QGraphicsItem *> children = d->QGraphicsItemPrivate::children;
+ qSort(children.begin(), children.end(), d->insertionOrder);
+
+ QPODVector<PositionedItem,8> oldItems;
+ positionedItems.copyAndClear(oldItems);
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QGraphicsObject *child = children.at(ii)->toGraphicsObject();
+ if (!child)
+ continue;
+ QGraphicsItemPrivate *childPrivate = static_cast<QGraphicsItemPrivate*>(QGraphicsItemPrivate::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->explicitlyHidden || !childPrivate->width() || !childPrivate->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->explicitlyHidden || !childPrivate->width() || !childPrivate->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 QDeclarativeBasePositioner::positionX(int x, const PositionedItem &target)
+{
+ Q_D(QDeclarativeBasePositioner);
+ 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 QDeclarativeBasePositioner::positionY(int y, const PositionedItem &target)
+{
+ Q_D(QDeclarativeBasePositioner);
+ 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 QDeclarativeBasePositioner::finishApplyTransitions()
+{
+ Q_D(QDeclarativeBasePositioner);
+ // 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();
+}
+
+/*!
+ \qmlclass Column QDeclarativeColumn
+ \ingroup qml-positioning-elements
+ \since 4.7
+ \brief The Column item arranges its children vertically.
+ \inherits Item
+
+ The Column item positions its child items so that they are vertically
+ aligned and not overlapping.
+
+ Spacing between items can be added using the \l spacing property.
+ Transitions can be used for cases where items managed by a Column are
+ added or moved. These are stored in the \l add and \l move properties
+ respectively.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example positions differently shaped rectangles using a Column
+ item.
+
+ \image verticalpositioner_example.png
+
+ \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Column item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Column item.
+
+ The use of transitions with positioners is described in more detail in the
+ \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
+ Positioner and Repeater Items} document.
+
+ \image verticalpositioner_transition.gif
+
+ \qml
+ Column {
+ spacing: 2
+ add: Transition {
+ // Define an animation for adding a new item...
+ }
+ move: Transition {
+ // Define an animation for moving items within the column...
+ }
+ // ...
+ }
+ \endqml
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ height of a child depend on the position of a child, then the
+ positioner may exhibit strange behavior. If you need to perform any of these
+ actions, consider positioning the items without the use of a Column.
+
+ Items with a width or height of 0 will not be positioned.
+
+ \sa Row, Grid, Flow, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition Column::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition Column::move
+
+ This property holds the transition to apply when moving an item
+ within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \image positioner-move.gif
+
+ \qml
+ Column {
+ move: Transition {
+ NumberAnimation {
+ properties: "y"
+ easing.type: Easing.OutBounce
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int Column::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ \sa Grid::spacing
+*/
+QDeclarativeColumn::QDeclarativeColumn(QDeclarativeItem *parent)
+: QDeclarativeBasePositioner(Vertical, parent)
+{
+}
+
+void QDeclarativeColumn::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(), QGraphicsItemPrivate::get(child.item)->width()));
+
+ voffset += QGraphicsItemPrivate::get(child.item)->height();
+ voffset += spacing();
+ }
+
+ contentSize->setHeight(voffset - spacing());
+}
+
+void QDeclarativeColumn::reportConflictingAnchors()
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
+ QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
+ if (anchors) {
+ QDeclarativeAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QDeclarativeAnchors::TopAnchor ||
+ usedAnchors & QDeclarativeAnchors::BottomAnchor ||
+ usedAnchors & QDeclarativeAnchors::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";
+ }
+}
+
+/*!
+ \qmlclass Row QDeclarativeRow
+ \ingroup qml-positioning-elements
+ \since 4.7
+ \brief The Row item arranges its children horizontally.
+ \inherits Item
+
+ The Row item positions its child items so that they are horizontally
+ aligned and not overlapping.
+
+ Use \l spacing to set the spacing between items in a Row, and use the
+ \l add and \l move properties to set the transitions that should be applied
+ when items are added to, removed from, or re-positioned within the Row.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example lays out differently shaped rectangles using a Row.
+
+ \image horizontalpositioner_example.png
+
+ \snippet doc/src/snippets/declarative/row/row.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Grid item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Row item.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Row.
+
+ Items with a width or height of 0 will not be positioned.
+
+ \sa Column, Grid, Flow, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition Row::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition Row::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Row {
+ id: positioner
+ move: Transition {
+ NumberAnimation {
+ properties: "x"
+ ease: "easeOutBounce"
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int Row::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ \sa Grid::spacing
+*/
+QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
+: QDeclarativeBasePositioner(Horizontal, parent)
+{
+}
+
+/*!
+ \qmlproperty enumeration Row::layoutDirection
+ \since Quick 1.1
+
+ This property holds the layoutDirection of the row.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
+ the left anchor remains to the left of the row.
+ \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
+ the right anchor remains to the right of the row.
+ \endlist
+
+ \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+Qt::LayoutDirection QDeclarativeRow::layoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QDeclarativeRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate* >(QDeclarativeBasePositionerPrivate::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, QDeclarativeItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Row::effectiveLayoutDirection
+ This property holds the effective layout direction of the row positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the row positioner will be mirrored. However, the
+ property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeRow::effectiveLayoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QDeclarativeRow::doPositioning(QSizeF *contentSize)
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::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(), QGraphicsItemPrivate::get(child.item)->height()));
+
+ hoffset += QGraphicsItemPrivate::get(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++] - QGraphicsItemPrivate::get(child.item)->width();
+ if(child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QDeclarativeRow::reportConflictingAnchors()
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
+ QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
+ if (anchors) {
+ QDeclarativeAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QDeclarativeAnchors::LeftAnchor ||
+ usedAnchors & QDeclarativeAnchors::RightAnchor ||
+ usedAnchors & QDeclarativeAnchors::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";
+}
+
+/*!
+ \qmlclass Grid QDeclarativeGrid
+ \ingroup qml-positioning-elements
+ \since 4.7
+ \brief The Grid item positions its children in a grid.
+ \inherits Item
+
+ The Grid item positions its child items so that they are
+ aligned in a grid and are not overlapping.
+
+ The grid positioner calculates a grid of rectangular cells of sufficient
+ size to hold all items, placing the items in the cells, from left to right
+ and top to bottom. Each item is positioned in the top-left corner of its
+ cell with position (0, 0).
+
+ A Grid defaults to four columns, and as many rows as are necessary to
+ fit all child items. The number of rows and columns can be constrained
+ by setting the \l rows and \l columns properties.
+
+ Spacing can be added between child items by setting the \l spacing
+ property. The amount of spacing applied will be the same in the
+ horizontal and vertical directions.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example demonstrates this.
+
+ \image gridLayout_example.png
+
+ \snippet doc/src/snippets/declarative/grid/grid.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Grid item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Grid item.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width or height of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Grid.
+
+ Items with a width or height of 0 will not be positioned.
+
+ \sa Flow, Row, Column, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition Grid::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition Grid::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Grid {
+ move: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ ease: "easeOutBounce"
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int Grid::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ The below example places a Grid containing a red, a blue and a
+ green rectangle on a gray background. The area the grid positioner
+ occupies is colored white. The positioner on the left has the
+ no spacing (the default), and the positioner on the right has
+ a spacing of 6.
+
+ \inlineimage qml-grid-no-spacing.png
+ \inlineimage qml-grid-spacing.png
+
+ \sa rows, columns
+*/
+QDeclarativeGrid::QDeclarativeGrid(QDeclarativeItem *parent) :
+ QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
+{
+}
+
+/*!
+ \qmlproperty int Grid::columns
+
+ This property holds the number of columns in the grid. The default
+ number of columns is 4.
+
+ If the grid does not have enough items to fill the specified
+ number of columns, some columns will be of zero width.
+*/
+
+/*!
+ \qmlproperty int Grid::rows
+ This property holds the number of rows in the grid.
+
+ If the grid does not have enough items to fill the specified
+ number of rows, some rows will be of zero width.
+*/
+
+void QDeclarativeGrid::setColumns(const int columns)
+{
+ if (columns == m_columns)
+ return;
+ m_columns = columns;
+ prePositioning();
+ emit columnsChanged();
+}
+
+void QDeclarativeGrid::setRows(const int rows)
+{
+ if (rows == m_rows)
+ return;
+ m_rows = rows;
+ prePositioning();
+ emit rowsChanged();
+}
+
+/*!
+ \qmlproperty enumeration Grid::flow
+ This property holds the flow of the layout.
+
+ Possible values are:
+
+ \list
+ \o Grid.LeftToRight (default) - Items are positioned next to
+ each other in the \l layoutDirection, then wrapped to the next line.
+ \o Grid.TopToBottom - Items are positioned next to each
+ other from top to bottom, then wrapped to the next column.
+ \endlist
+*/
+QDeclarativeGrid::Flow QDeclarativeGrid::flow() const
+{
+ return m_flow;
+}
+
+void QDeclarativeGrid::setFlow(Flow flow)
+{
+ if (m_flow != flow) {
+ m_flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Grid::layoutDirection
+ \since Quick 1.1
+
+ This property holds the layout direction of the layout.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Grid::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
+ \l Grid::flow property.
+ \endlist
+
+ \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+Qt::LayoutDirection QDeclarativeGrid::layoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QDeclarativeGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::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, QDeclarativeItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Grid::effectiveLayoutDirection
+ This property holds the effective layout direction of the grid positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeGrid::effectiveLayoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::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++);
+ QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
+ if (childPrivate->width() > maxColWidth[j])
+ maxColWidth[j] = childPrivate->width();
+ if (childPrivate->height() > maxRowHeight[i])
+ maxRowHeight[i] = childPrivate->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++);
+ QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
+ if (childPrivate->width() > maxColWidth[j])
+ maxColWidth[j] = childPrivate->width();
+ if (childPrivate->height() > maxRowHeight[i])
+ maxRowHeight[i] = childPrivate->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 -= QGraphicsItemPrivate::get(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 QDeclarativeGrid::reportConflictingAnchors()
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
+ QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(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";
+}
+
+/*!
+ \qmlclass Flow QDeclarativeFlow
+ \ingroup qml-positioning-elements
+ \since 4.7
+ \brief The Flow item arranges its children side by side, wrapping as necessary.
+ \inherits Item
+
+ The Flow item positions its child items like words on a page, wrapping them
+ to create rows or columns of items that do not overlap.
+
+ Spacing between items can be added using the \l spacing property.
+ Transitions can be used for cases where items managed by a Column are
+ added or moved. These are stored in the \l add and \l move properties
+ respectively.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example positions \l Text items within a parent item using
+ a Flow item.
+
+ \image qml-flow-snippet.png
+
+ \snippet doc/src/snippets/declarative/flow.qml flow item
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Flow item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Flow item.
+
+ The use of transitions with positioners is described in more detail in the
+ \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
+ Positioner and Repeater Items} document.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width or height of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Flow.
+
+ Items with a width or height of 0 will not be positioned.
+
+ \sa Column, Row, Grid, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition Flow::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition Flow::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Flow {
+ id: positioner
+ move: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ ease: "easeOutBounce"
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int Flow::spacing
+
+ spacing is the amount in pixels left empty between each adjacent
+ item, and defaults to 0.
+
+ \sa Grid::spacing
+*/
+
+class QDeclarativeFlowPrivate : public QDeclarativeBasePositionerPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeFlow)
+
+public:
+ QDeclarativeFlowPrivate()
+ : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight)
+ {}
+
+ QDeclarativeFlow::Flow flow;
+};
+
+QDeclarativeFlow::QDeclarativeFlow(QDeclarativeItem *parent)
+: QDeclarativeBasePositioner(*(new QDeclarativeFlowPrivate), Both, parent)
+{
+ Q_D(QDeclarativeFlow);
+ // Flow layout requires relayout if its own size changes too.
+ d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
+}
+
+/*!
+ \qmlproperty enumeration Flow::flow
+ This property holds the flow of the layout.
+
+ Possible values are:
+
+ \list
+ \o Flow.LeftToRight (default) - Items are positioned next to
+ to each other according to the \l layoutDirection until the width of the Flow
+ is exceeded, then wrapped to the next line.
+ \o Flow.TopToBottom - Items are positioned next to each
+ other from top to bottom until the height of the Flow is exceeded,
+ then wrapped to the next column.
+ \endlist
+*/
+QDeclarativeFlow::Flow QDeclarativeFlow::flow() const
+{
+ Q_D(const QDeclarativeFlow);
+ return d->flow;
+}
+
+void QDeclarativeFlow::setFlow(Flow flow)
+{
+ Q_D(QDeclarativeFlow);
+ if (d->flow != flow) {
+ d->flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Flow::layoutDirection
+ \since Quick 1.1
+
+ This property holds the layout direction of the layout.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Flow::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
+ \l Flow::flow property.
+ \endlist
+
+ \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+
+Qt::LayoutDirection QDeclarativeFlow::layoutDirection() const
+{
+ Q_D(const QDeclarativeFlow);
+ return d->layoutDirection;
+}
+
+void QDeclarativeFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QDeclarativeFlow);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Flow::effectiveLayoutDirection
+ This property holds the effective layout direction of the flow positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeFlow::effectiveLayoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QDeclarativeFlow::doPositioning(QSizeF *contentSize)
+{
+ Q_D(QDeclarativeFlow);
+
+ 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;
+
+ QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
+ if (d->flow == LeftToRight) {
+ if (widthValid() && hoffset && hoffset + childPrivate->width() > width()) {
+ hoffset = 0;
+ voffset += linemax + spacing();
+ linemax = 0;
+ }
+ } else {
+ if (heightValid() && voffset && voffset + childPrivate->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 + childPrivate->width()));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + childPrivate->height()));
+
+ if (d->flow == LeftToRight) {
+ hoffset += childPrivate->width();
+ hoffset += spacing();
+ linemax = qMax(linemax, qCeil(childPrivate->height()));
+ } else {
+ voffset += childPrivate->height();
+ voffset += spacing();
+ linemax = qMax(linemax, qCeil(childPrivate->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++] - QGraphicsItemPrivate::get(child.item)->width();
+ if(child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QDeclarativeFlow::reportConflictingAnchors()
+{
+ Q_D(QDeclarativeFlow);
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
+ QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(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/graphicsitems/qdeclarativepositioners_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p.h
new file mode 100644
index 0000000000..214c04ff85
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepositioners_p.h
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVELAYOUTS_H
+#define QDECLARATIVELAYOUTS_H
+
+#include "qdeclarativeimplicitsizeitem_p.h"
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qpodvector_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QDeclarativeBasePositionerPrivate;
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeBasePositioner : public QDeclarativeImplicitSizeItem
+{
+ 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 };
+ QDeclarativeBasePositioner(PositionerType, QDeclarativeItem *parent);
+ ~QDeclarativeBasePositioner();
+
+ int spacing() const;
+ void setSpacing(int);
+
+ QDeclarativeTransition *move() const;
+ void setMove(QDeclarativeTransition *);
+
+ QDeclarativeTransition *add() const;
+ void setAdd(QDeclarativeTransition *);
+
+protected:
+ QDeclarativeBasePositioner(QDeclarativeBasePositionerPrivate &dd, PositionerType at, QDeclarativeItem *parent);
+ virtual void componentComplete();
+ virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
+ void finishApplyTransitions();
+
+Q_SIGNALS:
+ void spacingChanged();
+ void moveChanged();
+ void addChanged();
+
+protected Q_SLOTS:
+ void prePositioning();
+ void graphicsWidgetGeometryChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize)=0;
+ virtual void reportConflictingAnchors()=0;
+ class PositionedItem {
+ public :
+ PositionedItem(QGraphicsObject *i) : item(i), isNew(false), isVisible(true) {}
+ bool operator==(const PositionedItem &other) const { return other.item == item; }
+ QGraphicsObject *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(QDeclarativeBasePositioner)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeBasePositioner)
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeColumn : public QDeclarativeBasePositioner
+{
+ Q_OBJECT
+public:
+ QDeclarativeColumn(QDeclarativeItem *parent=0);
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QDeclarativeColumn)
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeRow: public QDeclarativeBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
+public:
+ QDeclarativeRow(QDeclarativeItem *parent=0);
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
+Q_SIGNALS:
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+private:
+ Q_DISABLE_COPY(QDeclarativeRow)
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeGrid : public QDeclarativeBasePositioner
+{
+ 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 REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
+public:
+ QDeclarativeGrid(QDeclarativeItem *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();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+
+private:
+ int m_rows;
+ int m_columns;
+ Flow m_flow;
+ Q_DISABLE_COPY(QDeclarativeGrid)
+};
+
+class QDeclarativeFlowPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeFlow: public QDeclarativeBasePositioner
+{
+ Q_OBJECT
+ Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
+public:
+ QDeclarativeFlow(QDeclarativeItem *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();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
+
+protected:
+ virtual void doPositioning(QSizeF *contentSize);
+ virtual void reportConflictingAnchors();
+protected:
+ QDeclarativeFlow(QDeclarativeFlowPrivate &dd, QDeclarativeItem *parent);
+private:
+ Q_DISABLE_COPY(QDeclarativeFlow)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeFlow)
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeColumn)
+QML_DECLARE_TYPE(QDeclarativeRow)
+QML_DECLARE_TYPE(QDeclarativeGrid)
+QML_DECLARE_TYPE(QDeclarativeFlow)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h
new file mode 100644
index 0000000000..e80129d8f7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELAYOUTS_P_H
+#define QDECLARATIVELAYOUTS_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/qdeclarativepositioners_p.h"
+
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+
+#include <qdeclarativestate_p.h>
+#include <qdeclarativetransitionmanager_p_p.h>
+#include <qdeclarativestateoperations_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QTimer>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+class QDeclarativeBasePositionerPrivate : public QDeclarativeImplicitSizeItemPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativeBasePositioner)
+
+public:
+ QDeclarativeBasePositionerPrivate()
+ : spacing(0), type(QDeclarativeBasePositioner::None)
+ , moveTransition(0), addTransition(0), queuedPositioning(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
+ {
+ }
+
+ void init(QDeclarativeBasePositioner::PositionerType at)
+ {
+ type = at;
+ }
+
+ int spacing;
+
+ QDeclarativeBasePositioner::PositionerType type;
+ QDeclarativeTransition *moveTransition;
+ QDeclarativeTransition *addTransition;
+ QDeclarativeStateOperation::ActionList addActions;
+ QDeclarativeStateOperation::ActionList moveActions;
+ QDeclarativeTransitionManager addTransitionManager;
+ QDeclarativeTransitionManager moveTransitionManager;
+
+ void watchChanges(QGraphicsObject *other);
+ void unwatchChanges(QGraphicsObject* other);
+ bool queuedPositioning : 1;
+ bool doingPositioning : 1;
+ bool anchorConflict : 1;
+
+ Qt::LayoutDirection layoutDirection;
+
+
+ void schedulePositioning()
+ {
+ Q_Q(QDeclarativeBasePositioner);
+ if(!queuedPositioning){
+ QTimer::singleShot(0,q,SLOT(prePositioning()));
+ queuedPositioning = true;
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QDeclarativeBasePositioner);
+ if (type != QDeclarativeBasePositioner::Vertical)
+ q->prePositioning();
+ }
+ bool isLeftToRight() const {
+ if (type == QDeclarativeBasePositioner::Vertical)
+ return true;
+ else
+ return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight;
+ }
+
+ virtual void itemSiblingOrderChanged(QDeclarativeItem* 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(QDeclarativeItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
+ {
+ Q_Q(QDeclarativeBasePositioner);
+ if (newGeometry.size() != oldGeometry.size())
+ q->prePositioning();
+ }
+
+ virtual void itemVisibilityChanged(QDeclarativeItem *)
+ {
+ schedulePositioning();
+ }
+ virtual void itemOpacityChanged(QDeclarativeItem *)
+ {
+ Q_Q(QDeclarativeBasePositioner);
+ q->prePositioning();
+ }
+
+ void itemDestroyed(QDeclarativeItem *item)
+ {
+ Q_Q(QDeclarativeBasePositioner);
+ q->positionedItems.removeOne(QDeclarativeBasePositioner::PositionedItem(item));
+ }
+
+ static Qt::LayoutDirection getLayoutDirection(const QDeclarativeBasePositioner *positioner)
+ {
+ return positioner->d_func()->layoutDirection;
+ }
+
+ static Qt::LayoutDirection getEffectiveLayoutDirection(const QDeclarativeBasePositioner *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
diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
new file mode 100644
index 0000000000..b3235ef2d1
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativerectangle_p.h"
+#include "private/qdeclarativerectangle_p_p.h"
+
+#include <QPainter>
+#include <QStringBuilder>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QDeclarativePen
+ \brief The QDeclarativePen class provides a pen used for drawing rectangle borders on a QDeclarativeView.
+
+ By default, the pen is invalid and nothing is drawn. You must either set a color (then the default
+ width is 1) or a width (then the default color is black).
+
+ A width of 1 indicates is a single-pixel line on the border of the item being painted.
+
+ Example:
+ \qml
+ Rectangle {
+ border.width: 2
+ border.color: "red"
+ }
+ \endqml
+*/
+
+void QDeclarativePen::setColor(const QColor &c)
+{
+ _color = c;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
+ emit penChanged();
+}
+
+void QDeclarativePen::setWidth(int w)
+{
+ if (_width == w && _valid)
+ return;
+
+ _width = w;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
+ emit penChanged();
+}
+
+
+/*!
+ \qmlclass GradientStop QDeclarativeGradientStop
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The GradientStop item defines the color at a position in a Gradient.
+
+ \sa Gradient
+*/
+
+/*!
+ \qmlproperty real GradientStop::position
+ \qmlproperty color GradientStop::color
+
+ The position and color properties describe the color used at a given
+ position in a gradient, as represented by a gradient stop.
+
+ The default position is 0.0; the default color is black.
+
+ \sa Gradient
+*/
+
+void QDeclarativeGradientStop::updateGradient()
+{
+ if (QDeclarativeGradient *grad = qobject_cast<QDeclarativeGradient*>(parent()))
+ grad->doUpdate();
+}
+
+/*!
+ \qmlclass Gradient QDeclarativeGradient
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The Gradient item defines a gradient fill.
+
+ A gradient is defined by two or more colors, which will be blended seamlessly.
+
+ The colors are specified as a set of GradientStop child items, each of
+ which defines a position on the gradient from 0.0 to 1.0 and a color.
+ The position of each GradientStop is defined by setting its
+ \l{GradientStop::}{position} property; its color is defined using its
+ \l{GradientStop::}{color} property.
+
+ A gradient without any gradient stops is rendered as a solid white fill.
+
+ Note that this item is not a visual representation of a gradient. To display a
+ gradient, use a visual element (like \l Rectangle) which supports the use
+ of gradients.
+
+ \section1 Example Usage
+
+ \div {class="float-right"}
+ \inlineimage qml-gradient.png
+ \enddiv
+
+ The following example declares a \l Rectangle item with a gradient starting
+ with red, blending to yellow at one third of the height of the rectangle,
+ and ending with green:
+
+ \snippet doc/src/snippets/declarative/gradient.qml code
+
+ \clearfloat
+ \section1 Performance and Limitations
+
+ Calculating gradients can be computationally expensive compared to the use
+ of solid color fills or images. Consider using gradients for static items
+ in a user interface.
+
+ In Qt 4.7, only vertical, linear gradients can be applied to items. If you
+ need to apply different orientations of gradients, a combination of rotation
+ and clipping will need to be applied to the relevant items. This can
+ introduce additional performance requirements for your application.
+
+ The use of animations involving gradient stops may not give the desired
+ result. An alternative way to animate gradients is to use pre-generated
+ images or SVG drawings containing gradients.
+
+ \sa GradientStop
+*/
+
+/*!
+ \qmlproperty list<GradientStop> Gradient::stops
+ This property holds the gradient stops describing the gradient.
+
+ By default, this property contains an empty list.
+
+ To set the gradient stops, define them as children of the Gradient element.
+*/
+
+const QGradient *QDeclarativeGradient::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 QDeclarativeGradientStop *stop = m_stops.at(i);
+ m_gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
+ m_gradient->setColorAt(stop->position(), stop->color());
+ }
+ }
+
+ return m_gradient;
+}
+
+void QDeclarativeGradient::doUpdate()
+{
+ delete m_gradient;
+ m_gradient = 0;
+ emit updated();
+}
+
+
+/*!
+ \qmlclass Rectangle QDeclarativeRectangle
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The Rectangle item provides a filled rectangle with an optional border.
+ \inherits Item
+
+ Rectangle items are used to fill areas with solid color or gradients, and are
+ often used to hold other items.
+
+ \section1 Appearance
+
+ Each Rectangle item is painted using either a solid fill color, specified using
+ the \l color property, or a gradient, defined using a Gradient element and set
+ using the \l gradient property. If both a color and a gradient are specified,
+ the gradient is used.
+
+ You can add an optional border to a rectangle with its own color and thickness
+ by settting the \l border.color and \l border.width properties.
+
+ You can also create rounded rectangles using the \l radius property. Since this
+ introduces curved edges to the corners of a rectangle, it may be appropriate to
+ set the \l smooth property to improve its appearance.
+
+ \section1 Example Usage
+
+ \div {class="float-right"}
+ \inlineimage declarative-rect.png
+ \enddiv
+
+ The following example shows the effects of some of the common properties on a
+ Rectangle item, which in this case is used to create a square:
+
+ \snippet doc/src/snippets/declarative/rectangle/rectangle.qml document
+
+ \clearfloat
+ \section1 Performance
+
+ Using the \l smooth property improves the appearance of a rounded rectangle at
+ the cost of rendering performance. You should consider unsetting this property
+ for rectangles in motion, and only set it when they are stationary.
+
+ \sa Image
+*/
+
+int QDeclarativeRectanglePrivate::doUpdateSlotIdx = -1;
+
+QDeclarativeRectangle::QDeclarativeRectangle(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativeRectanglePrivate), parent)
+{
+}
+
+void QDeclarativeRectangle::doUpdate()
+{
+ Q_D(QDeclarativeRectangle);
+ d->rectImage = QPixmap();
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+ d->setPaintMargin((pw+1)/2);
+ update();
+}
+
+/*!
+ \qmlproperty int Rectangle::border.width
+ \qmlproperty color Rectangle::border.color
+
+ The width and color used to draw the border of the rectangle.
+
+ A width of 1 creates a thin line. For no line, use a width of 0 or a transparent color.
+
+ \note The width of the rectangle's border does not affect the geometry of the
+ rectangle itself or its position relative to other items if anchors are used.
+
+ If \c border.width is an odd number, the rectangle is painted at a half-pixel offset to retain
+ border smoothness. Also, the border is rendered evenly on either side of the
+ rectangle's boundaries, and the spare pixel is rendered to the right and below the
+ rectangle (as documented for QRect rendering). This can cause unintended effects if
+ \c border.width is 1 and the rectangle is \l{Item::clip}{clipped} by a parent item:
+
+ \div {class="float-right"}
+ \inlineimage rect-border-width.png
+ \enddiv
+
+ \snippet doc/src/snippets/declarative/rectangle/rect-border-width.qml 0
+
+ \clearfloat
+ Here, the innermost rectangle's border is clipped on the bottom and right edges by its
+ parent. To avoid this, the border width can be set to two instead of one.
+*/
+QDeclarativePen *QDeclarativeRectangle::border()
+{
+ Q_D(QDeclarativeRectangle);
+ return d->getPen();
+}
+
+/*!
+ \qmlproperty Gradient Rectangle::gradient
+
+ The gradient to use to fill the rectangle.
+
+ This property allows for the construction of simple vertical gradients.
+ Other gradients may by formed by adding rotation to the rectangle.
+
+ \div {class="float-left"}
+ \inlineimage declarative-rect_gradient.png
+ \enddiv
+
+ \snippet doc/src/snippets/declarative/rectangle/rectangle-gradient.qml rectangles
+ \clearfloat
+
+ If both a gradient and a color are specified, the gradient will be used.
+
+ \sa Gradient, color
+*/
+QDeclarativeGradient *QDeclarativeRectangle::gradient() const
+{
+ Q_D(const QDeclarativeRectangle);
+ return d->gradient;
+}
+
+void QDeclarativeRectangle::setGradient(QDeclarativeGradient *gradient)
+{
+ Q_D(QDeclarativeRectangle);
+ if (d->gradient == gradient)
+ return;
+ static int updatedSignalIdx = -1;
+ if (updatedSignalIdx < 0)
+ updatedSignalIdx = QDeclarativeGradient::staticMetaObject.indexOfSignal("updated()");
+ if (d->doUpdateSlotIdx < 0)
+ d->doUpdateSlotIdx = QDeclarativeRectangle::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();
+}
+
+
+/*!
+ \qmlproperty real Rectangle::radius
+ This property holds the corner radius used to draw a rounded rectangle.
+
+ If radius is non-zero, the rectangle will be painted as a rounded rectangle, otherwise it will be
+ painted as a normal rectangle. The same radius is used by all 4 corners; there is currently
+ no way to specify different radii for different corners.
+*/
+qreal QDeclarativeRectangle::radius() const
+{
+ Q_D(const QDeclarativeRectangle);
+ return d->radius;
+}
+
+void QDeclarativeRectangle::setRadius(qreal radius)
+{
+ Q_D(QDeclarativeRectangle);
+ if (d->radius == radius)
+ return;
+
+ d->radius = radius;
+ d->rectImage = QPixmap();
+ update();
+ emit radiusChanged();
+}
+
+/*!
+ \qmlproperty color Rectangle::color
+ This property holds the color used to fill the rectangle.
+
+ The default color is white.
+
+ \div {class="float-right"}
+ \inlineimage rect-color.png
+ \enddiv
+
+ The following example shows rectangles with colors specified
+ using hexadecimal and named color notation:
+
+ \snippet doc/src/snippets/declarative/rectangle/rectangle-colors.qml rectangles
+
+ \clearfloat
+ If both a gradient and a color are specified, the gradient will be used.
+
+ \sa gradient
+*/
+QColor QDeclarativeRectangle::color() const
+{
+ Q_D(const QDeclarativeRectangle);
+ return d->color;
+}
+
+void QDeclarativeRectangle::setColor(const QColor &c)
+{
+ Q_D(QDeclarativeRectangle);
+ if (d->color == c)
+ return;
+
+ d->color = c;
+ d->rectImage = QPixmap();
+ update();
+ emit colorChanged();
+}
+
+void QDeclarativeRectangle::generateRoundedRect()
+{
+ Q_D(QDeclarativeRectangle);
+ if (d->rectImage.isNull()) {
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+ const int radius = qCeil(d->radius); //ensure odd numbered width/height so we get 1-pixel center
+
+ QString key = QLatin1String("q_") % QString::number(pw) % d->color.name() % QString::number(d->color.alpha(), 16) % QLatin1Char('_') % QString::number(radius);
+ if (d->pen && d->pen->isValid())
+ key += d->pen->color().name() % QString::number(d->pen->color().alpha(), 16);
+
+ if (!QPixmapCache::find(key, &d->rectImage)) {
+ d->rectImage = QPixmap(radius*2 + 3 + pw*2, radius*2 + 3 + pw*2);
+ d->rectImage.fill(Qt::transparent);
+ QPainter p(&(d->rectImage));
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->pen && d->pen->isValid()) {
+ QPen pn(QColor(d->pen->color()), d->pen->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->color);
+ if (pw%2)
+ p.drawRoundedRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, d->rectImage.width()-(pw+1), d->rectImage.height()-(pw+1)), d->radius, d->radius);
+ else
+ p.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, d->rectImage.width()-pw, d->rectImage.height()-pw), d->radius, d->radius);
+
+ // end painting before inserting pixmap
+ // to pixmap cache to avoid a deep copy
+ p.end();
+ QPixmapCache::insert(key, d->rectImage);
+ }
+ }
+}
+
+void QDeclarativeRectangle::generateBorderedRect()
+{
+ Q_D(QDeclarativeRectangle);
+ if (d->rectImage.isNull()) {
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+
+ QString key = QLatin1String("q_") % QString::number(pw) % d->color.name() % QString::number(d->color.alpha(), 16);
+ if (d->pen && d->pen->isValid())
+ key += d->pen->color().name() % QString::number(d->pen->color().alpha(), 16);
+
+ if (!QPixmapCache::find(key, &d->rectImage)) {
+ // Adding 5 here makes qDrawBorderPixmap() paint correctly with smooth: true
+ // See QTBUG-7999 and QTBUG-10765 for more details.
+ d->rectImage = QPixmap(pw*2 + 5, pw*2 + 5);
+ d->rectImage.fill(Qt::transparent);
+ QPainter p(&(d->rectImage));
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->pen && d->pen->isValid()) {
+ QPen pn(QColor(d->pen->color()), d->pen->width());
+ pn.setJoinStyle(Qt::MiterJoin);
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->color);
+ if (pw%2)
+ p.drawRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, d->rectImage.width()-(pw+1), d->rectImage.height()-(pw+1)));
+ else
+ p.drawRect(QRectF(qreal(pw)/2, qreal(pw)/2, d->rectImage.width()-pw, d->rectImage.height()-pw));
+
+ // end painting before inserting pixmap
+ // to pixmap cache to avoid a deep copy
+ p.end();
+ QPixmapCache::insert(key, d->rectImage);
+ }
+ }
+}
+
+void QDeclarativeRectangle::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ Q_D(QDeclarativeRectangle);
+ if (width() <= 0 || height() <= 0)
+ return;
+ if (d->radius > 0 || (d->pen && d->pen->isValid())
+ || (d->gradient && d->gradient->gradient()) ) {
+ drawRect(*p);
+ }
+ else {
+ bool oldAA = p->testRenderHint(QPainter::Antialiasing);
+ if (d->smooth)
+ p->setRenderHints(QPainter::Antialiasing, true);
+ p->fillRect(QRectF(0, 0, width(), height()), d->color);
+ if (d->smooth)
+ p->setRenderHint(QPainter::Antialiasing, oldAA);
+ }
+}
+
+void QDeclarativeRectangle::drawRect(QPainter &p)
+{
+ Q_D(QDeclarativeRectangle);
+ if ((d->gradient && d->gradient->gradient())
+ || d->radius > width()/2 || d->radius > height()/2
+ || width() < 3 || height() < 3) {
+ // XXX This path is still slower than the image path
+ // Image path won't work for gradients or invalid radius though
+ bool oldAA = p.testRenderHint(QPainter::Antialiasing);
+ if (d->smooth)
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->pen && d->pen->isValid()) {
+ QPen pn(QColor(d->pen->color()), d->pen->width());
+ pn.setJoinStyle(Qt::MiterJoin);
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ if (d->gradient && d->gradient->gradient())
+ p.setBrush(*d->gradient->gradient());
+ else
+ p.setBrush(d->color);
+ const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
+ QRectF rect;
+ if (pw%2)
+ rect = QRectF(0.5, 0.5, width()-1, height()-1);
+ else
+ rect = QRectF(0, 0, width(), height());
+ qreal radius = d->radius;
+ if (radius > width()/2 || radius > height()/2)
+ radius = qMin(width()/2, height()/2);
+ if (radius > 0.)
+ p.drawRoundedRect(rect, radius, radius);
+ else
+ p.drawRect(rect);
+ if (d->smooth)
+ p.setRenderHint(QPainter::Antialiasing, oldAA);
+ } else {
+ bool oldAA = p.testRenderHint(QPainter::Antialiasing);
+ bool oldSmooth = p.testRenderHint(QPainter::SmoothPixmapTransform);
+ if (d->smooth)
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
+
+ const int pw = d->pen && d->pen->isValid() ? (d->pen->width()+1)/2*2 : 0;
+
+ if (d->radius > 0)
+ generateRoundedRect();
+ else
+ generateBorderedRect();
+
+ int xOffset = (d->rectImage.width()-1)/2;
+ int yOffset = (d->rectImage.height()-1)/2;
+ Q_ASSERT(d->rectImage.width() == 2*xOffset + 1);
+ Q_ASSERT(d->rectImage.height() == 2*yOffset + 1);
+
+ // check whether we've eliminated the center completely
+ if (2*xOffset > width()+pw)
+ xOffset = (width()+pw)/2;
+ if (2*yOffset > height()+pw)
+ yOffset = (height()+pw)/2;
+
+ QMargins margins(xOffset, yOffset, xOffset, yOffset);
+ QTileRules rules(Qt::StretchTile, Qt::StretchTile);
+ //NOTE: even though our item may have qreal-based width and height, qDrawBorderPixmap only supports QRects
+ qDrawBorderPixmap(&p, QRect(-pw/2, -pw/2, width()+pw, height()+pw), margins, d->rectImage, d->rectImage.rect(), margins, rules);
+
+ if (d->smooth) {
+ p.setRenderHint(QPainter::Antialiasing, oldAA);
+ p.setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool Rectangle::smooth
+
+ Set this property if you want the item to be smoothly scaled or
+ transformed. Smooth filtering gives better visual quality, but is slower. If
+ the item is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the item is stationary on
+ the screen. A common pattern when animating an item is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+
+ \image rect-smooth.png
+ On this image, smooth is turned off on the top half and on on the bottom half.
+*/
+
+QRectF QDeclarativeRectangle::boundingRect() const
+{
+ Q_D(const QDeclarativeRectangle);
+ return QRectF(-d->paintmargin, -d->paintmargin, d->width()+d->paintmargin*2, d->height()+d->paintmargin*2);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativerectangle_p.h b/src/declarative/graphicsitems/qdeclarativerectangle_p.h
new file mode 100644
index 0000000000..b143540f6d
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerectangle_p.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVERECT_H
+#define QDECLARATIVERECT_H
+
+#include "qdeclarativeitem.h"
+
+#include <QtGui/qbrush.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePen : 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:
+ QDeclarativePen(QObject *parent=0)
+ : QObject(parent), _width(1), _color("#000000"), _valid(false)
+ {}
+
+ int width() const { return _width; }
+ void setWidth(int w);
+
+ QColor color() const { return _color; }
+ void setColor(const QColor &c);
+
+ bool isValid() { return _valid; }
+
+Q_SIGNALS:
+ void penChanged();
+
+private:
+ int _width;
+ QColor _color;
+ bool _valid;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeGradientStop : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal position READ position WRITE setPosition)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+
+public:
+ QDeclarativeGradientStop(QObject *parent=0) : QObject(parent) {}
+
+ qreal position() const { return m_position; }
+ void setPosition(qreal position) { m_position = position; updateGradient(); }
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color) { m_color = color; updateGradient(); }
+
+private:
+ void updateGradient();
+
+private:
+ qreal m_position;
+ QColor m_color;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeGradient : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeGradientStop> stops READ stops)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QDeclarativeGradient(QObject *parent=0) : QObject(parent), m_gradient(0) {}
+ ~QDeclarativeGradient() { delete m_gradient; }
+
+ QDeclarativeListProperty<QDeclarativeGradientStop> stops() { return QDeclarativeListProperty<QDeclarativeGradientStop>(this, m_stops); }
+
+ const QGradient *gradient() const;
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ void doUpdate();
+
+private:
+ QList<QDeclarativeGradientStop *> m_stops;
+ mutable QGradient *m_gradient;
+ friend class QDeclarativeGradientStop;
+};
+
+class QDeclarativeRectanglePrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeRectangle : public QDeclarativeItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QDeclarativeGradient *gradient READ gradient WRITE setGradient)
+ Q_PROPERTY(QDeclarativePen * border READ border CONSTANT)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+public:
+ QDeclarativeRectangle(QDeclarativeItem *parent=0);
+
+ QColor color() const;
+ void setColor(const QColor &);
+
+ QDeclarativePen *border();
+
+ QDeclarativeGradient *gradient() const;
+ void setGradient(QDeclarativeGradient *gradient);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ QRectF boundingRect() const;
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+Q_SIGNALS:
+ void colorChanged();
+ void radiusChanged();
+
+private Q_SLOTS:
+ void doUpdate();
+
+private:
+ void generateRoundedRect();
+ void generateBorderedRect();
+ void drawRect(QPainter &painter);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeRectangle)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeRectangle)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePen)
+QML_DECLARE_TYPE(QDeclarativeGradientStop)
+QML_DECLARE_TYPE(QDeclarativeGradient)
+QML_DECLARE_TYPE(QDeclarativeRectangle)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVERECT_H
diff --git a/src/declarative/graphicsitems/qdeclarativerectangle_p_p.h b/src/declarative/graphicsitems/qdeclarativerectangle_p_p.h
new file mode 100644
index 0000000000..1626349978
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerectangle_p_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVERECT_P_H
+#define QDECLARATIVERECT_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/qdeclarativeitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeGradient;
+class QDeclarativeRectangle;
+class QDeclarativeRectanglePrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeRectangle)
+
+public:
+ QDeclarativeRectanglePrivate() :
+ color(Qt::white), gradient(0), pen(0), radius(0), paintmargin(0)
+ {
+ QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
+ }
+
+ ~QDeclarativeRectanglePrivate()
+ {
+ delete pen;
+ }
+
+ QColor color;
+ QDeclarativeGradient *gradient;
+ QDeclarativePen *pen;
+ qreal radius;
+ qreal paintmargin;
+ QPixmap rectImage;
+ static int doUpdateSlotIdx;
+
+ QDeclarativePen *getPen() {
+ if (!pen) {
+ Q_Q(QDeclarativeRectangle);
+ pen = new QDeclarativePen;
+ static int penChangedSignalIdx = -1;
+ if (penChangedSignalIdx < 0)
+ penChangedSignalIdx = QDeclarativePen::staticMetaObject.indexOfSignal("penChanged()");
+ if (doUpdateSlotIdx < 0)
+ doUpdateSlotIdx = QDeclarativeRectangle::staticMetaObject.indexOfSlot("doUpdate()");
+ QMetaObject::connect(pen, penChangedSignalIdx, q, doUpdateSlotIdx);
+ }
+ return pen;
+ }
+
+ void setPaintMargin(qreal margin)
+ {
+ Q_Q(QDeclarativeRectangle);
+ if (margin == paintmargin)
+ return;
+ q->prepareGeometryChange();
+ paintmargin = margin;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVERECT_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativerepeater.cpp b/src/declarative/graphicsitems/qdeclarativerepeater.cpp
new file mode 100644
index 0000000000..4d0f34c49f
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerepeater.cpp
@@ -0,0 +1,447 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativerepeater_p.h"
+#include "private/qdeclarativerepeater_p_p.h"
+
+#include "private/qdeclarativevisualitemmodel_p.h"
+#include <private/qdeclarativeglobal_p.h>
+#include <qdeclarativelistaccessor_p.h>
+
+#include <qlistmodelinterface_p.h>
+
+QT_BEGIN_NAMESPACE
+QDeclarativeRepeaterPrivate::QDeclarativeRepeaterPrivate()
+: model(0), ownModel(false)
+{
+}
+
+QDeclarativeRepeaterPrivate::~QDeclarativeRepeaterPrivate()
+{
+ if (ownModel)
+ delete model;
+}
+
+/*!
+ \qmlclass Repeater QDeclarativeRepeater
+ \ingroup qml-utility-elements
+ \since 4.7
+ \inherits Item
+
+ \brief The Repeater element allows you to repeat an Item-based component using a model.
+
+ The Repeater element is used to create a large number of
+ similar items. Like other view elements, a Repeater has a \l model and a \l delegate:
+ for each entry in the model, the delegate is instantiated
+ in a context seeded with data from the model. A Repeater item is usually
+ enclosed in a positioner element such as \l Row or \l Column to visually
+ position the multiple delegate items created by the Repeater.
+
+ The following Repeater creates three instances of a \l Rectangle item within
+ a \l Row:
+
+ \snippet doc/src/snippets/declarative/repeaters/repeater.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/repeaters/repeater.qml simple
+
+ \image repeater-simple.png
+
+ A Repeater's \l model can be any of the supported \l {qmlmodels}{data models}.
+ Additionally, like delegates for other views, a Repeater delegate can access
+ its index within the repeater, as well as the model data relevant to the
+ delegate. See the \l delegate property documentation for details.
+
+ Items instantiated by the Repeater are inserted, in order, as
+ children of the Repeater's parent. The insertion starts immediately after
+ the repeater's position in its parent stacking list. This allows
+ a Repeater to be used inside a layout. For example, the following Repeater's
+ items are stacked between a red rectangle and a blue rectangle:
+
+ \snippet doc/src/snippets/declarative/repeaters/repeater.qml layout
+
+ \image repeater.png
+
+
+ \note A Repeater item owns all items it instantiates. Removing or dynamically destroying
+ an item created by a Repeater results in unpredictable behavior.
+
+
+ \section2 Considerations when using Repeater
+
+ The Repeater element creates all of its delegate items when the repeater is first
+ created. This can be inefficient if there are a large number of delegate items and
+ not all of the items are required to be visible at the same time. If this is the case,
+ consider using other view elements like ListView (which only creates delegate items
+ when they are scrolled into view) or use the \l {Dynamic Object Creation} methods to
+ create items as they are required.
+
+ Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
+ For example, it cannot be used to repeat QtObjects:
+ \badcode
+ Item {
+ //XXX does not work! Can't repeat QtObject as it doesn't derive from Item.
+ Repeater {
+ model: 10
+ QtObject {}
+ }
+ }
+ \endcode
+ */
+
+/*!
+ \qmlsignal Repeater::onItemAdded(int index, Item item)
+ \since Quick 1.1
+
+ This handler is called when an item is added to the repeater. The \a index
+ parameter holds the index at which the item has been inserted within the
+ repeater, and the \a item parameter holds the \l Item that has been added.
+*/
+
+/*!
+ \qmlsignal Repeater::onItemRemoved(int index, Item item)
+ \since Quick 1.1
+
+ This handler is called when an item is removed from the repeater. The \a index
+ parameter holds the index at which the item was removed from the repeater,
+ and the \a item parameter holds the \l Item that was removed.
+
+ Do not keep a reference to \a item if it was created by this repeater, as
+ in these cases it will be deleted shortly after the handler is called.
+*/
+
+QDeclarativeRepeater::QDeclarativeRepeater(QDeclarativeItem *parent)
+ : QDeclarativeItem(*(new QDeclarativeRepeaterPrivate), parent)
+{
+}
+
+QDeclarativeRepeater::~QDeclarativeRepeater()
+{
+}
+
+/*!
+ \qmlproperty any Repeater::model
+
+ The model providing data for the repeater.
+
+ This property can be set to any of the supported \l {qmlmodels}{data models}:
+
+ \list
+ \o A number that indicates the number of delegates to be created by the repeater
+ \o A model (e.g. a ListModel item, or a QAbstractItemModel subclass)
+ \o A string list
+ \o An object list
+ \endlist
+
+ The type of model affects the properties that are exposed to the \l delegate.
+
+ \sa {qmlmodels}{Data Models}
+*/
+QVariant QDeclarativeRepeater::model() const
+{
+ Q_D(const QDeclarativeRepeater);
+ return d->dataSource;
+}
+
+void QDeclarativeRepeater::setModel(const QVariant &model)
+{
+ Q_D(QDeclarativeRepeater);
+ 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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ */
+ }
+ d->dataSource = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QDeclarativeVisualModel *vim = 0;
+ if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(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,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
+ */
+ regenerate();
+ }
+ emit modelChanged();
+ emit countChanged();
+}
+
+/*!
+ \qmlproperty Component Repeater::delegate
+ \default
+
+ The delegate provides a template defining each item instantiated by the repeater.
+
+ Delegates are exposed to a read-only \c index property that indicates the index
+ of the delegate within the repeater. For example, the following \l Text delegate
+ displays the index of each repeated item:
+
+ \table
+ \row
+ \o \snippet doc/src/snippets/declarative/repeaters/repeater.qml index
+ \o \image repeater-index.png
+ \endtable
+
+ If the \l model is a \l{QStringList-based model}{string list} or
+ \l{QObjectList-based model}{object list}, the delegate is also exposed to
+ a read-only \c modelData property that holds the string or object data. For
+ example:
+
+ \table
+ \row
+ \o \snippet doc/src/snippets/declarative/repeaters/repeater.qml modeldata
+ \o \image repeater-modeldata.png
+ \endtable
+
+ If the \l model is a model object (such as a \l ListModel) the delegate
+ can access all model roles as named properties, in the same way that delegates
+ do for view classes like ListView.
+
+ \sa {QML Data Models}
+ */
+QDeclarativeComponent *QDeclarativeRepeater::delegate() const
+{
+ Q_D(const QDeclarativeRepeater);
+ if (d->model) {
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ return dataModel->delegate();
+ }
+
+ return 0;
+}
+
+void QDeclarativeRepeater::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QDeclarativeRepeater);
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
+ if (delegate == dataModel->delegate())
+ return;
+
+ if (!d->ownModel) {
+ d->model = new QDeclarativeVisualDataModel(qmlContext(this));
+ d->ownModel = true;
+ }
+ if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
+ dataModel->setDelegate(delegate);
+ regenerate();
+ emit delegateChanged();
+ }
+}
+
+/*!
+ \qmlproperty int Repeater::count
+
+ This property holds the number of items in the repeater.
+*/
+int QDeclarativeRepeater::count() const
+{
+ Q_D(const QDeclarativeRepeater);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+/*!
+ \qmlmethod Item Repeater::itemAt(index)
+ \since Quick 1.1
+
+ Returns the \l Item that has been created at the given \a index, or \c null
+ if no item exists at \a index.
+*/
+QDeclarativeItem *QDeclarativeRepeater::itemAt(int index) const
+{
+ Q_D(const QDeclarativeRepeater);
+ if (index >= 0 && index < d->deletables.count())
+ return d->deletables[index];
+ return 0;
+
+}
+
+void QDeclarativeRepeater::componentComplete()
+{
+ QDeclarativeItem::componentComplete();
+ regenerate();
+}
+
+QVariant QDeclarativeRepeater::itemChange(GraphicsItemChange change,
+ const QVariant &value)
+{
+ QVariant rv = QDeclarativeItem::itemChange(change, value);
+ if (change == ItemParentHasChanged) {
+ regenerate();
+ }
+
+ return rv;
+}
+
+void QDeclarativeRepeater::clear()
+{
+ Q_D(QDeclarativeRepeater);
+ bool complete = isComponentComplete();
+
+ if (d->model) {
+ while (d->deletables.count() > 0) {
+ QDeclarativeItem *item = d->deletables.takeLast();
+ if (complete)
+ emit itemRemoved(d->deletables.count()-1, item);
+ d->model->release(item);
+ }
+ }
+ d->deletables.clear();
+}
+
+void QDeclarativeRepeater::regenerate()
+{
+ Q_D(QDeclarativeRepeater);
+ if (!isComponentComplete())
+ return;
+
+ clear();
+
+ if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
+ return;
+
+ for (int ii = 0; ii < count(); ++ii) {
+ QDeclarativeItem *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 QDeclarativeRepeater::itemsInserted(int index, int count)
+{
+ Q_D(QDeclarativeRepeater);
+ if (!isComponentComplete())
+ return;
+ for (int i = 0; i < count; ++i) {
+ int modelIndex = index + i;
+ QDeclarativeItem *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 QDeclarativeRepeater::itemsRemoved(int index, int count)
+{
+ Q_D(QDeclarativeRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ while (count--) {
+ QDeclarativeItem *item = d->deletables.takeAt(index);
+ emit itemRemoved(index, item);
+ if (item)
+ d->model->release(item);
+ else
+ break;
+ }
+ emit countChanged();
+}
+
+void QDeclarativeRepeater::itemsMoved(int from, int to, int count)
+{
+ Q_D(QDeclarativeRepeater);
+ if (!isComponentComplete() || count <= 0)
+ return;
+ if (from + count > d->deletables.count()) {
+ regenerate();
+ return;
+ }
+ QList<QDeclarativeItem*> 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) {
+ QDeclarativeItem *item = d->deletables.at(i-1);
+ item->stackBefore(d->deletables.at(i));
+ }
+}
+
+void QDeclarativeRepeater::modelReset()
+{
+ if (!isComponentComplete())
+ return;
+ regenerate();
+ emit countChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativerepeater_p.h b/src/declarative/graphicsitems/qdeclarativerepeater_p.h
new file mode 100644
index 0000000000..9cb4e30c1a
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerepeater_p.h
@@ -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 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 QDECLARATIVEREPEATER_H
+#define QDECLARATIVEREPEATER_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeRepeaterPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeRepeater : public QDeclarativeItem
+{
+ 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:
+ QDeclarativeRepeater(QDeclarativeItem *parent=0);
+ virtual ~QDeclarativeRepeater();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int count() const;
+
+ Q_INVOKABLE Q_REVISION(1) QDeclarativeItem *itemAt(int index) const;
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void countChanged();
+
+ Q_REVISION(1) void itemAdded(int index, QDeclarativeItem *item);
+ Q_REVISION(1) void itemRemoved(int index, QDeclarativeItem *item);
+
+private:
+ void clear();
+ void regenerate();
+
+protected:
+ virtual void componentComplete();
+ QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+
+private Q_SLOTS:
+ void itemsInserted(int,int);
+ void itemsRemoved(int,int);
+ void itemsMoved(int,int,int);
+ void modelReset();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeRepeater)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeRepeater)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeRepeater)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEREPEATER_H
diff --git a/src/declarative/graphicsitems/qdeclarativerepeater_p_p.h b/src/declarative/graphicsitems/qdeclarativerepeater_p_p.h
new file mode 100644
index 0000000000..1f409d85d5
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativerepeater_p_p.h
@@ -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 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 QDECLARATIVEREPEATER_P_H
+#define QDECLARATIVEREPEATER_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/qdeclarativerepeater_p.h"
+
+#include "private/qdeclarativeitem_p.h"
+
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QDeclarativeVisualModel;
+class QDeclarativeRepeaterPrivate : public QDeclarativeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeRepeater)
+
+public:
+ QDeclarativeRepeaterPrivate();
+ ~QDeclarativeRepeaterPrivate();
+
+ QDeclarativeVisualModel *model;
+ QVariant dataSource;
+ bool ownModel;
+
+ QList<QPointer<QDeclarativeItem> > deletables;
+};
+
+QT_END_NAMESPACE
+#endif // QDECLARATIVEREPEATER_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativescalegrid.cpp b/src/declarative/graphicsitems/qdeclarativescalegrid.cpp
new file mode 100644
index 0000000000..3ad0da61b6
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativescalegrid.cpp
@@ -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 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/qdeclarativescalegrid_p_p.h"
+
+#include <qdeclarative.h>
+
+#include <QBuffer>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+/*!
+ \internal
+ \class QDeclarativeScaleGrid
+ \brief The QDeclarativeScaleGrid class allows you to specify a 3x3 grid to use in scaling an image.
+*/
+
+QDeclarativeScaleGrid::QDeclarativeScaleGrid(QObject *parent) : QObject(parent), _left(0), _top(0), _right(0), _bottom(0)
+{
+}
+
+QDeclarativeScaleGrid::~QDeclarativeScaleGrid()
+{
+}
+
+bool QDeclarativeScaleGrid::isNull() const
+{
+ return !_left && !_top && !_right && !_bottom;
+}
+
+void QDeclarativeScaleGrid::setLeft(int pos)
+{
+ if (_left != pos) {
+ _left = pos;
+ emit borderChanged();
+ }
+}
+
+void QDeclarativeScaleGrid::setTop(int pos)
+{
+ if (_top != pos) {
+ _top = pos;
+ emit borderChanged();
+ }
+}
+
+void QDeclarativeScaleGrid::setRight(int pos)
+{
+ if (_right != pos) {
+ _right = pos;
+ emit borderChanged();
+ }
+}
+
+void QDeclarativeScaleGrid::setBottom(int pos)
+{
+ if (_bottom != pos) {
+ _bottom = pos;
+ emit borderChanged();
+ }
+}
+
+QDeclarativeGridScaledImage::QDeclarativeGridScaledImage()
+: _l(-1), _r(-1), _t(-1), _b(-1),
+ _h(QDeclarativeBorderImage::Stretch), _v(QDeclarativeBorderImage::Stretch)
+{
+}
+
+QDeclarativeGridScaledImage::QDeclarativeGridScaledImage(const QDeclarativeGridScaledImage &o)
+: _l(o._l), _r(o._r), _t(o._t), _b(o._b), _h(o._h), _v(o._v), _pix(o._pix)
+{
+}
+
+QDeclarativeGridScaledImage &QDeclarativeGridScaledImage::operator=(const QDeclarativeGridScaledImage &o)
+{
+ _l = o._l;
+ _r = o._r;
+ _t = o._t;
+ _b = o._b;
+ _h = o._h;
+ _v = o._v;
+ _pix = o._pix;
+ return *this;
+}
+
+QDeclarativeGridScaledImage::QDeclarativeGridScaledImage(QIODevice *data)
+: _l(-1), _r(-1), _t(-1), _b(-1), _h(QDeclarativeBorderImage::Stretch), _v(QDeclarativeBorderImage::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;
+}
+
+QDeclarativeBorderImage::TileMode QDeclarativeGridScaledImage::stringToRule(const QString &s)
+{
+ if (s == QLatin1String("Stretch"))
+ return QDeclarativeBorderImage::Stretch;
+ if (s == QLatin1String("Repeat"))
+ return QDeclarativeBorderImage::Repeat;
+ if (s == QLatin1String("Round"))
+ return QDeclarativeBorderImage::Round;
+
+ qWarning("QDeclarativeGridScaledImage: Invalid tile rule specified. Using Stretch.");
+ return QDeclarativeBorderImage::Stretch;
+}
+
+bool QDeclarativeGridScaledImage::isValid() const
+{
+ return _l >= 0;
+}
+
+int QDeclarativeGridScaledImage::gridLeft() const
+{
+ return _l;
+}
+
+int QDeclarativeGridScaledImage::gridRight() const
+{
+ return _r;
+}
+
+int QDeclarativeGridScaledImage::gridTop() const
+{
+ return _t;
+}
+
+int QDeclarativeGridScaledImage::gridBottom() const
+{
+ return _b;
+}
+
+QString QDeclarativeGridScaledImage::pixmapUrl() const
+{
+ return _pix;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativescalegrid_p_p.h b/src/declarative/graphicsitems/qdeclarativescalegrid_p_p.h
new file mode 100644
index 0000000000..fba161c1d0
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativescalegrid_p_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESCALEGRID_H
+#define QDECLARATIVESCALEGRID_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/QString>
+#include <QtCore/QObject>
+
+#include <private/qdeclarativeborderimage_p.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 QDeclarativeScaleGrid : 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:
+ QDeclarativeScaleGrid(QObject *parent=0);
+ ~QDeclarativeScaleGrid();
+
+ 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 QDeclarativeGridScaledImage
+{
+public:
+ QDeclarativeGridScaledImage();
+ QDeclarativeGridScaledImage(const QDeclarativeGridScaledImage &);
+ QDeclarativeGridScaledImage(QIODevice*);
+ QDeclarativeGridScaledImage &operator=(const QDeclarativeGridScaledImage &);
+ bool isValid() const;
+ int gridLeft() const;
+ int gridRight() const;
+ int gridTop() const;
+ int gridBottom() const;
+ QDeclarativeBorderImage::TileMode horizontalTileRule() const { return _h; }
+ QDeclarativeBorderImage::TileMode verticalTileRule() const { return _v; }
+
+ QString pixmapUrl() const;
+
+private:
+ static QDeclarativeBorderImage::TileMode stringToRule(const QString &);
+
+private:
+ int _l;
+ int _r;
+ int _t;
+ int _b;
+ QDeclarativeBorderImage::TileMode _h;
+ QDeclarativeBorderImage::TileMode _v;
+ QString _pix;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeScaleGrid)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESCALEGRID_H
diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp
new file mode 100644
index 0000000000..a38152d177
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetext.cpp
@@ -0,0 +1,1640 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetext_p.h"
+#include "private/qdeclarativetext_p_p.h"
+#include <qdeclarativestyledtext_p.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativepixmapcache_p.h>
+
+#include <QSet>
+#include <QTextLayout>
+#include <QTextLine>
+#include <QTextDocument>
+#include <QGraphicsSceneMouseEvent>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+#include <qmath.h>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
+
+class QTextDocumentWithImageResources : public QTextDocument {
+ Q_OBJECT
+
+public:
+ QTextDocumentWithImageResources(QDeclarativeText *parent);
+ virtual ~QTextDocumentWithImageResources();
+
+ 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 QDeclarativeTextPrivate::elideChar = QString(0x2026);
+
+QDeclarativeTextPrivate::QDeclarativeTextPrivate()
+: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft),
+ vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone),
+ format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineHeight(1),
+ lineHeightMode(QDeclarativeText::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
+ maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
+ cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true),
+ rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0)
+{
+ cacheAllTextAsImage = enableImageCache();
+ QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
+ QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
+}
+
+QTextDocumentWithImageResources::QTextDocumentWithImageResources(QDeclarativeText *parent)
+: QTextDocument(parent), outstanding(0)
+{
+}
+
+QTextDocumentWithImageResources::~QTextDocumentWithImageResources()
+{
+ if (!m_resources.isEmpty())
+ qDeleteAll(m_resources);
+}
+
+QVariant QTextDocumentWithImageResources::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 QTextDocumentWithImageResources::requestFinished()
+{
+ outstanding--;
+ if (outstanding == 0) {
+ QDeclarativeText *textItem = static_cast<QDeclarativeText*>(parent());
+ QString text = textItem->text();
+#ifndef QT_NO_TEXTHTMLPARSER
+ setHtml(text);
+#else
+ setPlainText(text);
+#endif
+ QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem);
+ d->updateLayout();
+ }
+}
+
+void QTextDocumentWithImageResources::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> QTextDocumentWithImageResources::errors;
+
+QDeclarativeTextPrivate::~QDeclarativeTextPrivate()
+{
+}
+
+qreal QDeclarativeTextPrivate::implicitWidth() 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
+ QDeclarativeTextPrivate *me = const_cast<QDeclarativeTextPrivate*>(this);
+ me->requireImplicitWidth = true;
+ me->updateSize();
+ }
+ return mImplicitWidth;
+}
+
+void QDeclarativeTextPrivate::updateLayout()
+{
+ Q_Q(QDeclarativeText);
+ if (!q->isComponentComplete()) {
+ updateOnComponentComplete = true;
+ return;
+ }
+
+ layoutTextElided = false;
+ // Setup instance of QTextLayout for all cases other than richtext
+ if (!richText) {
+ layout.clearLayout();
+ layout.setFont(font);
+ if (format != QDeclarativeText::StyledText) {
+ QString tmp = text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ singleline = !tmp.contains(QChar::LineSeparator);
+ if (singleline && !maximumLineCountValid && elideMode != QDeclarativeText::ElideNone && q->widthValid()) {
+ QFontMetrics fm(font);
+ tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
+ if (tmp != text) {
+ layoutTextElided = true;
+ if (!truncated) {
+ truncated = true;
+ emit q->truncatedChanged();
+ }
+ }
+ }
+ layout.setText(tmp);
+ } else {
+ singleline = false;
+ QDeclarativeStyledText::parse(text, layout);
+ }
+ }
+
+ updateSize();
+}
+
+void QDeclarativeTextPrivate::updateSize()
+{
+ Q_Q(QDeclarativeText);
+
+ 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();
+ if (layedOutTextRect.size() != textRect.size())
+ q->prepareGeometryChange();
+ 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);
+
+ QDeclarativeText::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QDeclarativeText::AlignLeft)
+ horizontalAlignment = QDeclarativeText::AlignRight;
+ else if (horizontalAlignment == QDeclarativeText::AlignRight)
+ horizontalAlignment = QDeclarativeText::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 != QDeclarativeText::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();
+ if (dsize != layedOutTextRect.size()) {
+ q->prepareGeometryChange();
+ layedOutTextRect = QRect(QPoint(0,0), dsize);
+ }
+ size = QSize(int(doc->idealWidth()),dsize.height());
+ }
+ int yoff = 0;
+
+ if (q->heightValid()) {
+ if (vAlign == QDeclarativeText::AlignBottom)
+ yoff = dy;
+ else if (vAlign == QDeclarativeText::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 QDeclarativeTextPrivate::layout QTextLayout in the constraints of the QDeclarativeText.
+
+ Returns the size of the final text. This can be used to position the text vertically (the text is
+ already absolutely positioned horizontally).
+*/
+QRect QDeclarativeTextPrivate::setupTextLayout()
+{
+ // ### text layout handling should be profiled and optimized as needed
+ // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
+ Q_Q(QDeclarativeText);
+ 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
+ QString elidedText;
+ if (layoutTextElided) {
+ // We have provided elided text to the layout, but we must calculate unelided width.
+ elidedText = layout.text();
+ layout.setText(text);
+ }
+ 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 (layoutTextElided)
+ layout.setText(elidedText);
+ }
+
+ 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==QDeclarativeText::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 == QDeclarativeText::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 QDeclarativeTextPrivate::layout QTextLayout.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle)
+{
+ //do layout
+ 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 QDeclarativeTextPrivate::layout QTextLayout into \a painter at \a pos. If
+ \a drawStyle is true, the style color overrides all colors in the document.
+*/
+void QDeclarativeTextPrivate::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 QDeclarativeTextPrivate::doc QTextDocument.
+ If \a drawStyle is true, the style color overrides all colors in the document.
+*/
+QPixmap QDeclarativeTextPrivate::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 QDeclarativeTextPrivate::invalidateImageCache()
+{
+ Q_Q(QDeclarativeText);
+
+ if(cacheAllTextAsImage || style != QDeclarativeText::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 QDeclarativeTextPrivate::checkImageCache()
+{
+ if (!imageCacheDirty)
+ return;
+
+ if (text.isEmpty()) {
+
+ imageCache = QPixmap();
+
+ } else {
+
+ QPixmap textImage;
+ QPixmap styledImage;
+
+ if (richText) {
+ textImage = textDocumentImage(false);
+ if (style != QDeclarativeText::Normal)
+ styledImage = textDocumentImage(true); //### should use styleColor
+ } else {
+ textImage = textLayoutImage(false);
+ if (style != QDeclarativeText::Normal)
+ styledImage = textLayoutImage(true); //### should use styleColor
+ }
+
+ switch (style) {
+ case QDeclarativeText::Outline:
+ imageCache = drawOutline(textImage, styledImage);
+ break;
+ case QDeclarativeText::Sunken:
+ imageCache = drawOutline(textImage, styledImage, -1);
+ break;
+ case QDeclarativeText::Raised:
+ imageCache = drawOutline(textImage, styledImage, 1);
+ break;
+ default:
+ imageCache = textImage;
+ break;
+ }
+
+ }
+
+ imageCacheDirty = false;
+}
+
+/*!
+ Ensures the QDeclarativeTextPrivate::doc variable is set to a valid text document
+*/
+void QDeclarativeTextPrivate::ensureDoc()
+{
+ if (!doc) {
+ Q_Q(QDeclarativeText);
+ doc = new QTextDocumentWithImageResources(q);
+ doc->setDocumentMargin(0);
+ }
+}
+
+/*!
+ Draw \a styleSource as an outline around \a source and return the new image.
+*/
+QPixmap QDeclarativeTextPrivate::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 QDeclarativeTextPrivate::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;
+}
+
+/*!
+ \qmlclass Text QDeclarativeText
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The Text item allows you to add formatted text to a scene.
+ \inherits Item
+
+ Text items can display both plain and rich text. For example, red text with
+ a specific font and size can be defined like this:
+
+ \qml
+ Text {
+ text: "Hello World!"
+ font.family: "Helvetica"
+ font.pointSize: 24
+ color: "red"
+ }
+ \endqml
+
+ Rich text is defined using HTML-style markup:
+
+ \qml
+ Text {
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ \endqml
+
+ \image declarative-text.png
+
+ If height and width are not explicitly set, Text will attempt to determine how
+ much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
+ prefer width to height (all text will be placed on a single line).
+
+ The \l elide property can alternatively be used to fit a single line of
+ plain text to a set width.
+
+ Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
+ HTML img tags that load remote images, the text is reloaded.
+
+ Text provides read-only text. For editable text, see \l TextEdit.
+
+ \sa {declarative/text/fonts}{Fonts example}
+*/
+QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent)
+ : QDeclarativeImplicitSizeItem(*(new QDeclarativeTextPrivate), parent)
+{
+}
+
+QDeclarativeText::~QDeclarativeText()
+{
+}
+
+/*!
+ \qmlproperty bool Text::clip
+ This property holds whether the text is clipped.
+
+ Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
+
+ If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
+*/
+
+/*!
+ \qmlproperty bool Text::smooth
+
+ This property holds whether the text is smoothly scaled or transformed.
+
+ Smooth filtering gives better visual quality, but is slower. If
+ the item is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the item is stationary on
+ the screen. A common pattern when animating an item is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+ \qmlsignal Text::onLinkActivated(string link)
+
+ This handler is called when the user clicks on a link embedded in the text.
+ The link must be in rich text or HTML format and the
+ \a link string provides access to the particular link.
+
+ \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
+
+ The example code will display the text
+ "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
+
+ Clicking on the highlighted link will output
+ \tt{http://qt.nokia.com link activated} to the console.
+*/
+
+/*!
+ \qmlproperty string Text::font.family
+
+ Sets the family name of the font.
+
+ The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+ If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+ If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+ \qmlproperty bool Text::font.bold
+
+ Sets whether the font weight is bold.
+*/
+
+/*!
+ \qmlproperty enumeration Text::font.weight
+
+ Sets the font's weight.
+
+ The weight can be one of:
+ \list
+ \o Font.Light
+ \o Font.Normal - the default
+ \o Font.DemiBold
+ \o Font.Bold
+ \o Font.Black
+ \endlist
+
+ \qml
+ Text { text: "Hello"; font.weight: Font.DemiBold }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool Text::font.italic
+
+ Sets whether the font has an italic style.
+*/
+
+/*!
+ \qmlproperty bool Text::font.underline
+
+ Sets whether the text is underlined.
+*/
+
+/*!
+ \qmlproperty bool Text::font.strikeout
+
+ Sets whether the font has a strikeout style.
+*/
+
+/*!
+ \qmlproperty real Text::font.pointSize
+
+ Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+ \qmlproperty int Text::font.pixelSize
+
+ Sets the font size in pixels.
+
+ Using this function makes the font device dependent.
+ Use \c pointSize to set the size of the font in a device independent manner.
+*/
+
+/*!
+ \qmlproperty real Text::font.letterSpacing
+
+ Sets the letter spacing for the font.
+
+ Letter spacing changes the default spacing between individual letters in the font.
+ A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
+*/
+
+/*!
+ \qmlproperty real Text::font.wordSpacing
+
+ Sets the word spacing for the font.
+
+ Word spacing changes the default spacing between individual words.
+ A positive value increases the word spacing by a corresponding amount of pixels,
+ while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+ \qmlproperty enumeration Text::font.capitalization
+
+ Sets the capitalization for the text.
+
+ \list
+ \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \endlist
+
+ \qml
+ Text { text: "Hello"; font.capitalization: Font.AllLowercase }
+ \endqml
+*/
+QFont QDeclarativeText::font() const
+{
+ Q_D(const QDeclarativeText);
+ return d->sourceFont;
+}
+
+void QDeclarativeText::setFont(const QFont &font)
+{
+ Q_D(QDeclarativeText);
+ 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->updateLayout();
+
+ emit fontChanged(d->sourceFont);
+}
+
+/*!
+ \qmlproperty string Text::text
+
+ The text to display. Text supports both plain and rich text strings.
+
+ The item will try to automatically determine whether the text should
+ be treated as rich text. This determination is made using Qt::mightBeRichText().
+*/
+QString QDeclarativeText::text() const
+{
+ Q_D(const QDeclarativeText);
+ return d->text;
+}
+
+void QDeclarativeText::setText(const QString &n)
+{
+ Q_D(QDeclarativeText);
+ 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);
+}
+
+
+/*!
+ \qmlproperty color Text::color
+
+ The text color.
+
+ An example of green text defined using hexadecimal notation:
+ \qml
+ Text {
+ color: "#00FF00"
+ text: "green text"
+ }
+ \endqml
+
+ An example of steel blue text defined using an SVG color name:
+ \qml
+ Text {
+ color: "steelblue"
+ text: "blue text"
+ }
+ \endqml
+*/
+QColor QDeclarativeText::color() const
+{
+ Q_D(const QDeclarativeText);
+ return d->color;
+}
+
+void QDeclarativeText::setColor(const QColor &color)
+{
+ Q_D(QDeclarativeText);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ d->invalidateImageCache();
+ emit colorChanged(d->color);
+}
+
+/*!
+ \qmlproperty enumeration Text::style
+
+ Set an additional text style.
+
+ Supported text styles are:
+ \list
+ \o Text.Normal - the default
+ \o Text.Outline
+ \o Text.Raised
+ \o Text.Sunken
+ \endlist
+
+ \qml
+ Row {
+ Text { font.pointSize: 24; text: "Normal" }
+ Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
+ Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
+ Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
+ }
+ \endqml
+
+ \image declarative-textstyle.png
+*/
+QDeclarativeText::TextStyle QDeclarativeText::style() const
+{
+ Q_D(const QDeclarativeText);
+ return d->style;
+}
+
+void QDeclarativeText::setStyle(QDeclarativeText::TextStyle style)
+{
+ Q_D(QDeclarativeText);
+ if (d->style == style)
+ return;
+
+ // changing to/from Normal requires the boundingRect() to change
+ if (isComponentComplete() && (d->style == Normal || style == Normal))
+ prepareGeometryChange();
+ d->style = style;
+ d->invalidateImageCache();
+ emit styleChanged(d->style);
+}
+
+/*!
+ \qmlproperty color Text::styleColor
+
+ Defines the secondary color used by text styles.
+
+ \c styleColor is used as the outline color for outlined text, and as the
+ shadow color for raised or sunken text. If no style has been set, it is not
+ used at all.
+
+ \qml
+ Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
+ \endqml
+
+ \sa style
+ */
+QColor QDeclarativeText::styleColor() const
+{
+ Q_D(const QDeclarativeText);
+ return d->styleColor;
+}
+
+void QDeclarativeText::setStyleColor(const QColor &color)
+{
+ Q_D(QDeclarativeText);
+ if (d->styleColor == color)
+ return;
+
+ d->styleColor = color;
+ d->invalidateImageCache();
+ emit styleColorChanged(d->styleColor);
+}
+
+
+/*!
+ \qmlproperty enumeration Text::horizontalAlignment
+ \qmlproperty enumeration Text::verticalAlignment
+ \qmlproperty enumeration Text::effectiveHorizontalAlignment
+
+ Sets the horizontal and vertical alignment of the text within the Text items
+ width and height. By default, the text is vertically aligned to the top. Horizontal
+ alignment follows the natural alignment of the text, for example text that is read
+ from left to right will be aligned to the left.
+
+ The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
+ \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
+ and \c Text.AlignVCenter.
+
+ Note that for a single line of text, the size of the text is the area of the text. In this common case,
+ all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
+ need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
+ that of the parent.
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of Text, use the read-only property \c effectiveHorizontalAlignment.
+*/
+QDeclarativeText::HAlignment QDeclarativeText::hAlign() const
+{
+ Q_D(const QDeclarativeText);
+ return d->hAlign;
+}
+
+void QDeclarativeText::setHAlign(HAlignment align)
+{
+ Q_D(QDeclarativeText);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete())
+ d->updateLayout();
+}
+
+void QDeclarativeText::resetHAlign()
+{
+ Q_D(QDeclarativeText);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete())
+ d->updateLayout();
+}
+
+QDeclarativeText::HAlignment QDeclarativeText::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeText);
+ QDeclarativeText::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeText::AlignLeft:
+ effectiveAlignment = QDeclarativeText::AlignRight;
+ break;
+ case QDeclarativeText::AlignRight:
+ effectiveAlignment = QDeclarativeText::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextPrivate::setHAlign(QDeclarativeText::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeText);
+ if (hAlign != alignment || forceAlign) {
+ QDeclarativeText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+
+ emit q->horizontalAlignmentChanged(hAlign);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QDeclarativeText);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QDeclarativeText::AlignRight : QDeclarativeText::AlignLeft);
+ }
+ return false;
+}
+
+void QDeclarativeTextPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeText);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeText::AlignRight || hAlign == QDeclarativeText::AlignLeft)) {
+ updateLayout();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QTextDocument *QDeclarativeTextPrivate::textDocument()
+{
+ return doc;
+}
+
+QDeclarativeText::VAlignment QDeclarativeText::vAlign() const
+{
+ Q_D(const QDeclarativeText);
+ return d->vAlign;
+}
+
+void QDeclarativeText::setVAlign(VAlignment align)
+{
+ Q_D(QDeclarativeText);
+ if (d->vAlign == align)
+ return;
+
+ if (isComponentComplete())
+ prepareGeometryChange();
+ d->vAlign = align;
+ emit verticalAlignmentChanged(align);
+}
+
+/*!
+ \qmlproperty enumeration Text::wrapMode
+
+ Set this property to wrap the text to the Text item's width. The text will only
+ wrap if an explicit width has been set. wrapMode can be one of:
+
+ \list
+ \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
+ \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
+ \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
+ \o Text.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
+ \endlist
+*/
+QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const
+{
+ Q_D(const QDeclarativeText);
+ return d->wrapMode;
+}
+
+void QDeclarativeText::setWrapMode(WrapMode mode)
+{
+ Q_D(QDeclarativeText);
+ if (mode == d->wrapMode)
+ return;
+
+ d->wrapMode = mode;
+ d->updateLayout();
+
+ emit wrapModeChanged();
+}
+
+/*!
+ \qmlproperty int Text::lineCount
+ \since Quick 1.1
+
+ Returns the number of lines visible in the text item.
+
+ This property is not supported for rich text.
+
+ \sa maximumLineCount
+*/
+int QDeclarativeText::lineCount() const
+{
+ Q_D(const QDeclarativeText);
+ return d->lineCount;
+}
+
+/*!
+ \qmlproperty bool Text::truncated
+ \since Quick 1.1
+
+ Returns true if the text has been truncated due to \l maximumLineCount
+ or \l elide.
+
+ This property is not supported for rich text.
+
+ \sa maximumLineCount, elide
+*/
+bool QDeclarativeText::truncated() const
+{
+ Q_D(const QDeclarativeText);
+ return d->truncated;
+}
+
+/*!
+ \qmlproperty int Text::maximumLineCount
+ \since Quick 1.1
+
+ Set this property to limit the number of lines that the text item will show.
+ If elide is set to Text.ElideRight, the text will be elided appropriately.
+ By default, this is the value of the largest possible integer.
+
+ This property is not supported for rich text.
+
+ \sa lineCount, elide
+*/
+int QDeclarativeText::maximumLineCount() const
+{
+ Q_D(const QDeclarativeText);
+ return d->maximumLineCount;
+}
+
+void QDeclarativeText::setMaximumLineCount(int lines)
+{
+ Q_D(QDeclarativeText);
+
+ d->maximumLineCountValid = lines==INT_MAX ? false : true;
+ if (d->maximumLineCount != lines) {
+ d->maximumLineCount = lines;
+ d->updateLayout();
+ emit maximumLineCountChanged();
+ }
+}
+
+void QDeclarativeText::resetMaximumLineCount()
+{
+ Q_D(QDeclarativeText);
+ setMaximumLineCount(INT_MAX);
+ d->elidePos = QPointF();
+ if (d->truncated != false) {
+ d->truncated = false;
+ emit truncatedChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration Text::textFormat
+
+ The way the text property should be displayed.
+
+ Supported text formats are:
+
+ \list
+ \o Text.AutoText (default)
+ \o Text.PlainText
+ \o Text.RichText
+ \o Text.StyledText
+ \endlist
+
+ If the text format is \c Text.AutoText the text element
+ will automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+
+ Text.StyledText is an optimized format supporting some basic text
+ styling markup, in the style of html 3.2:
+
+ \code
+ <font size="4" color="#ff0000">font size and color</font>
+ <b>bold</b>
+ <i>italic</i>
+ <br>
+ &gt; &lt; &amp;
+ \endcode
+
+ \c Text.StyledText parser is strict, requiring tags to be correctly nested.
+
+ \table
+ \row
+ \o
+ \qml
+Column {
+ Text {
+ font.pointSize: 24
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ Text {
+ font.pointSize: 24
+ textFormat: Text.RichText
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ Text {
+ font.pointSize: 24
+ textFormat: Text.PlainText
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+}
+ \endqml
+ \o \image declarative-textformat.png
+ \endtable
+*/
+QDeclarativeText::TextFormat QDeclarativeText::textFormat() const
+{
+ Q_D(const QDeclarativeText);
+ return d->format;
+}
+
+void QDeclarativeText::setTextFormat(TextFormat format)
+{
+ Q_D(QDeclarativeText);
+ 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);
+}
+
+/*!
+ \qmlproperty enumeration Text::elide
+
+ Set this property to elide parts of the text fit to the Text item's width.
+ The text will only elide if an explicit width has been set.
+
+ This property cannot be used with rich text.
+
+ Eliding can be:
+ \list
+ \o Text.ElideNone - the default
+ \o Text.ElideLeft
+ \o Text.ElideMiddle
+ \o Text.ElideRight
+ \endlist
+
+ If this property is set to Text.ElideRight, it can be used with multiline
+ text. The text will only elide if maximumLineCount has been set.
+
+ If the text is a multi-length string, and the mode is not \c Text.ElideNone,
+ the first string that fits will be used, otherwise the last will be elided.
+
+ Multi-length strings are ordered from longest to shortest, separated by the
+ Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
+*/
+QDeclarativeText::TextElideMode QDeclarativeText::elideMode() const
+{
+ Q_D(const QDeclarativeText);
+ return d->elideMode;
+}
+
+void QDeclarativeText::setElideMode(QDeclarativeText::TextElideMode mode)
+{
+ Q_D(QDeclarativeText);
+ if (mode == d->elideMode)
+ return;
+
+ d->elideMode = mode;
+ d->updateLayout();
+
+ emit elideModeChanged(d->elideMode);
+}
+
+/*! \internal */
+QRectF QDeclarativeText::boundingRect() const
+{
+ Q_D(const QDeclarativeText);
+
+ 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 QDeclarativeText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeText);
+ if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
+ && (d->wrapMode != QDeclarativeText::NoWrap
+ || d->elideMode != QDeclarativeText::ElideNone
+ || d->hAlign != QDeclarativeText::AlignLeft)) {
+ if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarativeText::ElideNone && widthValid()) {
+ // We need to re-elide
+ d->updateLayout();
+ } else {
+ // We just need to re-layout
+ d->updateSize();
+ }
+ }
+
+ QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+/*!
+ \qmlproperty real Text::paintedWidth
+
+ Returns the width of the text, including width past the width
+ which is covered due to insufficient wrapping if WrapMode is set.
+*/
+qreal QDeclarativeText::paintedWidth() const
+{
+ Q_D(const QDeclarativeText);
+ return d->paintedSize.width();
+}
+
+/*!
+ \qmlproperty real Text::paintedHeight
+
+ Returns the height of the text, including height past the height
+ which is covered due to there being more text than fits in the set height.
+*/
+qreal QDeclarativeText::paintedHeight() const
+{
+ Q_D(const QDeclarativeText);
+ return d->paintedSize.height();
+}
+
+/*!
+ \qmlproperty real Text::lineHeight
+ \since Quick 1.1
+
+ Sets the line height for the text.
+ The value can be in pixels or a multiplier depending on lineHeightMode.
+
+ The default value is a multiplier of 1.0.
+ The line height must be a positive value.
+*/
+qreal QDeclarativeText::lineHeight() const
+{
+ Q_D(const QDeclarativeText);
+ return d->lineHeight;
+}
+
+void QDeclarativeText::setLineHeight(qreal lineHeight)
+{
+ Q_D(QDeclarativeText);
+
+ if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
+ return;
+
+ d->lineHeight = lineHeight;
+ d->updateLayout();
+ emit lineHeightChanged(lineHeight);
+}
+
+/*!
+ \qmlproperty enumeration Text::lineHeightMode
+
+ This property determines how the line height is specified.
+ The possible values are:
+
+ \list
+ \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
+ line (as a multiplier). For example, set to 2 for double spacing.
+ \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
+ \endlist
+*/
+QDeclarativeText::LineHeightMode QDeclarativeText::lineHeightMode() const
+{
+ Q_D(const QDeclarativeText);
+ return d->lineHeightMode;
+}
+
+void QDeclarativeText::setLineHeightMode(LineHeightMode mode)
+{
+ Q_D(QDeclarativeText);
+ 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 QDeclarativeText::resourcesLoading() const
+{
+ Q_D(const QDeclarativeText);
+ return d->doc ? d->doc->resourcesLoading() : 0;
+}
+
+/*! \internal */
+void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ Q_D(QDeclarativeText);
+
+ if (d->cacheAllTextAsImage || d->style != Normal) {
+ d->checkImageCache();
+ if (d->imageCache.isNull())
+ return;
+
+ bool oldAA = p->testRenderHint(QPainter::Antialiasing);
+ bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
+ if (d->smooth)
+ p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
+
+ QRect br = boundingRect().toRect();
+
+ bool needClip = clip() && (d->imageCache.width() > width() ||
+ d->imageCache.height() > height());
+
+ if (needClip)
+ p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height());
+ else
+ p->drawPixmap(br.x(), br.y(), d->imageCache);
+
+ if (d->smooth) {
+ p->setRenderHint(QPainter::Antialiasing, oldAA);
+ p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
+ }
+ } else {
+ QRectF bounds = boundingRect();
+
+ bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
+ d->layedOutTextRect.height() > height());
+
+ if (needClip) {
+ p->save();
+ p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
+ }
+ if (d->richText) {
+ QAbstractTextDocumentLayout::PaintContext context;
+ context.palette.setColor(QPalette::Text, d->color);
+ p->translate(bounds.x(), bounds.y());
+ d->doc->documentLayout()->draw(p, context);
+ p->translate(-bounds.x(), -bounds.y());
+ } else {
+ d->drawTextLayout(p, QPointF(0, bounds.y()), false);
+ }
+
+ if (needClip) {
+ p->restore();
+ }
+ }
+}
+
+/*! \internal */
+void QDeclarativeText::componentComplete()
+{
+ Q_D(QDeclarativeText);
+ QDeclarativeItem::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 QDeclarativeText::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeText);
+
+ 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())
+ QDeclarativeItem::mousePressEvent(event);
+
+}
+
+/*! \internal */
+void QDeclarativeText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeText);
+
+ // ### 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())
+ QDeclarativeItem::mouseReleaseEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "qdeclarativetext.moc"
diff --git a/src/declarative/graphicsitems/qdeclarativetext_p.h b/src/declarative/graphicsitems/qdeclarativetext_p.h
new file mode 100644
index 0000000000..a1153c254e
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetext_p.h
@@ -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 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 QDECLARATIVETEXT_H
+#define QDECLARATIVETEXT_H
+
+#include <QtGui/qtextoption.h>
+#include "qdeclarativeimplicitsizeitem_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QDeclarativeTextPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeText : public QDeclarativeImplicitSizeItem
+{
+ 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 REVISION 1)
+ 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 REVISION 1)
+ Q_PROPERTY(bool truncated READ truncated NOTIFY truncatedChanged REVISION 1)
+ Q_PROPERTY(int maximumLineCount READ maximumLineCount WRITE setMaximumLineCount NOTIFY maximumLineCountChanged RESET resetMaximumLineCount REVISION 1)
+
+ 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 REVISION 1)
+ Q_PROPERTY(LineHeightMode lineHeightMode READ lineHeightMode WRITE setLineHeightMode NOTIFY lineHeightModeChanged REVISION 1)
+
+public:
+ QDeclarativeText(QDeclarativeItem *parent=0);
+ ~QDeclarativeText();
+
+ enum HAlignment { AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify }; // ### VERSIONING: Only in QtQuick 1.1
+ 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);
+
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+ 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();
+ Q_REVISION(1) void lineCountChanged();
+ Q_REVISION(1) void truncatedChanged();
+ Q_REVISION(1) void maximumLineCountChanged();
+ void textFormatChanged(TextFormat textFormat);
+ void elideModeChanged(TextElideMode mode);
+ void paintedSizeChanged();
+ Q_REVISION(1) void lineHeightChanged(qreal lineHeight);
+ Q_REVISION(1) void lineHeightModeChanged(LineHeightMode mode);
+ Q_REVISION(1) void effectiveHorizontalAlignmentChanged();
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeText)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeText)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeText)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h
new file mode 100644
index 0000000000..6a3d581734
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h
@@ -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 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 QDECLARATIVETEXT_P_H
+#define QDECLARATIVETEXT_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 "qdeclarativeitem.h"
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+#include "private/qdeclarativetextlayout_p.h"
+
+#include <qdeclarative.h>
+
+#include <QtGui/qtextlayout.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QTextDocumentWithImageResources;
+
+class Q_AUTOTEST_EXPORT QDeclarativeTextPrivate : public QDeclarativeImplicitSizeItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeText)
+public:
+ QDeclarativeTextPrivate();
+
+ ~QDeclarativeTextPrivate();
+
+ void updateSize();
+ void updateLayout();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QDeclarativeText::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ QTextDocument *textDocument();
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QDeclarativeText::TextStyle style;
+ QColor styleColor;
+ QString activeLink;
+ QDeclarativeText::HAlignment hAlign;
+ QDeclarativeText::VAlignment vAlign;
+ QDeclarativeText::TextElideMode elideMode;
+ QDeclarativeText::TextFormat format;
+ QDeclarativeText::WrapMode wrapMode;
+ qreal lineHeight;
+ QDeclarativeText::LineHeightMode lineHeightMode;
+ int lineCount;
+ bool truncated;
+ int maximumLineCount;
+ int maximumLineCountValid;
+ QPointF elidePos;
+
+ static QString elideChar;
+
+ void invalidateImageCache();
+ void checkImageCache();
+ QPixmap imageCache;
+
+ bool imageCacheDirty:1;
+ bool updateOnComponentComplete:1;
+ bool richText:1;
+ bool singleline:1;
+ bool cacheAllTextAsImage:1;
+ bool internalWidthUpdate:1;
+ bool requireImplicitWidth:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
+ bool layoutTextElided:1;
+
+ QRect layedOutTextRect;
+ QSize paintedSize;
+ qreal naturalWidth;
+ virtual qreal implicitWidth() const;
+ void ensureDoc();
+ QPixmap textDocumentImage(bool drawStyle);
+ QTextDocumentWithImageResources *doc;
+
+ QRect setupTextLayout();
+ QPixmap textLayoutImage(bool drawStyle);
+ void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle);
+ QDeclarativeTextLayout layout;
+
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource);
+ static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset);
+
+ static inline QDeclarativeTextPrivate *get(QDeclarativeText *t) {
+ return t->d_func();
+ }
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
new file mode 100644
index 0000000000..af2c8f38d7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
@@ -0,0 +1,1889 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetextedit_p.h"
+#include "private/qdeclarativetextedit_p_p.h"
+
+#include "private/qdeclarativeevents_p_p.h"
+#include <private/qdeclarativeglobal_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qmath.h>
+
+#include <private/qtextengine_p.h>
+#include <QTextLayout>
+#include <QTextLine>
+#include <QTextDocument>
+#include <QTextObject>
+#include <QGraphicsSceneMouseEvent>
+#include <QDebug>
+#include <QPainter>
+
+#include <private/qtextcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass TextEdit QDeclarativeTextEdit
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The TextEdit item displays multiple lines of editable formatted text.
+ \inherits Item
+
+ The TextEdit item displays a block of editable, formatted text.
+
+ It can display both plain and rich text. For example:
+
+ \qml
+TextEdit {
+ width: 240
+ text: "<b>Hello</b> <i>World!</i>"
+ font.family: "Helvetica"
+ font.pointSize: 20
+ color: "blue"
+ focus: true
+}
+ \endqml
+
+ \image declarative-textedit.gif
+
+ Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
+
+ Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
+ to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
+
+ \snippet snippets/declarative/texteditor.qml 0
+
+ A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
+ scrollbar, or a scrollbar that fades in to show location, etc.
+
+ Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
+ be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
+ from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
+
+ You can translate between cursor positions (characters from the start of the document) and pixel
+ points using positionAt() and positionToRectangle().
+
+ \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
+*/
+
+/*!
+ \qmlsignal TextEdit::onLinkActivated(string link)
+ \since Quick 1.1
+
+ This handler is called when the user clicks on a link embedded in the text.
+ The link must be in rich text or HTML format and the
+ \a link string provides access to the particular link.
+*/
+QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
+: QDeclarativeImplicitSizePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
+{
+ Q_D(QDeclarativeTextEdit);
+ d->init();
+}
+
+QString QDeclarativeTextEdit::text() const
+{
+ Q_D(const QDeclarativeTextEdit);
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (d->richText)
+ return d->document->toHtml();
+ else
+#endif
+ return d->document->toPlainText();
+}
+
+/*!
+ \qmlproperty string TextEdit::font.family
+
+ Sets the family name of the font.
+
+ The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+ If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+ If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+ \qmlproperty bool TextEdit::font.bold
+
+ Sets whether the font weight is bold.
+*/
+
+/*!
+ \qmlproperty enumeration TextEdit::font.weight
+
+ Sets the font's weight.
+
+ The weight can be one of:
+ \list
+ \o Font.Light
+ \o Font.Normal - the default
+ \o Font.DemiBold
+ \o Font.Bold
+ \o Font.Black
+ \endlist
+
+ \qml
+ TextEdit { text: "Hello"; font.weight: Font.DemiBold }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool TextEdit::font.italic
+
+ Sets whether the font has an italic style.
+*/
+
+/*!
+ \qmlproperty bool TextEdit::font.underline
+
+ Sets whether the text is underlined.
+*/
+
+/*!
+ \qmlproperty bool TextEdit::font.strikeout
+
+ Sets whether the font has a strikeout style.
+*/
+
+/*!
+ \qmlproperty real TextEdit::font.pointSize
+
+ Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+ \qmlproperty int TextEdit::font.pixelSize
+
+ Sets the font size in pixels.
+
+ Using this function makes the font device dependent. Use
+ \l{TextEdit::font.pointSize} to set the size of the font in a
+ device independent manner.
+*/
+
+/*!
+ \qmlproperty real TextEdit::font.letterSpacing
+
+ Sets the letter spacing for the font.
+
+ Letter spacing changes the default spacing between individual letters in the font.
+ A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
+*/
+
+/*!
+ \qmlproperty real TextEdit::font.wordSpacing
+
+ Sets the word spacing for the font.
+
+ Word spacing changes the default spacing between individual words.
+ A positive value increases the word spacing by a corresponding amount of pixels,
+ while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+ \qmlproperty enumeration TextEdit::font.capitalization
+
+ Sets the capitalization for the text.
+
+ \list
+ \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \endlist
+
+ \qml
+ TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
+ \endqml
+*/
+
+/*!
+ \qmlproperty string TextEdit::text
+
+ The text to display. If the text format is AutoText the text edit will
+ automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+*/
+void QDeclarativeTextEdit::setText(const QString &text)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (QDeclarativeTextEdit::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();
+}
+
+/*!
+ \qmlproperty enumeration TextEdit::textFormat
+
+ The way the text property should be displayed.
+
+ \list
+ \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
+ will automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+
+ \table
+ \row
+ \o
+ \qml
+Column {
+ TextEdit {
+ font.pointSize: 24
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ TextEdit {
+ font.pointSize: 24
+ textFormat: TextEdit.RichText
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ TextEdit {
+ font.pointSize: 24
+ textFormat: TextEdit.PlainText
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+}
+ \endqml
+ \o \image declarative-textformat.png
+ \endtable
+*/
+QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->format;
+}
+
+void QDeclarativeTextEdit::setTextFormat(TextFormat format)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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 QDeclarativeTextEdit::font() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->sourceFont;
+}
+
+void QDeclarativeTextEdit::setFont(const QFont &font)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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) {
+ clearCache();
+ d->document->setDefaultFont(d->font);
+ if(d->cursor){
+ d->cursor->setHeight(QFontMetrics(d->font).height());
+ moveCursorDelegate();
+ }
+ updateSize();
+ update();
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+/*!
+ \qmlproperty color TextEdit::color
+
+ The text color.
+
+ \qml
+ // green text using hexadecimal notation
+ TextEdit { color: "#00FF00" }
+ \endqml
+
+ \qml
+ // steelblue text using SVG color name
+ TextEdit { color: "steelblue" }
+ \endqml
+*/
+QColor QDeclarativeTextEdit::color() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->color;
+}
+
+void QDeclarativeTextEdit::setColor(const QColor &color)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->color == color)
+ return;
+
+ clearCache();
+ d->color = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Text, color);
+ d->control->setPalette(pal);
+ update();
+ emit colorChanged(d->color);
+}
+
+/*!
+ \qmlproperty color TextEdit::selectionColor
+
+ The text highlight color, used behind selections.
+*/
+QColor QDeclarativeTextEdit::selectionColor() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->selectionColor;
+}
+
+void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->selectionColor == color)
+ return;
+
+ clearCache();
+ d->selectionColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Highlight, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectionColorChanged(d->selectionColor);
+}
+
+/*!
+ \qmlproperty color TextEdit::selectedTextColor
+
+ The selected text color, used in selections.
+*/
+QColor QDeclarativeTextEdit::selectedTextColor() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->selectedTextColor;
+}
+
+void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->selectedTextColor == color)
+ return;
+
+ clearCache();
+ d->selectedTextColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::HighlightedText, color);
+ d->control->setPalette(pal);
+ update();
+ emit selectedTextColorChanged(d->selectedTextColor);
+}
+
+/*!
+ \qmlproperty enumeration TextEdit::horizontalAlignment
+ \qmlproperty enumeration TextEdit::verticalAlignment
+ \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment
+
+ Sets the horizontal and vertical alignment of the text within the TextEdit item's
+ width and height. By default, the text alignment follows the natural alignment
+ of the text, for example text that is read from left to right will be aligned to
+ the left.
+
+ Valid values for \c horizontalAlignment are:
+ \list
+ \o TextEdit.AlignLeft (default)
+ \o TextEdit.AlignRight
+ \o TextEdit.AlignHCenter
+ \o TextEdit.AlignJustify
+ \endlist
+
+ Valid values for \c verticalAlignment are:
+ \list
+ \o TextEdit.AlignTop (default)
+ \o TextEdit.AlignBottom
+ \o TextEdit.AlignVCenter
+ \endlist
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
+*/
+QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->hAlign;
+}
+
+void QDeclarativeTextEdit::setHAlign(HAlignment align)
+{
+ Q_D(QDeclarativeTextEdit);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+void QDeclarativeTextEdit::resetHAlign()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeTextEdit::AlignLeft:
+ effectiveAlignment = QDeclarativeTextEdit::AlignRight;
+ break;
+ case QDeclarativeTextEdit::AlignRight:
+ effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (hAlign != alignment || forceAlign) {
+ QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
+ }
+ return false;
+}
+
+void QDeclarativeTextEditPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
+ updateDefaultTextOption();
+ q->updateSize();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->vAlign;
+}
+
+void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (alignment == d->vAlign)
+ return;
+ d->vAlign = alignment;
+ d->updateDefaultTextOption();
+ updateSize();
+ moveCursorDelegate();
+ emit verticalAlignmentChanged(d->vAlign);
+}
+
+/*!
+ \qmlproperty enumeration TextEdit::wrapMode
+
+ Set this property to wrap the text to the TextEdit item's width.
+ The text will only wrap if an explicit width has been set.
+
+ \list
+ \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
+ \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
+ \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
+ \o TextEdit.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
+ \endlist
+
+ The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
+*/
+QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->wrapMode;
+}
+
+void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (mode == d->wrapMode)
+ return;
+ d->wrapMode = mode;
+ d->updateDefaultTextOption();
+ updateSize();
+ emit wrapModeChanged();
+}
+
+/*!
+ \qmlproperty int TextEdit::lineCount
+ \since Quick 1.1
+
+ Returns the total number of lines in the textEdit item.
+*/
+int QDeclarativeTextEdit::lineCount() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->lineCount;
+}
+
+/*!
+ \qmlproperty real TextEdit::paintedWidth
+
+ Returns the width of the text, including the width past the width
+ which is covered due to insufficient wrapping if \l wrapMode is set.
+*/
+qreal QDeclarativeTextEdit::paintedWidth() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->paintedSize.width();
+}
+
+/*!
+ \qmlproperty real TextEdit::paintedHeight
+
+ Returns the height of the text, including the height past the height
+ that is covered if the text does not fit within the set height.
+*/
+qreal QDeclarativeTextEdit::paintedHeight() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->paintedSize.height();
+}
+
+/*!
+ \qmlmethod rectangle TextEdit::positionToRectangle(position)
+
+ Returns the rectangle at the given \a position in the text. The x, y,
+ and height properties correspond to the cursor that would describe
+ that position.
+*/
+QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
+{
+ Q_D(const QDeclarativeTextEdit);
+ QTextCursor c(d->document);
+ c.setPosition(pos);
+ return d->control->cursorRect(c);
+
+}
+
+/*!
+ \qmlmethod int TextEdit::positionAt(int x, int y)
+
+ Returns the text position closest to pixel position (\a x, \a y).
+
+ Position 0 is before the first character, position 1 is after the first character
+ but before the second, and so on until position \l {text}.length, which is after all characters.
+*/
+int QDeclarativeTextEdit::positionAt(int x, int y) const
+{
+ Q_D(const QDeclarativeTextEdit);
+ 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 QDeclarativeTextEdit::moveCursorSelection(int pos)
+{
+ //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
+ Q_D(QDeclarativeTextEdit);
+ QTextCursor cursor = d->control->textCursor();
+ if (cursor.position() == pos)
+ return;
+ cursor.setPosition(pos, QTextCursor::KeepAnchor);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
+ \since Quick 1.1
+
+ Moves the cursor to \a position and updates the selection according to the optional \a mode
+ parameter. (To only move the cursor, set the \l cursorPosition property.)
+
+ When this method is called it additionally sets either the
+ selectionStart or the selectionEnd (whichever was at the previous cursor position)
+ to the specified position. This allows you to easily extend and contract the selected
+ text range.
+
+ The selection mode specifies whether the selection is updated on a per character or a per word
+ basis. If not specified the selection mode will default to TextEdit.SelectCharacters.
+
+ \list
+ \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
+ the previous cursor position) to the specified position.
+ \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
+ words between the specified postion and the previous cursor position. Words partially in the
+ range are included.
+ \endlist
+
+ For example, take this sequence of calls:
+
+ \code
+ cursorPosition = 5
+ moveCursorSelection(9, TextEdit.SelectCharacters)
+ moveCursorSelection(7, TextEdit.SelectCharacters)
+ \endcode
+
+ This moves the cursor to position 5, extend the selection end from 5 to 9
+ and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
+ selected (the 6th and 7th characters).
+
+ The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
+ before or on position 5 and extend the selection end to a word boundary on or past position 9.
+*/
+void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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);
+}
+
+/*!
+ \qmlproperty bool TextEdit::cursorVisible
+ If true the text edit shows a cursor.
+
+ This property is set and unset when the text edit gets active focus, but it can also
+ be set directly (useful, for example, if a KeyProxy might forward keys to it).
+*/
+bool QDeclarativeTextEdit::isCursorVisible() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->cursorVisible;
+}
+
+void QDeclarativeTextEdit::setCursorVisible(bool on)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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);
+}
+
+/*!
+ \qmlproperty int TextEdit::cursorPosition
+ The position of the cursor in the TextEdit.
+*/
+int QDeclarativeTextEdit::cursorPosition() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->textCursor().position();
+}
+
+void QDeclarativeTextEdit::setCursorPosition(int pos)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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);
+}
+
+/*!
+ \qmlproperty Component TextEdit::cursorDelegate
+ The delegate for the cursor in the TextEdit.
+
+ If you set a cursorDelegate for a TextEdit, this delegate will be used for
+ drawing the cursor instead of the standard cursor. An instance of the
+ delegate will be created and managed by the text edit when a cursor is
+ needed, and the x and y properties of delegate instance will be set so as
+ to be one pixel before the top left of the current character.
+
+ Note that the root item of the delegate component must be a QDeclarativeItem or
+ QDeclarativeItem derived item.
+*/
+QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->cursorComponent;
+}
+
+void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QDeclarativeTextEdit);
+ if(d->cursorComponent){
+ if(d->cursor){
+ d->control->setCursorWidth(-1);
+ dirtyCache(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 QDeclarativeTextEdit::loadCursorDelegate()
+{
+ Q_D(QDeclarativeTextEdit);
+ if(d->cursorComponent->isLoading())
+ return;
+ d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
+ if(d->cursor){
+ d->control->setCursorWidth(0);
+ dirtyCache(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.";
+ }
+}
+
+/*!
+ \qmlproperty int TextEdit::selectionStart
+
+ The cursor position before the first character in the current selection.
+
+ This property is read-only. To change the selection, use select(start,end),
+ selectAll(), or selectWord().
+
+ \sa selectionEnd, cursorPosition, selectedText
+*/
+int QDeclarativeTextEdit::selectionStart() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->textCursor().selectionStart();
+}
+
+/*!
+ \qmlproperty int TextEdit::selectionEnd
+
+ The cursor position after the last character in the current selection.
+
+ This property is read-only. To change the selection, use select(start,end),
+ selectAll(), or selectWord().
+
+ \sa selectionStart, cursorPosition, selectedText
+*/
+int QDeclarativeTextEdit::selectionEnd() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->textCursor().selectionEnd();
+}
+
+/*!
+ \qmlproperty string TextEdit::selectedText
+
+ This read-only property provides the text currently selected in the
+ text edit.
+
+ It is equivalent to the following snippet, but is faster and easier
+ to use.
+ \code
+ //myTextEdit is the id of the TextEdit
+ myTextEdit.text.toString().substring(myTextEdit.selectionStart,
+ myTextEdit.selectionEnd);
+ \endcode
+*/
+QString QDeclarativeTextEdit::selectedText() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->textCursor().selectedText();
+}
+
+/*!
+ \qmlproperty bool TextEdit::activeFocusOnPress
+
+ Whether the TextEdit should gain active focus on a mouse press. By default this is
+ set to true.
+*/
+bool QDeclarativeTextEdit::focusOnPress() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->focusOnPress;
+}
+
+void QDeclarativeTextEdit::setFocusOnPress(bool on)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->focusOnPress == on)
+ return;
+ d->focusOnPress = on;
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+/*!
+ \qmlproperty bool TextEdit::persistentSelection
+
+ Whether the TextEdit should keep the selection visible when it loses active focus to another
+ item in the scene. By default this is set to true;
+*/
+bool QDeclarativeTextEdit::persistentSelection() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->persistentSelection;
+}
+
+void QDeclarativeTextEdit::setPersistentSelection(bool on)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->persistentSelection == on)
+ return;
+ d->persistentSelection = on;
+ emit persistentSelectionChanged(d->persistentSelection);
+}
+
+/*
+ \qmlproperty real TextEdit::textMargin
+
+ The margin, in pixels, around the text in the TextEdit.
+*/
+qreal QDeclarativeTextEdit::textMargin() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->textMargin;
+}
+
+void QDeclarativeTextEdit::setTextMargin(qreal margin)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->textMargin == margin)
+ return;
+ d->textMargin = margin;
+ d->document->setDocumentMargin(d->textMargin);
+ emit textMarginChanged(d->textMargin);
+}
+
+void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width())
+ updateSize();
+ QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+/*!
+ Ensures any delayed caching or data loading the class
+ needs to performed is complete.
+*/
+void QDeclarativeTextEdit::componentComplete()
+{
+ Q_D(QDeclarativeTextEdit);
+ QDeclarativePaintedItem::componentComplete();
+ if (d->dirty) {
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ d->dirty = false;
+ }
+}
+
+/*!
+ \qmlproperty bool TextEdit::selectByMouse
+
+ Defaults to false.
+
+ If true, the user can use the mouse to select text in some
+ platform-specific way. Note that for some platforms this may
+ not be an appropriate interaction (eg. may conflict with how
+ the text needs to behave inside a Flickable.
+*/
+bool QDeclarativeTextEdit::selectByMouse() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->selectByMouse;
+}
+
+void QDeclarativeTextEdit::setSelectByMouse(bool on)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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);
+ }
+}
+
+
+/*!
+ \qmlproperty enum TextEdit::mouseSelectionMode
+ \since Quick 1.1
+
+ Specifies how text should be selected using a mouse.
+
+ \list
+ \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
+ \o TextEdit.SelectWords - The selection is updated with whole words.
+ \endlist
+
+ This property only applies when \l selectByMouse is true.
+*/
+
+QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->mouseSelectionMode;
+}
+
+void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ d->control->setWordSelectionEnabled(mode == SelectWords);
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+/*!
+ \qmlproperty bool TextEdit::readOnly
+
+ Whether the user an 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.
+*/
+void QDeclarativeTextEdit::setReadOnly(bool r)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (r == isReadOnly())
+ return;
+
+ setFlag(QGraphicsItem::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 QDeclarativeTextEdit::isReadOnly() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+/*!
+ Sets how the text edit should interact with user input to the given
+ \a flags.
+*/
+void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+/*!
+ Returns the flags specifying how the text edit should interact
+ with user input.
+*/
+Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+/*!
+ \qmlproperty rectangle TextEdit::cursorRectangle
+
+ The rectangle where the text cursor is rendered
+ within the text edit. Read-only.
+*/
+QRect QDeclarativeTextEdit::cursorRectangle() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->cursorRect().toRect().translated(0,d->yoff);
+}
+
+
+/*!
+\overload
+Handles the given \a event.
+*/
+bool QDeclarativeTextEdit::event(QEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (event->type() == QEvent::ShortcutOverride) {
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ return event->isAccepted();
+ }
+ return QDeclarativePaintedItem::event(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ keyPressPreHandler(event);
+ if (!event->isAccepted())
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::keyPressEvent(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ keyReleasePreHandler(event);
+ if (!event->isAccepted())
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::keyReleaseEvent(event);
+}
+
+void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
+{
+ Q_Q(QDeclarativeTextEdit);
+ q->setCursorVisible(hasFocus && scene && scene->hasFocus());
+ QDeclarativeItemPrivate::focusChanged(hasFocus);
+}
+
+/*!
+ \qmlmethod void TextEdit::deselect()
+ \since Quick 1.1
+
+ Removes active text selection.
+*/
+void QDeclarativeTextEdit::deselect()
+{
+ Q_D(QDeclarativeTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.clearSelection();
+ d->control->setTextCursor(c);
+}
+
+/*!
+ \qmlmethod void TextEdit::selectAll()
+
+ Causes all text to be selected.
+*/
+void QDeclarativeTextEdit::selectAll()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->selectAll();
+}
+
+/*!
+ \qmlmethod void TextEdit::selectWord()
+
+ Causes the word closest to the current cursor position to be selected.
+*/
+void QDeclarativeTextEdit::selectWord()
+{
+ Q_D(QDeclarativeTextEdit);
+ QTextCursor c = d->control->textCursor();
+ c.select(QTextCursor::WordUnderCursor);
+ d->control->setTextCursor(c);
+}
+
+/*!
+ \qmlmethod void TextEdit::select(int start, int end)
+
+ Causes the text from \a start to \a end to be selected.
+
+ If either start or end is out of range, the selection is not changed.
+
+ After calling this, selectionStart will become the lesser
+ and selectionEnd will become the greater (regardless of the order passed
+ to this method).
+
+ \sa selectionStart, selectionEnd
+*/
+void QDeclarativeTextEdit::select(int start, int end)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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();
+}
+
+/*!
+ \qmlmethod void TextEdit::isRightToLeft(int start, int end)
+
+ Returns true if the natural reading direction of the editor text
+ found between positions \a start and \a end is right to left.
+*/
+bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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
+/*!
+ \qmlmethod TextEdit::cut()
+
+ Moves the currently selected text to the system clipboard.
+*/
+void QDeclarativeTextEdit::cut()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->cut();
+}
+
+/*!
+ \qmlmethod TextEdit::copy()
+
+ Copies the currently selected text to the system clipboard.
+*/
+void QDeclarativeTextEdit::copy()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->copy();
+}
+
+/*!
+ \qmlmethod TextEdit::paste()
+
+ Replaces the currently selected text by the contents of the system clipboard.
+*/
+void QDeclarativeTextEdit::paste()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ 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())
+ QDeclarativePaintedItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::mouseReleaseEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::mouseDoubleClickEvent(event);
+
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::mouseMoveEvent(event);
+}
+
+/*!
+\overload
+Handles the given input method \a event.
+*/
+void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QDeclarativeTextEdit);
+ const bool wasComposing = isInputMethodComposing();
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (wasComposing != isInputMethodComposing())
+ emit inputMethodComposingChanged();
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->control->inputMethodQuery(property);
+}
+
+/*!
+Draws the contents of the text edit using the given \a painter within
+the given \a bounds.
+*/
+void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
+{
+ Q_D(QDeclarativeTextEdit);
+
+ 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 QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
+{
+ Q_D(const QDeclarativeTextEdit);
+ 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);
+ }
+ }
+ dirtyCache(r);
+ emit update();
+}
+
+/*!
+ \qmlproperty bool TextEdit::smooth
+
+ This property holds whether the text is smoothly scaled or transformed.
+
+ Smooth filtering gives better visual quality, but is slower. If
+ the item is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the item is stationary on
+ the screen. A common pattern when animating an item is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+ \qmlproperty bool TextEdit::canPaste
+ \since QtQuick 1.1
+
+ Returns true if the TextEdit is writable and the content of the clipboard is
+ suitable for pasting into the TextEdit.
+*/
+bool QDeclarativeTextEdit::canPaste() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ return d->canPaste;
+}
+
+/*!
+ \qmlproperty bool TextEdit::inputMethodComposing
+
+ \since QtQuick 1.1
+
+ This property holds whether the TextEdit has partial text input from an
+ input method.
+
+ While it is composing an input method may rely on mouse or key events from
+ the TextEdit to edit or commit the partial text. This property can be used
+ to determine when to disable events handlers that may interfere with the
+ correct operation of an input method.
+*/
+bool QDeclarativeTextEdit::isInputMethodComposing() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ if (QTextLayout *layout = d->control->textCursor().block().layout())
+ return layout->preeditAreaText().length() > 0;
+ return false;
+}
+
+void QDeclarativeTextEditPrivate::init()
+{
+ Q_Q(QDeclarativeTextEdit);
+
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QGraphicsItem::ItemHasNoContents, false);
+ q->setFlag(QGraphicsItem::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(microFocusChanged()), q, SLOT(moveCursorDelegate()));
+ 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 QDeclarativeTextEdit::q_textChanged()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->text = text();
+ d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
+ updateSize();
+ updateTotalLines();
+ emit textChanged(d->text);
+}
+
+void QDeclarativeTextEdit::moveCursorDelegate()
+{
+ Q_D(QDeclarativeTextEdit);
+ updateMicroFocus();
+ emit cursorRectangleChanged();
+ if(!d->cursor)
+ return;
+ QRectF cursorRect = cursorRectangle();
+ d->cursor->setX(cursorRect.x());
+ d->cursor->setY(cursorRect.y());
+}
+
+void QDeclarativeTextEditPrivate::updateSelection()
+{
+ Q_Q(QDeclarativeTextEdit);
+ 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 QDeclarativeTextEdit::updateSelectionMarkers()
+{
+ Q_D(QDeclarativeTextEdit);
+ 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();
+ }
+}
+
+QRectF QDeclarativeTextEdit::boundingRect() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ QRectF r = QDeclarativePaintedItem::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 QDeclarativeTextEditPrivate::implicitWidth() const
+{
+ Q_Q(const QDeclarativeTextEdit);
+ 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<QDeclarativeTextEditPrivate*>(this)->requireImplicitWidth = true;
+ const_cast<QDeclarativeTextEdit*>(q)->updateSize();
+ }
+ return mImplicitWidth;
+}
+
+//### 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 QDeclarativeTextEdit::updateSize()
+{
+ Q_D(QDeclarativeTextEdit);
+ if (isComponentComplete()) {
+ qreal naturalWidth = d->mImplicitWidth;
+ // ### 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) {
+ prepareGeometryChange();
+ 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;
+ }
+ emit update();
+}
+
+void QDeclarativeTextEdit::updateTotalLines()
+{
+ Q_D(QDeclarativeTextEdit);
+
+ 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 QDeclarativeTextEditPrivate::updateDefaultTextOption()
+{
+ Q_Q(QDeclarativeTextEdit);
+ QTextOption opt = document->defaultTextOption();
+ int oldAlignment = opt.alignment();
+
+ QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
+ horizontalAlignment = QDeclarativeTextEdit::AlignRight;
+ else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
+ horizontalAlignment = QDeclarativeTextEdit::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);
+}
+
+
+/*!
+ \qmlmethod void TextEdit::openSoftwareInputPanel()
+
+ Opens software input panels like virtual keyboards for typing, useful for
+ customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. On Symbian^1 and
+ Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
+ the panels are automatically opened when TextEdit element gains active focus. Input panels are
+ always closed if no editor has active focus.
+
+ You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \code
+ import QtQuick 1.0
+ TextEdit {
+ id: textEdit
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textEdit.activeFocus) {
+ textEdit.forceActiveFocus();
+ textEdit.openSoftwareInputPanel();
+ } else {
+ textEdit.focus = false;
+ }
+ }
+ onPressAndHold: textEdit.closeSoftwareInputPanel();
+ }
+ }
+ \endcode
+*/
+void QDeclarativeTextEdit::openSoftwareInputPanel()
+{
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ if (qApp) {
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ QApplication::sendEvent(view, &event);
+ }
+ }
+ }
+}
+
+/*!
+ \qmlmethod void TextEdit::closeSoftwareInputPanel()
+
+ Closes a software input panel like a virtual keyboard shown on the screen, useful
+ for customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. On Symbian^1 and
+ Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
+ the panels are automatically opened when TextEdit element gains active focus. Input panels are
+ always closed if no editor has active focus.
+
+ You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \code
+ import QtQuick 1.0
+ TextEdit {
+ id: textEdit
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textEdit.activeFocus) {
+ textEdit.forceActiveFocus();
+ textEdit.openSoftwareInputPanel();
+ } else {
+ textEdit.focus = false;
+ }
+ }
+ onPressAndHold: textEdit.closeSoftwareInputPanel();
+ }
+ }
+ \endcode
+*/
+void QDeclarativeTextEdit::closeSoftwareInputPanel()
+{
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ if (qApp) {
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ QApplication::sendEvent(view, &event);
+ }
+ }
+ }
+}
+
+void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QDeclarativeTextEdit);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QDeclarativePaintedItem::focusInEvent(event);
+}
+
+void QDeclarativeTextEdit::q_canPasteChanged()
+{
+ Q_D(QDeclarativeTextEdit);
+ bool old = d->canPaste;
+ d->canPaste = d->control->canPaste();
+ if(old!=d->canPaste)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h
new file mode 100644
index 0000000000..25ca1e7497
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVETEXTEDIT_H
+#define QDECLARATIVETEXTEDIT_H
+
+#include "private/qdeclarativetext_p.h"
+#include "private/qdeclarativeimplicitsizeitem_p.h"
+
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextoption.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qtextformat.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QDeclarativeTextEditPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePaintedItem
+{
+ 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 REVISION 1)
+ 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 REVISION 1)
+ 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 REVISION 1)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1)
+
+public:
+ QDeclarativeTextEdit(QDeclarativeItem *parent=0);
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter,
+ AlignJustify = Qt::AlignJustify // ### VERSIONING: Only in QtQuick 1.1
+ };
+
+ 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 Q_REVISION(1) 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);
+ Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode);
+ Q_REVISION(1) void linkActivated(const QString &link);
+ Q_REVISION(1) void canPasteChanged();
+ Q_REVISION(1) void inputMethodComposingChanged();
+ Q_REVISION(1) void effectiveHorizontalAlignmentChanged();
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ Q_REVISION(1) void deselect();
+ Q_REVISION(1) 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);
+
+ void drawContents(QPainter *, const QRect &);
+private:
+ Q_DISABLE_COPY(QDeclarativeTextEdit)
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeTextEdit)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTextEdit)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h
new file mode 100644
index 0000000000..36e1b5105a
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h
@@ -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 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 QDECLARATIVETEXTEDIT_P_H
+#define QDECLARATIVETEXTEDIT_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 "qdeclarativeitem.h"
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+
+#include <qdeclarative.h>
+
+QT_BEGIN_NAMESPACE
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+class QDeclarativeTextEditPrivate : public QDeclarativeImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTextEdit)
+
+public:
+ QDeclarativeTextEditPrivate()
+ : color("black"), hAlign(QDeclarativeTextEdit::AlignLeft), vAlign(QDeclarativeTextEdit::AlignTop),
+ imgDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true), requireImplicitWidth(false),
+ hAlignImplicit(true), rightToLeftText(false), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0),
+ cursorComponent(0), cursor(0), format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap),
+ mouseSelectionMode(QDeclarativeTextEdit::SelectCharacters), selectByMouse(false), canPaste(false),
+ 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(QDeclarativeTextEdit::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ qreal implicitWidth() const;
+ void focusChanged(bool);
+
+ QString text;
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QString style;
+ QColor styleColor;
+ QPixmap imgCache;
+ QPixmap imgStyleCache;
+ QDeclarativeTextEdit::HAlignment hAlign;
+ QDeclarativeTextEdit::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 hAlignImplicit:1;
+ bool rightToLeftText:1;
+ qreal textMargin;
+ int lastSelectionStart;
+ int lastSelectionEnd;
+ QDeclarativeComponent* cursorComponent;
+ QDeclarativeItem* cursor;
+ QDeclarativeTextEdit::TextFormat format;
+ QTextDocument *document;
+ QTextControl *control;
+ QDeclarativeTextEdit::WrapMode wrapMode;
+ QDeclarativeTextEdit::SelectionMode mouseSelectionMode;
+ int lineCount;
+ bool selectByMouse;
+ bool canPaste;
+ int yoff;
+ QSize paintedSize;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
new file mode 100644
index 0000000000..9a917690f1
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
@@ -0,0 +1,2023 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetextinput_p.h"
+#include "private/qdeclarativetextinput_p_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <QValidator>
+#include <QTextCursor>
+#include <QApplication>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QTextBoundaryFinder>
+#include <QInputContext>
+#include <qstyle.h>
+
+#ifndef QT_NO_LINEEDIT
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass TextInput QDeclarativeTextInput
+ \ingroup qml-basic-visual-elements
+ \since 4.7
+ \brief The TextInput item displays an editable line of text.
+ \inherits Item
+
+ The TextInput element displays a single line of editable plain text.
+
+ TextInput is used to accept a line of text input. Input constraints
+ can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
+ and setting \l echoMode to an appropriate value enables TextInput to be used for
+ a password input field.
+
+ On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
+ If you want such bindings (on any platform), you will need to construct them in QML.
+
+ \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
+*/
+QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent)
+ : QDeclarativeImplicitSizePaintedItem(*(new QDeclarativeTextInputPrivate), parent)
+{
+ Q_D(QDeclarativeTextInput);
+ d->init();
+}
+
+QDeclarativeTextInput::~QDeclarativeTextInput()
+{
+}
+
+/*!
+ \qmlproperty string TextInput::text
+
+ The text in the TextInput.
+*/
+
+QString QDeclarativeTextInput::text() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->text();
+}
+
+void QDeclarativeTextInput::setText(const QString &s)
+{
+ Q_D(QDeclarativeTextInput);
+ if(s == text())
+ return;
+ d->control->setText(s);
+}
+
+/*!
+ \qmlproperty string TextInput::font.family
+
+ Sets the family name of the font.
+
+ The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+ If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+ If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+ \qmlproperty bool TextInput::font.bold
+
+ Sets whether the font weight is bold.
+*/
+
+/*!
+ \qmlproperty enumeration TextInput::font.weight
+
+ Sets the font's weight.
+
+ The weight can be one of:
+ \list
+ \o Font.Light
+ \o Font.Normal - the default
+ \o Font.DemiBold
+ \o Font.Bold
+ \o Font.Black
+ \endlist
+
+ \qml
+ TextInput { text: "Hello"; font.weight: Font.DemiBold }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool TextInput::font.italic
+
+ Sets whether the font has an italic style.
+*/
+
+/*!
+ \qmlproperty bool TextInput::font.underline
+
+ Sets whether the text is underlined.
+*/
+
+/*!
+ \qmlproperty bool TextInput::font.strikeout
+
+ Sets whether the font has a strikeout style.
+*/
+
+/*!
+ \qmlproperty real TextInput::font.pointSize
+
+ Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+ \qmlproperty int TextInput::font.pixelSize
+
+ Sets the font size in pixels.
+
+ Using this function makes the font device dependent.
+ Use \c pointSize to set the size of the font in a device independent manner.
+*/
+
+/*!
+ \qmlproperty real TextInput::font.letterSpacing
+
+ Sets the letter spacing for the font.
+
+ Letter spacing changes the default spacing between individual letters in the font.
+ A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
+*/
+
+/*!
+ \qmlproperty real TextInput::font.wordSpacing
+
+ Sets the word spacing for the font.
+
+ Word spacing changes the default spacing between individual words.
+ A positive value increases the word spacing by a corresponding amount of pixels,
+ while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+ \qmlproperty enumeration TextInput::font.capitalization
+
+ Sets the capitalization for the text.
+
+ \list
+ \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \endlist
+
+ \qml
+ TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
+ \endqml
+*/
+
+QFont QDeclarativeTextInput::font() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->sourceFont;
+}
+
+void QDeclarativeTextInput::setFont(const QFont &font)
+{
+ Q_D(QDeclarativeTextInput);
+ 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);
+}
+
+/*!
+ \qmlproperty color TextInput::color
+
+ The text color.
+*/
+QColor QDeclarativeTextInput::color() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->color;
+}
+
+void QDeclarativeTextInput::setColor(const QColor &c)
+{
+ Q_D(QDeclarativeTextInput);
+ if (c != d->color) {
+ d->color = c;
+ clearCache();
+ update();
+ emit colorChanged(c);
+ }
+}
+
+
+/*!
+ \qmlproperty color TextInput::selectionColor
+
+ The text highlight color, used behind selections.
+*/
+QColor QDeclarativeTextInput::selectionColor() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->selectionColor;
+}
+
+void QDeclarativeTextInput::setSelectionColor(const QColor &color)
+{
+ Q_D(QDeclarativeTextInput);
+ 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()) {
+ clearCache();
+ update();
+ }
+ emit selectionColorChanged(color);
+}
+
+/*!
+ \qmlproperty color TextInput::selectedTextColor
+
+ The highlighted text color, used in selections.
+*/
+QColor QDeclarativeTextInput::selectedTextColor() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->selectedTextColor;
+}
+
+void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QDeclarativeTextInput);
+ 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()) {
+ clearCache();
+ update();
+ }
+ emit selectedTextColorChanged(color);
+}
+
+/*!
+ \qmlproperty enumeration TextInput::horizontalAlignment
+ \qmlproperty enumeration TextInput::effectiveHorizontalAlignment
+
+ Sets the horizontal alignment of the text within the TextInput item's
+ width and height. By default, the text alignment follows the natural alignment
+ of the text, for example text that is read from left to right will be aligned to
+ the left.
+
+ TextInput does not have vertical alignment, as the natural height is
+ exactly the height of the single line of text. If you set the height
+ manually to something larger, TextInput will always be top aligned
+ vertically. You can use anchors to align it however you want within
+ another item.
+
+ The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
+ \c TextInput.AlignHCenter.
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->hAlign;
+}
+
+void QDeclarativeTextInput::setHAlign(HAlignment align)
+{
+ Q_D(QDeclarativeTextInput);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+void QDeclarativeTextInput::resetHAlign()
+{
+ Q_D(QDeclarativeTextInput);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+QDeclarativeTextInput::HAlignment QDeclarativeTextInput::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeTextInput);
+ QDeclarativeTextInput::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeTextInput::AlignLeft:
+ effectiveAlignment = QDeclarativeTextInput::AlignRight;
+ break;
+ case QDeclarativeTextInput::AlignRight:
+ effectiveAlignment = QDeclarativeTextInput::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextInputPrivate::setHAlign(QDeclarativeTextInput::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeTextInput);
+ if ((hAlign != alignment || forceAlign) && alignment <= QDeclarativeTextInput::AlignHCenter) { // justify not supported
+ QDeclarativeTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextInputPrivate::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 ? QDeclarativeTextInput::AlignRight : QDeclarativeTextInput::AlignLeft);
+ }
+ return false;
+}
+
+void QDeclarativeTextInputPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeTextInput);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeTextInput::AlignRight || hAlign == QDeclarativeTextInput::AlignLeft)) {
+ q->updateRect();
+ updateHorizontalScroll();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool TextInput::readOnly
+
+ Sets whether user input can modify the contents of the TextInput.
+
+ If readOnly is set to true, then user input will not affect the text
+ property. Any bindings or attempts to set the text property will still
+ work.
+*/
+
+bool QDeclarativeTextInput::isReadOnly() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->isReadOnly();
+}
+
+void QDeclarativeTextInput::setReadOnly(bool ro)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->control->isReadOnly() == ro)
+ return;
+
+ setFlag(QGraphicsItem::ItemAcceptsInputMethod, !ro);
+ d->control->setReadOnly(ro);
+
+ emit readOnlyChanged(ro);
+}
+
+/*!
+ \qmlproperty int TextInput::maximumLength
+ The maximum permitted length of the text in the TextInput.
+
+ If the text is too long, it is truncated at the limit.
+
+ By default, this property contains a value of 32767.
+*/
+int QDeclarativeTextInput::maxLength() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->maxLength();
+}
+
+void QDeclarativeTextInput::setMaxLength(int ml)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->control->maxLength() == ml)
+ return;
+
+ d->control->setMaxLength(ml);
+
+ emit maximumLengthChanged(ml);
+}
+
+/*!
+ \qmlproperty bool TextInput::cursorVisible
+ Set to true when the TextInput shows a cursor.
+
+ This property is set and unset when the TextInput gets active focus, so that other
+ properties can be bound to whether the cursor is currently showing. As it
+ gets set and unset automatically, when you set the value yourself you must
+ keep in mind that your value may be overwritten.
+
+ It can be set directly in script, for example if a KeyProxy might
+ forward keys to it and you desire it to look active when this happens
+ (but without actually giving it active focus).
+
+ It should not be set directly on the element, like in the below QML,
+ as the specified value will be overridden an lost on focus changes.
+
+ \code
+ TextInput {
+ text: "Text"
+ cursorVisible: false
+ }
+ \endcode
+
+ In the above snippet the cursor will still become visible when the
+ TextInput gains active focus.
+*/
+bool QDeclarativeTextInput::isCursorVisible() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->cursorVisible;
+}
+
+void QDeclarativeTextInput::setCursorVisible(bool on)
+{
+ Q_D(QDeclarativeTextInput);
+ 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);
+}
+
+/*!
+ \qmlproperty int TextInput::cursorPosition
+ The position of the cursor in the TextInput.
+*/
+int QDeclarativeTextInput::cursorPosition() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->cursor();
+}
+void QDeclarativeTextInput::setCursorPosition(int cp)
+{
+ Q_D(QDeclarativeTextInput);
+ if (cp < 0 || cp > d->control->text().length())
+ return;
+ d->control->moveCursor(cp);
+}
+
+/*!
+ Returns a Rect which encompasses the cursor, but which may be larger than is
+ required. Ignores custom cursor delegates.
+*/
+QRect QDeclarativeTextInput::cursorRectangle() const
+{
+ Q_D(const QDeclarativeTextInput);
+ 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;
+}
+
+/*!
+ \qmlproperty int TextInput::selectionStart
+
+ The cursor position before the first character in the current selection.
+ Setting this and selectionEnd allows you to specify a selection in the
+ text edit.
+
+ Note that if selectionStart == selectionEnd then there is no current
+ selection.
+
+ \sa selectionEnd, cursorPosition, selectedText, select()
+*/
+int QDeclarativeTextInput::selectionStart() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->lastSelectionStart;
+}
+
+/*!
+ \qmlproperty int TextInput::selectionEnd
+
+ The cursor position after the last character in the current selection.
+ Setting this and selectionStart allows you to specify a selection in the
+ text edit.
+
+ Note that if selectionStart == selectionEnd then there is no current
+ selection.
+
+ \sa selectionStart, cursorPosition, selectedText, select()
+*/
+int QDeclarativeTextInput::selectionEnd() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->lastSelectionEnd;
+}
+
+/*!
+ \qmlmethod void TextInput::select(int start, int end)
+
+ Causes the text from \a start to \a end to be selected.
+
+ If either start or end is out of range, the selection is not changed.
+
+ After calling this, selectionStart will become the lesser
+ and selectionEnd will become the greater (regardless of the order passed
+ to this method).
+
+ \sa selectionStart, selectionEnd
+*/
+void QDeclarativeTextInput::select(int start, int end)
+{
+ Q_D(QDeclarativeTextInput);
+ if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
+ return;
+ d->control->setSelection(start, end-start);
+}
+
+/*!
+ \qmlproperty string TextInput::selectedText
+
+ This read-only property provides the text currently selected in the
+ text input.
+
+ It is equivalent to the following snippet, but is faster and easier
+ to use.
+
+ \js
+ myTextInput.text.toString().substring(myTextInput.selectionStart,
+ myTextInput.selectionEnd);
+ \endjs
+*/
+QString QDeclarativeTextInput::selectedText() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->selectedText();
+}
+
+/*!
+ \qmlproperty bool TextInput::activeFocusOnPress
+
+ Whether the TextInput should gain active focus on a mouse press. By default this is
+ set to true.
+*/
+bool QDeclarativeTextInput::focusOnPress() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->focusOnPress;
+}
+
+void QDeclarativeTextInput::setFocusOnPress(bool b)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->focusOnPress == b)
+ return;
+
+ d->focusOnPress = b;
+
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+
+/*!
+ \qmlproperty bool TextInput::autoScroll
+
+ Whether the TextInput should scroll when the text is longer than the width. By default this is
+ set to true.
+*/
+bool QDeclarativeTextInput::autoScroll() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->autoScroll;
+}
+
+void QDeclarativeTextInput::setAutoScroll(bool b)
+{
+ Q_D(QDeclarativeTextInput);
+ 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);
+}
+
+/*!
+ \qmlclass IntValidator QIntValidator
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator for integer values.
+
+ IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
+ will accept locale specific digits, group separators, and positive and negative signs. In
+ addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
+ locale.
+*/
+/*!
+ \qmlproperty int IntValidator::top
+
+ This property holds the validator's highest acceptable value.
+ By default, this property's value is derived from the highest signed integer available (typically 2147483647).
+*/
+/*!
+ \qmlproperty int IntValidator::bottom
+
+ This property holds the validator's lowest acceptable value.
+ By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
+*/
+
+/*!
+ \qmlclass DoubleValidator QDoubleValidator
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator for non-integer numbers.
+*/
+
+/*!
+ \qmlproperty real DoubleValidator::top
+
+ This property holds the validator's maximum acceptable value.
+ By default, this property contains a value of infinity.
+*/
+/*!
+ \qmlproperty real DoubleValidator::bottom
+
+ This property holds the validator's minimum acceptable value.
+ By default, this property contains a value of -infinity.
+*/
+/*!
+ \qmlproperty int DoubleValidator::decimals
+
+ This property holds the validator's maximum number of digits after the decimal point.
+ By default, this property contains a value of 1000.
+*/
+/*!
+ \qmlproperty enumeration DoubleValidator::notation
+ This property holds the notation of how a string can describe a number.
+
+ The possible values for this property are:
+
+ \list
+ \o DoubleValidator.StandardNotation
+ \o DoubleValidator.ScientificNotation (default)
+ \endlist
+
+ If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
+*/
+
+/*!
+ \qmlclass RegExpValidator QRegExpValidator
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator, which counts as valid any string which
+ matches a specified regular expression.
+*/
+/*!
+ \qmlproperty regExp RegExpValidator::regExp
+
+ This property holds the regular expression used for validation.
+
+ Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
+ matching "a".
+
+ By default, this property contains a regular expression with the pattern .* that matches any string.
+*/
+
+/*!
+ \qmlproperty Validator TextInput::validator
+
+ Allows you to set a validator on the TextInput. When a validator is set
+ the TextInput will only accept input which leaves the text property in
+ an acceptable or intermediate state. The accepted signal will only be sent
+ if the text is in an acceptable state when enter is pressed.
+
+ Currently supported validators are IntValidator, DoubleValidator and
+ RegExpValidator. An example of using validators is shown below, which allows
+ input of integers between 11 and 31 into the text input:
+
+ \code
+ import QtQuick 1.0
+ TextInput{
+ validator: IntValidator{bottom: 11; top: 31;}
+ focus: true
+ }
+ \endcode
+
+ \sa acceptableInput, inputMask
+*/
+#ifndef QT_NO_VALIDATOR
+QValidator* QDeclarativeTextInput::validator() const
+{
+ Q_D(const QDeclarativeTextInput);
+ //###const cast isn't good, but needed for property system?
+ return const_cast<QValidator*>(d->control->validator());
+}
+
+void QDeclarativeTextInput::setValidator(QValidator* v)
+{
+ Q_D(QDeclarativeTextInput);
+ 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
+
+/*!
+ \qmlproperty string TextInput::inputMask
+
+ Allows you to set an input mask on the TextInput, restricting the allowable
+ text inputs. See QLineEdit::inputMask for further details, as the exact
+ same mask strings are used by TextInput.
+
+ \sa acceptableInput, validator
+*/
+QString QDeclarativeTextInput::inputMask() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->inputMask();
+}
+
+void QDeclarativeTextInput::setInputMask(const QString &im)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->control->inputMask() == im)
+ return;
+
+ d->control->setInputMask(im);
+ emit inputMaskChanged(d->control->inputMask());
+}
+
+/*!
+ \qmlproperty bool TextInput::acceptableInput
+
+ This property is always true unless a validator or input mask has been set.
+ If a validator or input mask has been set, this property will only be true
+ if the current text is acceptable to the validator or input mask as a final
+ string (not as an intermediate string).
+*/
+bool QDeclarativeTextInput::hasAcceptableInput() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->hasAcceptableInput();
+}
+
+/*!
+ \qmlsignal TextInput::onAccepted()
+
+ This handler is called when the Return or Enter key is pressed.
+ Note that if there is a \l validator or \l inputMask set on the text
+ input, the handler will only be emitted if the input is in an acceptable
+ state.
+*/
+
+void QDeclarativeTextInputPrivate::updateInputMethodHints()
+{
+ Q_Q(QDeclarativeTextInput);
+ Qt::InputMethodHints hints = inputMethodHints;
+ uint echo = control->echoMode();
+ if (echo == QDeclarativeTextInput::Password || echo == QDeclarativeTextInput::NoEcho)
+ hints |= Qt::ImhHiddenText;
+ else if (echo == QDeclarativeTextInput::PasswordEchoOnEdit)
+ hints &= ~Qt::ImhHiddenText;
+ if (echo != QDeclarativeTextInput::Normal)
+ hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ q->setInputMethodHints(hints);
+}
+
+/*!
+ \qmlproperty enumeration TextInput::echoMode
+
+ Specifies how the text should be displayed in the TextInput.
+ \list
+ \o TextInput.Normal - Displays the text as it is. (Default)
+ \o TextInput.Password - Displays asterixes instead of characters.
+ \o TextInput.NoEcho - Displays nothing.
+ \o TextInput.PasswordEchoOnEdit - Displays all but the current character as asterixes.
+ \endlist
+*/
+QDeclarativeTextInput::EchoMode QDeclarativeTextInput::echoMode() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return (QDeclarativeTextInput::EchoMode)d->control->echoMode();
+}
+
+void QDeclarativeTextInput::setEchoMode(QDeclarativeTextInput::EchoMode echo)
+{
+ Q_D(QDeclarativeTextInput);
+ if (echoMode() == echo)
+ return;
+ d->control->setEchoMode((uint)echo);
+ d->updateInputMethodHints();
+ q_textChanged();
+ emit echoModeChanged(echoMode());
+}
+
+Qt::InputMethodHints QDeclarativeTextInput::imHints() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->inputMethodHints;
+}
+
+void QDeclarativeTextInput::setIMHints(Qt::InputMethodHints hints)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->inputMethodHints == hints)
+ return;
+ d->inputMethodHints = hints;
+ d->updateInputMethodHints();
+}
+
+/*!
+ \qmlproperty Component TextInput::cursorDelegate
+ The delegate for the cursor in the TextInput.
+
+ If you set a cursorDelegate for a TextInput, this delegate will be used for
+ drawing the cursor instead of the standard cursor. An instance of the
+ delegate will be created and managed by the TextInput when a cursor is
+ needed, and the x property of delegate instance will be set so as
+ to be one pixel before the top left of the current character.
+
+ Note that the root item of the delegate component must be a QDeclarativeItem or
+ QDeclarativeItem derived item.
+*/
+QDeclarativeComponent* QDeclarativeTextInput::cursorDelegate() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->cursorComponent;
+}
+
+void QDeclarativeTextInput::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QDeclarativeTextInput);
+ 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()));
+ disconnect(d->control, SIGNAL(updateMicroFocus()),
+ this, SLOT(moveCursor()));
+ delete d->cursorItem;
+ }else{
+ d->startCreatingCursor();
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QDeclarativeTextInputPrivate::startCreatingCursor()
+{
+ Q_Q(QDeclarativeTextInput);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(moveCursor()), Qt::UniqueConnection);
+ q->connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(moveCursor()), Qt::UniqueConnection);
+ if(cursorComponent->isReady()){
+ q->createCursor();
+ }else if(cursorComponent->isLoading()){
+ q->connect(cursorComponent, SIGNAL(statusChanged(int)),
+ q, SLOT(createCursor()));
+ }else {//isError
+ qmlInfo(q, cursorComponent->errors()) << QDeclarativeTextInput::tr("Could not load cursor delegate");
+ }
+}
+
+void QDeclarativeTextInput::createCursor()
+{
+ Q_D(QDeclarativeTextInput);
+ 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<QDeclarativeItem*>(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 QDeclarativeTextInput::moveCursor()
+{
+ Q_D(QDeclarativeTextInput);
+ if(!d->cursorItem)
+ return;
+ d->updateHorizontalScroll();
+ d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
+}
+
+/*!
+ \qmlmethod rect TextInput::positionToRectangle(int pos)
+
+ This function takes a character position and returns the rectangle that the
+ cursor would occupy, if it was placed at that character position.
+
+ This is similar to setting the cursorPosition, and then querying the cursor
+ rectangle, but the cursorPosition is not changed.
+*/
+QRectF QDeclarativeTextInput::positionToRectangle(int pos) const
+{
+ Q_D(const QDeclarativeTextInput);
+ 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 QDeclarativeTextInput::positionAt(int x) const
+{
+ return positionAt(x, CursorBetweenCharacters);
+}
+
+/*!
+ \qmlmethod int TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
+ \since Quick 1.1
+
+ This function returns the character position at
+ x pixels from the left of the textInput. Position 0 is before the
+ first character, position 1 is after the first character but before the second,
+ and so on until position text.length, which is after all characters.
+
+ This means that for all x values before the first character this function returns 0,
+ and for all x values after the last character this function returns text.length.
+
+ The cursor position type specifies how the cursor position should be resolved.
+
+ \list
+ \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
+ \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
+ \endlist
+*/
+int QDeclarativeTextInput::positionAt(int x, CursorPosition position) const
+{
+ Q_D(const QDeclarativeTextInput);
+ 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 QDeclarativeTextInputPrivate::focusChanged(bool hasFocus)
+{
+ Q_Q(QDeclarativeTextInput);
+ focused = hasFocus;
+ q->setCursorVisible(hasFocus && scene && scene->hasFocus());
+ if(q->echoMode() == QDeclarativeTextInput::PasswordEchoOnEdit && !hasFocus)
+ control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
+ if (!hasFocus)
+ control->deselect();
+ QDeclarativeItemPrivate::focusChanged(hasFocus);
+}
+
+void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev)
+{
+ Q_D(QDeclarativeTextInput);
+ keyPressPreHandler(ev);
+ if (ev->isAccepted())
+ return;
+
+ // 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())
+ QDeclarativePaintedItem::keyPressEvent(ev);
+}
+
+void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev)
+{
+ Q_D(QDeclarativeTextInput);
+ ev->ignore();
+ const bool wasComposing = d->control->preeditAreaText().length() > 0;
+ inputMethodPreHandler(ev);
+ if (!ev->isAccepted()) {
+ if (d->control->isReadOnly()) {
+ ev->ignore();
+ } else {
+ d->control->processInputMethodEvent(ev);
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ }
+ if (!ev->isAccepted())
+ QDeclarativePaintedItem::inputMethodEvent(ev);
+
+ if (wasComposing != (d->control->preeditAreaText().length() > 0))
+ emit inputMethodComposingChanged();
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextInput);
+ 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 {
+ QDeclarativePaintedItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextInput);
+ 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->selectPressed = true;
+ d->pressPos = event->pos();
+ }
+ bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
+ int cursor = d->xToPos(event->pos().x());
+ d->control->moveCursor(cursor, mark);
+ event->setAccepted(true);
+}
+
+void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
+ return;
+ if (d->selectPressed) {
+ 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 {
+ QDeclarativePaintedItem::mouseMoveEvent(event);
+ }
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
+ return;
+ if (d->selectPressed) {
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+ }
+ if (!d->showInputPanelOnFocus) { // input panel on click
+ if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
+ }
+ }
+ }
+ }
+ d->clickCausedFocus = false;
+ d->control->processEvent(event);
+ if (!event->isAccepted())
+ QDeclarativePaintedItem::mouseReleaseEvent(event);
+}
+
+bool QDeclarativeTextInputPrivate::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;
+}
+
+bool QDeclarativeTextInput::sceneEvent(QEvent *event)
+{
+ Q_D(QDeclarativeTextInput);
+ bool rv = QDeclarativeItem::sceneEvent(event);
+ if (event->type() == QEvent::UngrabMouse) {
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+ }
+ return rv;
+}
+
+bool QDeclarativeTextInput::event(QEvent* ev)
+{
+ Q_D(QDeclarativeTextInput);
+ //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 = QDeclarativePaintedItem::event(ev);
+ return handled;
+}
+
+void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QDeclarativeTextInput);
+ if (newGeometry.width() != oldGeometry.width()) {
+ updateSize();
+ d->updateHorizontalScroll();
+ }
+ QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+int QDeclarativeTextInputPrivate::calculateTextWidth()
+{
+ return qRound(control->naturalTextWidth());
+}
+
+void QDeclarativeTextInputPrivate::updateHorizontalScroll()
+{
+ Q_Q(QDeclarativeTextInput);
+ const int preeditLength = control->preeditAreaText().length();
+ int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
+ QRect br(q->boundingRect().toRect());
+ int widthUsed = calculateTextWidth();
+
+ QDeclarativeTextInput::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 QDeclarativeTextInput::AlignRight:
+ hscroll = q->width() - widthUsed;
+ break;
+ case QDeclarativeTextInput::AlignHCenter:
+ hscroll = (q->width() - widthUsed) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ }
+}
+
+void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r)
+{
+ Q_D(QDeclarativeTextInput);
+ 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();
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QDeclarativeTextInput);
+ 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();
+ }
+}
+
+/*!
+ \qmlmethod void TextInput::deselect()
+ \since Quick 1.1
+
+ Removes active text selection.
+*/
+void QDeclarativeTextInput::deselect()
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->deselect();
+}
+
+/*!
+ \qmlmethod void TextInput::selectAll()
+
+ Causes all text to be selected.
+*/
+void QDeclarativeTextInput::selectAll()
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->setSelection(0, d->control->text().length());
+}
+
+/*!
+ \qmlmethod void TextInput::isRightToLeft(int start, int end)
+
+ Returns true if the natural reading direction of the editor text
+ found between positions \a start and \a end is right to left.
+*/
+bool QDeclarativeTextInput::isRightToLeft(int start, int end)
+{
+ Q_D(QDeclarativeTextInput);
+ 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
+/*!
+ \qmlmethod TextInput::cut()
+
+ Moves the currently selected text to the system clipboard.
+*/
+void QDeclarativeTextInput::cut()
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->copy();
+ d->control->del();
+}
+
+/*!
+ \qmlmethod TextInput::copy()
+
+ Copies the currently selected text to the system clipboard.
+*/
+void QDeclarativeTextInput::copy()
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->copy();
+}
+
+/*!
+ \qmlmethod TextInput::paste()
+
+ Replaces the currently selected text by the contents of the system clipboard.
+*/
+void QDeclarativeTextInput::paste()
+{
+ Q_D(QDeclarativeTextInput);
+ if(!d->control->isReadOnly())
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+/*!
+ \qmlmethod void TextInput::selectWord()
+
+ Causes the word closest to the current cursor position to be selected.
+*/
+void QDeclarativeTextInput::selectWord()
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->selectWordAtPos(d->control->cursor());
+}
+
+/*!
+ \qmlproperty bool TextInput::smooth
+
+ This property holds whether the text is smoothly scaled or transformed.
+
+ Smooth filtering gives better visual quality, but is slower. If
+ the item is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the item is stationary on
+ the screen. A common pattern when animating an item is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+ \qmlproperty string TextInput::passwordCharacter
+
+ This is the character displayed when echoMode is set to Password or
+ PasswordEchoOnEdit. By default it is an asterisk.
+
+ If this property is set to a string with more than one character,
+ the first character is used. If the string is empty, the value
+ is ignored and the property is not set.
+*/
+QString QDeclarativeTextInput::passwordCharacter() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return QString(d->control->passwordCharacter());
+}
+
+void QDeclarativeTextInput::setPasswordCharacter(const QString &str)
+{
+ Q_D(QDeclarativeTextInput);
+ if(str.length() < 1)
+ return;
+ d->control->setPasswordCharacter(str.constData()[0]);
+ EchoMode echoMode_ = echoMode();
+ if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
+ updateSize();
+ }
+ emit passwordCharacterChanged();
+}
+
+/*!
+ \qmlproperty string TextInput::displayText
+
+ This is the text displayed in the TextInput.
+
+ If \l echoMode is set to TextInput::Normal, this holds the
+ same value as the TextInput::text property. Otherwise,
+ this property holds the text visible to the user, while
+ the \l text property holds the actual entered text.
+*/
+QString QDeclarativeTextInput::displayText() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->displayText();
+}
+
+/*!
+ \qmlproperty bool TextInput::selectByMouse
+
+ Defaults to false.
+
+ If true, the user can use the mouse to select text in some
+ platform-specific way. Note that for some platforms this may
+ not be an appropriate interaction (eg. may conflict with how
+ the text needs to behave inside a Flickable.
+*/
+bool QDeclarativeTextInput::selectByMouse() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->selectByMouse;
+}
+
+void QDeclarativeTextInput::setSelectByMouse(bool on)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ emit selectByMouseChanged(on);
+ }
+}
+
+/*!
+ \qmlproperty enum TextInput::mouseSelectionMode
+ \since Quick 1.1
+
+ Specifies how text should be selected using a mouse.
+
+ \list
+ \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
+ \o TextInput.SelectWords - The selection is updated with whole words.
+ \endlist
+
+ This property only applies when \l selectByMouse is true.
+*/
+
+QDeclarativeTextInput::SelectionMode QDeclarativeTextInput::mouseSelectionMode() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->mouseSelectionMode;
+}
+
+void QDeclarativeTextInput::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QDeclarativeTextInput);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+/*!
+ \qmlproperty bool TextInput::canPaste
+ \since QtQuick 1.1
+
+ Returns true if the TextInput is writable and the content of the clipboard is
+ suitable for pasting into the TextEdit.
+*/
+bool QDeclarativeTextInput::canPaste() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->canPaste;
+}
+
+void QDeclarativeTextInput::moveCursorSelection(int position)
+{
+ Q_D(QDeclarativeTextInput);
+ d->control->moveCursor(position, true);
+ d->updateHorizontalScroll();
+}
+
+/*!
+ \qmlmethod void TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
+ \since Quick 1.1
+
+ Moves the cursor to \a position and updates the selection according to the optional \a mode
+ parameter. (To only move the cursor, set the \l cursorPosition property.)
+
+ When this method is called it additionally sets either the
+ selectionStart or the selectionEnd (whichever was at the previous cursor position)
+ to the specified position. This allows you to easily extend and contract the selected
+ text range.
+
+ The selection mode specifies whether the selection is updated on a per character or a per word
+ basis. If not specified the selection mode will default to TextInput.SelectCharacters.
+
+ \list
+ \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
+ the previous cursor position) to the specified position.
+ \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
+ words between the specified postion and the previous cursor position. Words partially in the
+ range are included.
+ \endlist
+
+ For example, take this sequence of calls:
+
+ \code
+ cursorPosition = 5
+ moveCursorSelection(9, TextInput.SelectCharacters)
+ moveCursorSelection(7, TextInput.SelectCharacters)
+ \endcode
+
+ This moves the cursor to position 5, extend the selection end from 5 to 9
+ and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
+ selected (the 6th and 7th characters).
+
+ The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
+ before or on position 5 and extend the selection end to a word boundary on or past position 9.
+*/
+void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QDeclarativeTextInput);
+
+ 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);
+ }
+ }
+}
+
+/*!
+ \qmlmethod void TextInput::openSoftwareInputPanel()
+
+ Opens software input panels like virtual keyboards for typing, useful for
+ customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. On Symbian^1 and
+ Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
+ the panels are automatically opened when TextInput element gains active focus. Input panels are
+ always closed if no editor has active focus.
+
+ . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \qml
+ import QtQuick 1.0
+ TextInput {
+ id: textInput
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textInput.activeFocus) {
+ textInput.forceActiveFocus()
+ textInput.openSoftwareInputPanel();
+ } else {
+ textInput.focus = false;
+ }
+ }
+ onPressAndHold: textInput.closeSoftwareInputPanel();
+ }
+ }
+ \endqml
+*/
+void QDeclarativeTextInput::openSoftwareInputPanel()
+{
+ QEvent event(QEvent::RequestSoftwareInputPanel);
+ if (qApp) {
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ QApplication::sendEvent(view, &event);
+ }
+ }
+ }
+}
+
+/*!
+ \qmlmethod void TextInput::closeSoftwareInputPanel()
+
+ Closes a software input panel like a virtual keyboard shown on the screen, useful
+ for customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. On Symbian^1 and
+ Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
+ the panels are automatically opened when TextInput element gains active focus. Input panels are
+ always closed if no editor has active focus.
+
+ . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \qml
+ import QtQuick 1.0
+ TextInput {
+ id: textInput
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textInput.activeFocus) {
+ textInput.forceActiveFocus();
+ textInput.openSoftwareInputPanel();
+ } else {
+ textInput.focus = false;
+ }
+ }
+ onPressAndHold: textInput.closeSoftwareInputPanel();
+ }
+ }
+ \endqml
+*/
+void QDeclarativeTextInput::closeSoftwareInputPanel()
+{
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ if (qApp) {
+ QEvent event(QEvent::CloseSoftwareInputPanel);
+ if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
+ if (view->scene() && view->scene() == scene()) {
+ QApplication::sendEvent(view, &event);
+ }
+ }
+ }
+}
+
+void QDeclarativeTextInput::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QDeclarativeTextInput);
+ if (d->showInputPanelOnFocus) {
+ if (d->focusOnPress && !isReadOnly()) {
+ openSoftwareInputPanel();
+ }
+ }
+ QDeclarativePaintedItem::focusInEvent(event);
+}
+
+/*!
+ \qmlproperty bool TextInput::inputMethodComposing
+
+ \since QtQuick 1.1
+
+ This property holds whether the TextInput has partial text input from an
+ input method.
+
+ While it is composing an input method may rely on mouse or key events from
+ the TextInput to edit or commit the partial text. This property can be
+ used to determine when to disable events handlers that may interfere with
+ the correct operation of an input method.
+*/
+bool QDeclarativeTextInput::isInputMethodComposing() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->preeditAreaText().length() > 0;
+}
+
+void QDeclarativeTextInputPrivate::init()
+{
+ Q_Q(QDeclarativeTextInput);
+ control->setCursorWidth(1);
+ control->setPasswordCharacter(QLatin1Char('*'));
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QGraphicsItem::ItemHasNoContents, false);
+ q->setFlag(QGraphicsItem::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 QDeclarativeTextInput::cursorPosChanged()
+{
+ Q_D(QDeclarativeTextInput);
+ d->updateHorizontalScroll();
+ updateRect();//TODO: Only update rect between pos's
+ updateMicroFocus();
+ emit cursorPositionChanged();
+ d->control->resetCursorBlinkTimer();
+
+ 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 QDeclarativeTextInput::selectionChanged()
+{
+ Q_D(QDeclarativeTextInput);
+ 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 QDeclarativeTextInput::q_textChanged()
+{
+ Q_D(QDeclarativeTextInput);
+ updateSize();
+ d->determineHorizontalAlignment();
+ d->updateHorizontalScroll();
+ updateMicroFocus();
+ emit textChanged();
+ emit displayTextChanged();
+ if(hasAcceptableInput() != d->oldValidity){
+ d->oldValidity = hasAcceptableInput();
+ emit acceptableInputChanged();
+ }
+}
+
+void QDeclarativeTextInput::updateRect(const QRect &r)
+{
+ Q_D(QDeclarativeTextInput);
+ if(r == QRect())
+ clearCache();
+ else
+ dirtyCache(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height()));
+ update();
+}
+
+QRectF QDeclarativeTextInput::boundingRect() const
+{
+ Q_D(const QDeclarativeTextInput);
+ QRectF r = QDeclarativePaintedItem::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 QDeclarativeTextInput::updateSize(bool needsRedraw)
+{
+ Q_D(QDeclarativeTextInput);
+ 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()));//Repaints if changed
+ if(w==width() && h==height() && needsRedraw){
+ clearCache();
+ update();
+ }
+}
+
+void QDeclarativeTextInput::q_canPasteChanged()
+{
+ Q_D(QDeclarativeTextInput);
+ 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
+
+#endif // QT_NO_LINEEDIT
+
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h
new file mode 100644
index 0000000000..ec70e43f68
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVETEXTINPUT_H
+#define QDECLARATIVETEXTINPUT_H
+
+#include "private/qdeclarativetext_p.h"
+#include "private/qdeclarativeimplicitsizeitem_p.h"
+
+#include <QGraphicsSceneMouseEvent>
+#include <QIntValidator>
+
+#ifndef QT_NO_LINEEDIT
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeTextInputPrivate;
+class QValidator;
+class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizePaintedItem
+{
+ 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 REVISION 1)
+ 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 imHints WRITE setIMHints)
+
+ 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 REVISION 1)
+ Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1)
+
+public:
+ QDeclarativeTextInput(QDeclarativeItem* parent=0);
+ ~QDeclarativeTextInput();
+
+ 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 Q_REVISION(1) int positionAt(int x, CursorPosition position) const;
+ Q_INVOKABLE QRectF positionToRectangle(int pos) const;
+ Q_INVOKABLE void moveCursorSelection(int pos);
+ Q_INVOKABLE Q_REVISION(1) 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 drawContents(QPainter *p,const QRect &r);
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+ QRectF boundingRect() const;
+ bool canPaste() const;
+
+ bool isInputMethodComposing() const;
+
+ Qt::InputMethodHints imHints() const;
+ void setIMHints(Qt::InputMethodHints hints);
+
+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);
+ Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode);
+ Q_REVISION(1) void canPasteChanged();
+ Q_REVISION(1) void inputMethodComposingChanged();
+ Q_REVISION(1) 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 *);
+ bool event(QEvent *e);
+ void focusInEvent(QFocusEvent *event);
+
+public Q_SLOTS:
+ void selectAll();
+ void selectWord();
+ void select(int start, int end);
+ Q_REVISION(1) void deselect();
+ Q_REVISION(1) 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_D(QGraphicsItem::d_ptr.data(), QDeclarativeTextInput)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTextInput)
+#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 // QT_NO_LINEEDIT
+
+#endif // QDECLARATIVETEXTINPUT_H
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
new file mode 100644
index 0000000000..f6f6bd8ca4
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVETEXTINPUT_P_H
+#define QDECLARATIVETEXTINPUT_P_H
+
+#include "private/qdeclarativetextinput_p.h"
+
+#include "private/qdeclarativeimplicitsizeitem_p_p.h"
+
+#include <qdeclarative.h>
+
+#include <QPointer>
+
+#include <private/qlinecontrol_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.
+
+#ifndef QT_NO_LINEEDIT
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QDeclarativeTextInputPrivate : public QDeclarativeImplicitSizePaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTextInput)
+public:
+ QDeclarativeTextInputPrivate() : control(new QLineControl(QString())),
+ color((QRgb)0), style(QDeclarativeText::Normal),
+ styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft),
+ mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), inputMethodHints(Qt::ImhNone),
+ hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true),
+ showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false),
+ autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true),
+ selectPressed(false)
+ {
+#ifdef Q_OS_SYMBIAN
+ if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
+ showInputPanelOnFocus = false;
+ }
+#endif
+
+ }
+
+ ~QDeclarativeTextInputPrivate()
+ {
+ delete control;
+ }
+
+ int xToPos(int x, QTextLine::CursorPosition betweenOrOn = QTextLine::CursorBetweenCharacters) const
+ {
+ Q_Q(const QDeclarativeTextInput);
+ QRect cr = q->boundingRect().toRect();
+ x-= cr.x() - hscroll;
+ return control->xToPos(x, betweenOrOn);
+ }
+
+ void init();
+ void startCreatingCursor();
+ void focusChanged(bool hasFocus);
+ void updateHorizontalScroll();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QDeclarativeTextInput::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ int calculateTextWidth();
+ bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType);
+ void updateInputMethodHints();
+
+ QLineControl* control;
+
+ QFont font;
+ QFont sourceFont;
+ QColor color;
+ QColor selectionColor;
+ QColor selectedTextColor;
+ QDeclarativeText::TextStyle style;
+ QColor styleColor;
+ QDeclarativeTextInput::HAlignment hAlign;
+ QDeclarativeTextInput::SelectionMode mouseSelectionMode;
+ Qt::InputMethodHints inputMethodHints;
+ QPointer<QDeclarativeComponent> cursorComponent;
+ QPointer<QDeclarativeItem> 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;
+ bool selectPressed:1;
+
+ static inline QDeclarativeTextInputPrivate *get(QDeclarativeTextInput *t) {
+ return t->d_func();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LINEEDIT
+
+#endif
+
diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp
new file mode 100644
index 0000000000..1e6db3f1e7
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativetextlayout_p.h"
+#include <private/qstatictext_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qtextengine_p.h>
+#include <private/qpainter_p.h>
+#include <private/qpaintengineex_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeTextLayoutPrivate
+{
+public:
+ QDeclarativeTextLayoutPrivate()
+ : cached(false) {}
+
+ QPointF position;
+
+ bool cached;
+ QVector<QStaticTextItem> items;
+ QVector<QFixedPoint> positions;
+ QVector<glyph_t> glyphs;
+ QVector<QChar> chars;
+};
+
+namespace {
+class DrawTextItemRecorder: public QPaintEngine
+{
+ public:
+ DrawTextItemRecorder(bool untransformedCoordinates, bool useBackendOptimizations)
+ : m_inertText(0), m_dirtyPen(false), m_useBackendOptimizations(useBackendOptimizations),
+ m_untransformedCoordinates(untransformedCoordinates)
+ {
+ }
+
+ virtual void updateState(const QPaintEngineState &newState)
+ {
+ if (newState.state() & QPaintEngine::DirtyPen)
+ m_dirtyPen = true;
+ }
+
+ virtual void drawTextItem(const QPointF &position, const QTextItem &textItem)
+ {
+ int glyphOffset = m_inertText->glyphs.size(); // Store offset into glyph pool
+ int positionOffset = m_inertText->glyphs.size(); // Offset into position pool
+ int charOffset = m_inertText->chars.size();
+
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+
+ bool needFreshCurrentItem = true;
+ if (!m_inertText->items.isEmpty()) {
+ QStaticTextItem &last = m_inertText->items[m_inertText->items.count() - 1];
+
+ if (last.fontEngine() == ti.fontEngine && last.font == ti.font() &&
+ (!m_dirtyPen || last.color == state->pen().color())) {
+ needFreshCurrentItem = false;
+
+ last.numChars += ti.num_chars;
+
+ }
+ }
+
+ if (needFreshCurrentItem) {
+ QStaticTextItem currentItem;
+
+ currentItem.setFontEngine(ti.fontEngine);
+ currentItem.font = ti.font();
+ currentItem.charOffset = charOffset;
+ currentItem.numChars = ti.num_chars;
+ currentItem.numGlyphs = 0;
+ currentItem.glyphOffset = glyphOffset;
+ currentItem.positionOffset = positionOffset;
+ currentItem.useBackendOptimizations = m_useBackendOptimizations;
+ if (m_dirtyPen)
+ currentItem.color = state->pen().color();
+
+ m_inertText->items.append(currentItem);
+ }
+
+ QStaticTextItem &currentItem = m_inertText->items.last();
+
+ QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform();
+ matrix.translate(position.x(), position.y());
+
+ QVarLengthArray<glyph_t> glyphs;
+ QVarLengthArray<QFixedPoint> positions;
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ int size = glyphs.size();
+ Q_ASSERT(size == positions.size());
+ currentItem.numGlyphs += size;
+
+ m_inertText->glyphs.resize(m_inertText->glyphs.size() + size);
+ m_inertText->positions.resize(m_inertText->glyphs.size());
+ m_inertText->chars.resize(m_inertText->chars.size() + ti.num_chars);
+
+ glyph_t *glyphsDestination = m_inertText->glyphs.data() + glyphOffset;
+ qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * size);
+
+ QFixedPoint *positionsDestination = m_inertText->positions.data() + positionOffset;
+ qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * size);
+
+ QChar *charsDestination = m_inertText->chars.data() + charOffset;
+ qMemCopy(charsDestination, ti.chars, sizeof(QChar) * ti.num_chars);
+
+ }
+
+ virtual void drawPolygon(const QPointF *, int , PolygonDrawMode )
+ {
+ /* intentionally empty */
+ }
+
+ virtual bool begin(QPaintDevice *) { return true; }
+ virtual bool end() { return true; }
+ virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
+ virtual Type type() const
+ {
+ return User;
+ }
+
+ void begin(QDeclarativeTextLayoutPrivate *t) {
+ m_inertText = t;
+ m_dirtyPen = false;
+ }
+
+ private:
+ QDeclarativeTextLayoutPrivate *m_inertText;
+
+ bool m_dirtyPen;
+ bool m_useBackendOptimizations;
+ bool m_untransformedCoordinates;
+};
+
+class DrawTextItemDevice: public QPaintDevice
+{
+ public:
+ DrawTextItemDevice(bool untransformedCoordinates, bool useBackendOptimizations)
+ {
+ m_paintEngine = new DrawTextItemRecorder(untransformedCoordinates,
+ useBackendOptimizations);
+ }
+
+ ~DrawTextItemDevice()
+ {
+ delete m_paintEngine;
+ }
+
+ void begin(QDeclarativeTextLayoutPrivate *t) {
+ m_paintEngine->begin(t);
+ }
+
+ int metric(PaintDeviceMetric m) const
+ {
+ int val;
+ switch (m) {
+ case PdmWidth:
+ case PdmHeight:
+ case PdmWidthMM:
+ case PdmHeightMM:
+ val = 0;
+ break;
+ case PdmDpiX:
+ case PdmPhysicalDpiX:
+ val = qt_defaultDpiX();
+ break;
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ val = qt_defaultDpiY();
+ break;
+ case PdmNumColors:
+ val = 16777216;
+ break;
+ case PdmDepth:
+ val = 24;
+ break;
+ default:
+ val = 0;
+ qWarning("DrawTextItemDevice::metric: Invalid metric command");
+ }
+ return val;
+ }
+
+ virtual QPaintEngine *paintEngine() const
+ {
+ return m_paintEngine;
+ }
+
+ private:
+ DrawTextItemRecorder *m_paintEngine;
+};
+
+struct InertTextPainter {
+ InertTextPainter()
+ : device(true, true), painter(&device) {}
+
+ DrawTextItemDevice device;
+ QPainter painter;
+};
+}
+
+Q_GLOBAL_STATIC(InertTextPainter, inertTextPainter);
+
+/*!
+\class QDeclarativeTextLayout
+\brief The QDeclarativeTextLayout class is a version of QStaticText that works with QTextLayouts.
+\internal
+
+This class is basically a copy of the QStaticText code, but it is adapted to source its text from
+QTextLayout.
+
+It is also considerably faster to create a QDeclarativeTextLayout than a QStaticText because it uses
+a single, shared QPainter instance. QStaticText by comparison creates a new QPainter per instance.
+As a consequence this means that QDeclarativeTextLayout is not re-enterant. Adding a lock around
+the shared painter solves this, and only introduces a minor performance penalty, but is unnecessary
+for QDeclarativeTextLayout's current use (QDeclarativeText is already tied to the GUI thread).
+*/
+
+QDeclarativeTextLayout::QDeclarativeTextLayout()
+: d(0)
+{
+}
+
+QDeclarativeTextLayout::QDeclarativeTextLayout(const QString &text)
+: QTextLayout(text), d(0)
+{
+}
+
+QDeclarativeTextLayout::~QDeclarativeTextLayout()
+{
+ if (d) delete d;
+}
+
+void QDeclarativeTextLayout::beginLayout()
+{
+ if (d && d->cached) {
+ d->cached = false;
+ d->items.clear();
+ d->positions.clear();
+ d->glyphs.clear();
+ d->chars.clear();
+ d->position = QPointF();
+ }
+ QTextLayout::beginLayout();
+}
+
+void QDeclarativeTextLayout::clearLayout()
+{
+ if (d && d->cached) {
+ d->cached = false;
+ d->items.clear();
+ d->positions.clear();
+ d->glyphs.clear();
+ d->chars.clear();
+ d->position = QPointF();
+ }
+ QTextLayout::clearLayout();
+}
+
+void QDeclarativeTextLayout::prepare(QPainter *painter)
+{
+ if (!d || !d->cached) {
+
+ if (!d)
+ d = new QDeclarativeTextLayoutPrivate;
+
+ InertTextPainter *itp = inertTextPainter();
+ itp->device.begin(d);
+ itp->painter.setPen(painter->pen());
+ QTextLayout::draw(&itp->painter, QPointF(0, 0));
+
+ glyph_t *glyphPool = d->glyphs.data();
+ QFixedPoint *positionPool = d->positions.data();
+ QChar *charPool = d->chars.data();
+
+ int itemCount = d->items.count();
+ for (int ii = 0; ii < itemCount; ++ii) {
+ QStaticTextItem &item = d->items[ii];
+ item.glyphs = glyphPool + item.glyphOffset;
+ item.glyphPositions = positionPool + item.positionOffset;
+ item.chars = charPool + item.charOffset;
+ }
+
+ d->cached = true;
+ }
+}
+
+// Defined in qpainter.cpp
+extern Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
+ const QFixedPoint *positions, int glyphCount,
+ QFontEngine *fontEngine, const QFont &font,
+ const QTextCharFormat &charFormat);
+
+void QDeclarativeTextLayout::draw(QPainter *painter, const QPointF &p)
+{
+ QPainterPrivate *priv = QPainterPrivate::get(painter);
+
+ bool paintEngineSupportsTransformations = priv->extended &&
+ (priv->extended->type() == QPaintEngine::OpenGL2 ||
+ priv->extended->type() == QPaintEngine::OpenVG ||
+ priv->extended->type() == QPaintEngine::OpenGL);
+
+ if (!paintEngineSupportsTransformations || !priv->state->matrix.isAffine()) {
+ QTextLayout::draw(painter, p);
+ return;
+ }
+
+ prepare(painter);
+
+ int itemCount = d->items.count();
+
+ if (p != d->position) {
+ QFixed fx = QFixed::fromReal(p.x());
+ QFixed fy = QFixed::fromReal(p.y());
+ QFixed oldX = QFixed::fromReal(d->position.x());
+ QFixed oldY = QFixed::fromReal(d->position.y());
+ for (int item = 0; item < itemCount; ++item) {
+ QStaticTextItem &textItem = d->items[item];
+
+ for (int ii = 0; ii < textItem.numGlyphs; ++ii) {
+ textItem.glyphPositions[ii].x += fx - oldX;
+ textItem.glyphPositions[ii].y += fy - oldY;
+ }
+ textItem.userDataNeedsUpdate = true;
+ }
+
+ d->position = p;
+ }
+
+ QPen oldPen = priv->state->pen;
+ QColor currentColor = oldPen.color();
+ for (int ii = 0; ii < itemCount; ++ii) {
+ QStaticTextItem &item = d->items[ii];
+ if (item.color.isValid() && currentColor != item.color) {
+ painter->setPen(item.color);
+ currentColor = item.color;
+ }
+ priv->extended->drawStaticTextItem(&item);
+
+ qt_draw_decoration_for_glyphs(painter, item.glyphs, item.glyphPositions,
+ item.numGlyphs, item.fontEngine(), painter->font(),
+ QTextCharFormat());
+ }
+ if (currentColor != oldPen.color())
+ painter->setPen(oldPen);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout_p.h b/src/declarative/graphicsitems/qdeclarativetextlayout_p.h
new file mode 100644
index 0000000000..23b22a665a
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetextlayout_p.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 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 QDECLARATIVETEXTLAYOUT_P_H
+#define QDECLARATIVETEXTLAYOUT_P_H
+
+#include <QtGui/qtextlayout.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeTextLayoutPrivate;
+class QDeclarativeTextLayout : public QTextLayout
+{
+public:
+ QDeclarativeTextLayout();
+ QDeclarativeTextLayout(const QString &);
+ ~QDeclarativeTextLayout();
+
+ void beginLayout();
+ void clearLayout();
+
+ void prepare(QPainter *);
+ void draw(QPainter *, const QPointF & = QPointF());
+
+private:
+ QDeclarativeTextLayoutPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVETEXTLAYOUT_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativetranslate.cpp b/src/declarative/graphicsitems/qdeclarativetranslate.cpp
new file mode 100644
index 0000000000..08fcbe5284
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetranslate.cpp
@@ -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 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/qdeclarativetranslate_p.h"
+#include <private/qgraphicstransform_p.h>
+#include <QDebug>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeTranslatePrivate : public QGraphicsTransformPrivate
+{
+public:
+ QDeclarativeTranslatePrivate()
+ : x(0), y(0) {}
+ qreal x;
+ qreal y;
+};
+
+/*!
+ Constructs an empty QDeclarativeTranslate object with the given \a parent.
+*/
+QDeclarativeTranslate::QDeclarativeTranslate(QObject *parent)
+ : QGraphicsTransform(*new QDeclarativeTranslatePrivate, parent)
+{
+}
+
+/*!
+ Destroys the graphics scale.
+*/
+QDeclarativeTranslate::~QDeclarativeTranslate()
+{
+}
+
+/*!
+ \property QDeclarativeTranslate::x
+ \brief the horizontal translation.
+
+ The translation can be any real number; the default value is 0.0.
+
+ \sa y
+*/
+qreal QDeclarativeTranslate::x() const
+{
+ Q_D(const QDeclarativeTranslate);
+ return d->x;
+}
+void QDeclarativeTranslate::setX(qreal x)
+{
+ Q_D(QDeclarativeTranslate);
+ if (d->x == x)
+ return;
+ d->x = x;
+ update();
+ emit xChanged();
+}
+
+/*!
+ \property QDeclarativeTranslate::y
+ \brief the vertical translation.
+
+ The translation can be any real number; the default value is 0.0.
+
+ \sa x
+*/
+qreal QDeclarativeTranslate::y() const
+{
+ Q_D(const QDeclarativeTranslate);
+ return d->y;
+}
+void QDeclarativeTranslate::setY(qreal y)
+{
+ Q_D(QDeclarativeTranslate);
+ if (d->y == y)
+ return;
+ d->y = y;
+ update();
+ emit yChanged();
+}
+
+void QDeclarativeTranslate::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QDeclarativeTranslate);
+ matrix->translate(d->x, d->y, 0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativetranslate_p.h b/src/declarative/graphicsitems/qdeclarativetranslate_p.h
new file mode 100644
index 0000000000..9aaea8c605
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativetranslate_p.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 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 QDECLARATIVETRANSLATE_H
+#define QDECLARATIVETRANSLATE_H
+
+#include "qdeclarativeitem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeTranslatePrivate;
+
+class Q_AUTOTEST_EXPORT QDeclarativeTranslate : public QGraphicsTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+
+public:
+ QDeclarativeTranslate(QObject *parent = 0);
+ ~QDeclarativeTranslate();
+
+ 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(QDeclarativeTranslate)
+ Q_DISABLE_COPY(QDeclarativeTranslate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTranslate)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp
new file mode 100644
index 0000000000..97ce0592a4
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp
@@ -0,0 +1,1420 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativevisualitemmodel_p.h"
+
+#include "qdeclarativeitem.h"
+
+#include <qdeclarativecontext.h>
+#include <qdeclarativecontext_p.h>
+#include <qdeclarativeengine.h>
+#include <qdeclarativeexpression.h>
+#include <qdeclarativepackage_p.h>
+#include <qdeclarativeopenmetaobject_p.h>
+#include <qdeclarativelistaccessor_p.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativedata_p.h>
+#include <qdeclarativepropertycache_p.h>
+#include <qdeclarativeguard_p.h>
+#include <qdeclarativeglobal_p.h>
+
+#include <qgraphicsscene.h>
+#include <qlistmodelinterface_p.h>
+#include <qhash.h>
+#include <qlist.h>
+#include <qmetaobjectbuilder_p.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QHash<QObject*, QDeclarativeVisualItemModelAttached*> QDeclarativeVisualItemModelAttached::attachedProperties;
+
+
+class QDeclarativeVisualItemModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeVisualItemModel)
+public:
+ QDeclarativeVisualItemModelPrivate() : QObjectPrivate() {}
+
+ static void children_append(QDeclarativeListProperty<QDeclarativeItem> *prop, QDeclarativeItem *item) {
+ QDeclarative_setParent_noEvent(item, prop->object);
+ static_cast<QDeclarativeVisualItemModelPrivate *>(prop->data)->children.append(Item(item));
+ static_cast<QDeclarativeVisualItemModelPrivate *>(prop->data)->itemAppended();
+ static_cast<QDeclarativeVisualItemModelPrivate *>(prop->data)->emitChildrenChanged();
+ }
+
+ static int children_count(QDeclarativeListProperty<QDeclarativeItem> *prop) {
+ return static_cast<QDeclarativeVisualItemModelPrivate *>(prop->data)->children.count();
+ }
+
+ static QDeclarativeItem *children_at(QDeclarativeListProperty<QDeclarativeItem> *prop, int index) {
+ return static_cast<QDeclarativeVisualItemModelPrivate *>(prop->data)->children.at(index).item;
+ }
+
+ void itemAppended() {
+ Q_Q(QDeclarativeVisualItemModel);
+ QDeclarativeVisualItemModelAttached *attached = QDeclarativeVisualItemModelAttached::properties(children.last().item);
+ attached->setIndex(children.count()-1);
+ emit q->itemsInserted(children.count()-1, 1);
+ emit q->countChanged();
+ }
+
+ void emitChildrenChanged() {
+ Q_Q(QDeclarativeVisualItemModel);
+ emit q->childrenChanged();
+ }
+
+ int indexOf(QDeclarativeItem *item) const {
+ for (int i = 0; i < children.count(); ++i)
+ if (children.at(i).item == item)
+ return i;
+ return -1;
+ }
+
+ class Item {
+ public:
+ Item(QDeclarativeItem *i) : item(i), ref(0) {}
+
+ void addRef() { ++ref; }
+ bool deref() { return --ref == 0; }
+
+ QDeclarativeItem *item;
+ int ref;
+ };
+
+ QList<Item> children;
+};
+
+
+/*!
+ \qmlclass VisualItemModel QDeclarativeVisualItemModel
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The VisualItemModel allows items to be provided to a view.
+
+ A VisualItemModel contains the visual items to be used in a view.
+ When a VisualItemModel is used in a view, the view does not require
+ a delegate since the VisualItemModel already contains the visual
+ delegate (items).
+
+ An item can determine its index within the
+ model via the \l{VisualItemModel::index}{index} attached property.
+
+ The example below places three colored rectangles in a ListView.
+ \code
+ import QtQuick 1.0
+
+ Rectangle {
+ VisualItemModel {
+ id: itemModel
+ Rectangle { height: 30; width: 80; color: "red" }
+ Rectangle { height: 30; width: 80; color: "green" }
+ Rectangle { height: 30; width: 80; color: "blue" }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: itemModel
+ }
+ }
+ \endcode
+
+ \image visualitemmodel.png
+
+ \sa {declarative/modelviews/visualitemmodel}{VisualItemModel example}
+*/
+QDeclarativeVisualItemModel::QDeclarativeVisualItemModel(QObject *parent)
+ : QDeclarativeVisualModel(*(new QDeclarativeVisualItemModelPrivate), parent)
+{
+}
+
+/*!
+ \qmlattachedproperty int VisualItemModel::index
+ This attached property holds the index of this delegate's item within the model.
+
+ It is attached to each instance of the delegate.
+*/
+
+QDeclarativeListProperty<QDeclarativeItem> QDeclarativeVisualItemModel::children()
+{
+ Q_D(QDeclarativeVisualItemModel);
+ return QDeclarativeListProperty<QDeclarativeItem>(this, d, d->children_append,
+ d->children_count, d->children_at);
+}
+
+/*!
+ \qmlproperty int VisualItemModel::count
+
+ The number of items in the model. This property is readonly.
+*/
+int QDeclarativeVisualItemModel::count() const
+{
+ Q_D(const QDeclarativeVisualItemModel);
+ return d->children.count();
+}
+
+bool QDeclarativeVisualItemModel::isValid() const
+{
+ return true;
+}
+
+QDeclarativeItem *QDeclarativeVisualItemModel::item(int index, bool)
+{
+ Q_D(QDeclarativeVisualItemModel);
+ QDeclarativeVisualItemModelPrivate::Item &item = d->children[index];
+ item.addRef();
+ return item.item;
+}
+
+QDeclarativeVisualModel::ReleaseFlags QDeclarativeVisualItemModel::release(QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeVisualItemModel);
+ int idx = d->indexOf(item);
+ if (idx >= 0) {
+ if (d->children[idx].deref()) {
+ if (item->scene())
+ item->scene()->removeItem(item);
+ QDeclarative_setParent_noEvent(item, this);
+ }
+ }
+ return 0;
+}
+
+bool QDeclarativeVisualItemModel::completePending() const
+{
+ return false;
+}
+
+void QDeclarativeVisualItemModel::completeItem()
+{
+ // Nothing to do
+}
+
+QString QDeclarativeVisualItemModel::stringValue(int index, const QString &name)
+{
+ Q_D(QDeclarativeVisualItemModel);
+ if (index < 0 || index >= d->children.count())
+ return QString();
+ return QDeclarativeEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString();
+}
+
+int QDeclarativeVisualItemModel::indexOf(QDeclarativeItem *item, QObject *) const
+{
+ Q_D(const QDeclarativeVisualItemModel);
+ return d->indexOf(item);
+}
+
+QDeclarativeVisualItemModelAttached *QDeclarativeVisualItemModel::qmlAttachedProperties(QObject *obj)
+{
+ return QDeclarativeVisualItemModelAttached::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 QDeclarativeVisualDataModelParts;
+class QDeclarativeVisualDataModelData;
+class QDeclarativeVisualDataModelPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeVisualDataModelPrivate(QDeclarativeContext *);
+
+ static QDeclarativeVisualDataModelPrivate *get(QDeclarativeVisualDataModel *m) {
+ return static_cast<QDeclarativeVisualDataModelPrivate *>(QObjectPrivate::get(m));
+ }
+
+ QDeclarativeGuard<QListModelInterface> m_listModelInterface;
+ QDeclarativeGuard<QAbstractItemModel> m_abstractItemModel;
+ QDeclarativeGuard<QDeclarativeVisualDataModel> 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;
+
+ QDeclarativeVisualDataModelParts *m_parts;
+ friend class QDeclarativeVisualItemParts;
+
+ VDMDelegateDataType *m_delegateDataType;
+ friend class QDeclarativeVisualDataModelData;
+ bool m_metaDataCreated : 1;
+ bool m_metaDataCacheable : 1;
+ bool m_delegateValidated : 1;
+ bool m_completePending : 1;
+
+ QDeclarativeVisualDataModelData *data(QObject *item);
+
+ QVariant m_modelVariant;
+ QDeclarativeListAccessor *m_listAccessor;
+
+ QModelIndex m_root;
+ QList<QByteArray> watchedRoles;
+ QList<int> watchedRoleIds;
+};
+
+class QDeclarativeVisualDataModelDataMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QDeclarativeVisualDataModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type)
+ : QDeclarativeOpenMetaObject(parent, type) {}
+
+ virtual QVariant initialValue(int);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ friend class QDeclarativeVisualDataModelData;
+};
+
+class QDeclarativeVisualDataModelData : public QObject
+{
+Q_OBJECT
+public:
+ QDeclarativeVisualDataModelData(int index, QDeclarativeVisualDataModel *model);
+ ~QDeclarativeVisualDataModelData();
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ int index() const;
+ void setIndex(int index);
+
+ int propForRole(int) const;
+ int modelDataPropertyId() const {
+ QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::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 QDeclarativeVisualDataModelDataMetaObject;
+ int m_index;
+ QDeclarativeGuard<QDeclarativeVisualDataModel> m_model;
+ QDeclarativeVisualDataModelDataMetaObject *m_meta;
+};
+
+int QDeclarativeVisualDataModelData::propForRole(int id) const
+{
+ QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::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 QDeclarativeVisualDataModelData::setValue(int id, const QVariant &val)
+{
+ m_meta->setValue(id, val);
+}
+
+int QDeclarativeVisualDataModelDataMetaObject::createProperty(const char *name, const char *type)
+{
+ QDeclarativeVisualDataModelData *data =
+ static_cast<QDeclarativeVisualDataModelData *>(object());
+
+ if (!data->m_model)
+ return -1;
+
+ QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::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 QDeclarativeVisualDataModelDataMetaObject::initialValue(int propId)
+{
+ QDeclarativeVisualDataModelData *data =
+ static_cast<QDeclarativeVisualDataModelData *>(object());
+
+ Q_ASSERT(data->m_model);
+ QDeclarativeVisualDataModelPrivate *model = QDeclarativeVisualDataModelPrivate::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();
+}
+
+QDeclarativeVisualDataModelData::QDeclarativeVisualDataModelData(int index,
+ QDeclarativeVisualDataModel *model)
+: m_index(index), m_model(model),
+m_meta(new QDeclarativeVisualDataModelDataMetaObject(this, QDeclarativeVisualDataModelPrivate::get(model)->m_delegateDataType))
+{
+ ensureProperties();
+}
+
+QDeclarativeVisualDataModelData::~QDeclarativeVisualDataModelData()
+{
+}
+
+void QDeclarativeVisualDataModelData::ensureProperties()
+{
+ QDeclarativeVisualDataModelPrivate *modelPriv = QDeclarativeVisualDataModelPrivate::get(m_model);
+ if (modelPriv->m_metaDataCacheable) {
+ if (!modelPriv->m_metaDataCreated)
+ modelPriv->createMetaData();
+ if (modelPriv->m_metaDataCreated)
+ m_meta->setCached(true);
+ }
+}
+
+int QDeclarativeVisualDataModelData::index() const
+{
+ return m_index;
+}
+
+// This is internal only - it should not be set from qml
+void QDeclarativeVisualDataModelData::setIndex(int index)
+{
+ m_index = index;
+ emit indexChanged();
+}
+
+//---------------------------------------------------------------------------
+
+class QDeclarativeVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QDeclarativeVisualDataModelPartsMetaObject(QObject *parent)
+ : QDeclarativeOpenMetaObject(parent) {}
+
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual QVariant initialValue(int);
+};
+
+class QDeclarativeVisualDataModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QDeclarativeVisualDataModelParts(QDeclarativeVisualDataModel *parent);
+
+private:
+ friend class QDeclarativeVisualDataModelPartsMetaObject;
+ QDeclarativeVisualDataModel *model;
+};
+
+void QDeclarativeVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+}
+
+QVariant QDeclarativeVisualDataModelPartsMetaObject::initialValue(int id)
+{
+ QDeclarativeVisualDataModel *m = new QDeclarativeVisualDataModel;
+ m->setParent(object());
+ m->setPart(QString::fromUtf8(name(id)));
+ m->setModel(QVariant::fromValue(static_cast<QDeclarativeVisualDataModelParts *>(object())->model));
+
+ QVariant var = QVariant::fromValue((QObject *)m);
+ return var;
+}
+
+QDeclarativeVisualDataModelParts::QDeclarativeVisualDataModelParts(QDeclarativeVisualDataModel *parent)
+: QObject(parent), model(parent)
+{
+ new QDeclarativeVisualDataModelPartsMetaObject(this);
+}
+
+QDeclarativeVisualDataModelPrivate::QDeclarativeVisualDataModelPrivate(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)
+{
+}
+
+QDeclarativeVisualDataModelData *QDeclarativeVisualDataModelPrivate::data(QObject *item)
+{
+ QDeclarativeVisualDataModelData *dataItem =
+ item->findChild<QDeclarativeVisualDataModelData *>();
+ Q_ASSERT(dataItem);
+ return dataItem;
+}
+
+//---------------------------------------------------------------------------
+
+/*!
+ \qmlclass VisualDataModel QDeclarativeVisualDataModel
+ \ingroup qml-working-with-data
+ \brief The VisualDataModel encapsulates a model and delegate
+
+ A VisualDataModel encapsulates a model and the delegate that will
+ be instantiated for items in the model.
+
+ It is usually not necessary to create VisualDataModel elements.
+ However, it can be useful for manipulating and accessing the \l modelIndex
+ when a QAbstractItemModel subclass is used as the
+ model. Also, VisualDataModel is used together with \l Package to
+ provide delegates to multiple views.
+
+ The example below illustrates using a VisualDataModel with a ListView.
+
+ \snippet doc/src/snippets/declarative/visualdatamodel.qml 0
+*/
+
+QDeclarativeVisualDataModel::QDeclarativeVisualDataModel()
+: QDeclarativeVisualModel(*(new QDeclarativeVisualDataModelPrivate(0)))
+{
+}
+
+QDeclarativeVisualDataModel::QDeclarativeVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
+: QDeclarativeVisualModel(*(new QDeclarativeVisualDataModelPrivate(ctxt)), parent)
+{
+}
+
+QDeclarativeVisualDataModel::~QDeclarativeVisualDataModel()
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (d->m_listAccessor)
+ delete d->m_listAccessor;
+ if (d->m_delegateDataType)
+ d->m_delegateDataType->release();
+}
+
+/*!
+ \qmlproperty model VisualDataModel::model
+ This property holds the model providing data for the VisualDataModel.
+
+ The model provides a set of data that is used to create the items
+ for a view. For large or dynamic datasets the model is usually
+ provided by a C++ model object. The C++ model object must be a \l
+ {QAbstractItemModel} subclass or a simple list.
+
+ Models can also be created directly in QML, using a \l{ListModel} or
+ \l{XmlListModel}.
+
+ \sa {qmlmodels}{Data Models}
+*/
+QVariant QDeclarativeVisualDataModel::model() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ return d->m_modelVariant;
+}
+
+void QDeclarativeVisualDataModel::setModel(const QVariant &model)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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(&QDeclarativeVisualDataModelData::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<QDeclarativeVisualDataModel *>(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();
+ }
+}
+
+/*!
+ \qmlproperty Component VisualDataModel::delegate
+
+ The delegate provides a template defining each item instantiated by a view.
+ The index is exposed as an accessible \c index property. Properties of the
+ model are also available depending upon the type of \l {qmlmodels}{Data Model}.
+*/
+QDeclarativeComponent *QDeclarativeVisualDataModel::delegate() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->delegate();
+ return d->m_delegate;
+}
+
+void QDeclarativeVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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();
+ }
+}
+
+/*!
+ \qmlproperty QModelIndex VisualDataModel::rootIndex
+
+ QAbstractItemModel provides a hierarchical tree of data, whereas
+ QML only operates on list data. \c rootIndex allows the children of
+ any node in a QAbstractItemModel to be provided by this model.
+
+ This property only affects models of type QAbstractItemModel that
+ are hierarchical (e.g, a tree model).
+
+ For example, here is a simple interactive file system browser.
+ When a directory name is clicked, the view's \c rootIndex is set to the
+ QModelIndex node of the clicked directory, thus updating the view to show
+ the new directory's contents.
+
+ \c main.cpp:
+ \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0
+
+ \c view.qml:
+ \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0
+
+ If the \l model is a QAbstractItemModel subclass, the delegate can also
+ reference a \c hasModelChildren property (optionally qualified by a
+ \e model. prefix) that indicates whether the delegate's model item has
+ any child nodes.
+
+
+ \sa modelIndex(), parentModelIndex()
+*/
+QVariant QDeclarativeVisualDataModel::rootIndex() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ return QVariant::fromValue(d->m_root);
+}
+
+void QDeclarativeVisualDataModel::setRootIndex(const QVariant &root)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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();
+ }
+}
+
+
+/*!
+ \qmlmethod QModelIndex VisualDataModel::modelIndex(int index)
+
+ QAbstractItemModel provides a hierarchical tree of data, whereas
+ QML only operates on list data. This function assists in using
+ tree models in QML.
+
+ Returns a QModelIndex for the specified index.
+ This value can be assigned to rootIndex.
+
+ \sa rootIndex
+*/
+QVariant QDeclarativeVisualDataModel::modelIndex(int idx) const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+/*!
+ \qmlmethod QModelIndex VisualDataModel::parentModelIndex()
+
+ QAbstractItemModel provides a hierarchical tree of data, whereas
+ QML only operates on list data. This function assists in using
+ tree models in QML.
+
+ Returns a QModelIndex for the parent of the current rootIndex.
+ This value can be assigned to rootIndex.
+
+ \sa rootIndex
+*/
+QVariant QDeclarativeVisualDataModel::parentModelIndex() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ if (d->m_abstractItemModel)
+ return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root));
+ return QVariant::fromValue(QModelIndex());
+}
+
+QString QDeclarativeVisualDataModel::part() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ return d->m_part;
+}
+
+void QDeclarativeVisualDataModel::setPart(const QString &part)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ d->m_part = part;
+}
+
+int QDeclarativeVisualDataModel::count() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->count();
+ if (!d->m_delegate)
+ return 0;
+ return d->modelCount();
+}
+
+QDeclarativeItem *QDeclarativeVisualDataModel::item(int index, bool complete)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete);
+ return item(index, QByteArray(), complete);
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+QDeclarativeVisualDataModel::ReleaseFlags QDeclarativeVisualDataModel::release(QDeclarativeItem *item)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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 {
+ if (item->scene())
+ item->scene()->removeItem(item);
+ }
+ stat |= Destroyed;
+ obj->deleteLater();
+ } else if (!inPackage) {
+ stat |= Referenced;
+ }
+
+ return stat;
+}
+
+/*!
+ \qmlproperty object VisualDataModel::parts
+
+ The \a parts property selects a VisualDataModel which creates
+ delegates from the part named. This is used in conjunction with
+ the \l Package element.
+
+ For example, the code below selects a model which creates
+ delegates named \e list from a \l Package:
+
+ \code
+ VisualDataModel {
+ id: visualModel
+ delegate: Package {
+ Item { Package.name: "list" }
+ }
+ model: myModel
+ }
+
+ ListView {
+ width: 200; height:200
+ model: visualModel.parts.list
+ }
+ \endcode
+
+ \sa Package
+*/
+QObject *QDeclarativeVisualDataModel::parts()
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (!d->m_parts)
+ d->m_parts = new QDeclarativeVisualDataModelParts(this);
+ return d->m_parts;
+}
+
+QDeclarativeItem *QDeclarativeVisualDataModel::item(int index, const QByteArray &viewId, bool complete)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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);
+ QDeclarativeVisualDataModelData *data = new QDeclarativeVisualDataModelData(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";
+ }
+ }
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(nobj);
+ if (!item) {
+ QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(nobj);
+ if (package) {
+ QObject *o = package->part(QString::fromUtf8(viewId));
+ item = qobject_cast<QDeclarativeItem *>(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) << QDeclarativeVisualDataModel::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 QDeclarativeVisualDataModel::completePending() const
+{
+ Q_D(const QDeclarativeVisualDataModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->completePending();
+ return d->m_completePending;
+}
+
+void QDeclarativeVisualDataModel::completeItem()
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (d->m_visualItemModel) {
+ d->m_visualItemModel->completeItem();
+ return;
+ }
+
+ d->m_delegate->completeCreate();
+ d->m_completePending = false;
+}
+
+QString QDeclarativeVisualDataModel::stringValue(int index, const QString &name)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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 QDeclarativeVisualDataModelData(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 QDeclarativeVisualDataModel::indexOf(QDeclarativeItem *item, QObject *) const
+{
+ QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index"));
+ return val.toInt();
+ return -1;
+}
+
+void QDeclarativeVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ d->watchedRoles = roles;
+ d->watchedRoleIds.clear();
+}
+
+void QDeclarativeVisualDataModel::_q_itemsChanged(int index, int count,
+ const QList<int> &roles)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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,QDeclarativeVisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ++iter) {
+ const int idx = iter.key();
+
+ if (idx >= index && idx < index+count) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ QDeclarativeVisualDataModelData *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 QDeclarativeVisualDataModel::_q_itemsInserted(int index, int count)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int,QDeclarativeVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QDeclarativeVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= index) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QDeclarativeVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsInserted(index, count);
+ emit countChanged();
+}
+
+void QDeclarativeVisualDataModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (!count)
+ return;
+ // XXX - highly inefficient
+ QHash<int, QDeclarativeVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int, QDeclarativeVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if (iter.key() >= index && iter.key() < index + count) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
+ QDeclarativeVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(-1);
+ } else if (iter.key() >= index + count) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, objRef);
+ QDeclarativeVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+
+ d->m_cache.unite(items);
+ emit itemsRemoved(index, count);
+ emit countChanged();
+}
+
+void QDeclarativeVisualDataModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ // XXX - highly inefficient
+ QHash<int,QDeclarativeVisualDataModelPrivate::ObjectRef> items;
+ for (QHash<int,QDeclarativeVisualDataModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= from && iter.key() < from + count) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QDeclarativeVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ for (QHash<int,QDeclarativeVisualDataModelPrivate::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)) {
+ QDeclarativeVisualDataModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + diff;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QDeclarativeVisualDataModelData *data = d->data(objRef.obj);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsMoved(from, to, count);
+}
+
+void QDeclarativeVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsInserted(begin, end - begin + 1);
+}
+
+void QDeclarativeVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (parent == d->m_root)
+ _q_itemsRemoved(begin, end - begin + 1);
+}
+
+void QDeclarativeVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ 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 QDeclarativeVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ if (begin.parent() == d->m_root)
+ _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
+}
+
+void QDeclarativeVisualDataModel::_q_layoutChanged()
+{
+ Q_D(QDeclarativeVisualDataModel);
+ _q_itemsChanged(0, count(), d->m_roles);
+}
+
+void QDeclarativeVisualDataModel::_q_modelReset()
+{
+ emit modelReset();
+}
+
+void QDeclarativeVisualDataModel::_q_createdPackage(int index, QDeclarativePackage *package)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ emit createdItem(index, qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
+}
+
+void QDeclarativeVisualDataModel::_q_destroyingPackage(QDeclarativePackage *package)
+{
+ Q_D(QDeclarativeVisualDataModel);
+ emit destroyingItem(qobject_cast<QDeclarativeItem*>(package->part(d->m_part)));
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QListModelInterface)
+
+#include <qdeclarativevisualitemmodel.moc>
diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h
new file mode 100644
index 0000000000..19ee4ec30c
--- /dev/null
+++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEVISUALDATAMODEL_H
+#define QDECLARATIVEVISUALDATAMODEL_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractitemmodel.h>
+
+QT_BEGIN_HEADER
+
+Q_DECLARE_METATYPE(QModelIndex)
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeItem;
+class QDeclarativeComponent;
+class QDeclarativePackage;
+class QDeclarativeVisualDataModelPrivate;
+
+class Q_AUTOTEST_EXPORT QDeclarativeVisualModel : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+public:
+ virtual ~QDeclarativeVisualModel() {}
+
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
+
+ virtual int count() const = 0;
+ virtual bool isValid() const = 0;
+ virtual QDeclarativeItem *item(int index, bool complete=true) = 0;
+ virtual ReleaseFlags release(QDeclarativeItem *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(QDeclarativeItem *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, QDeclarativeItem *item);
+ void destroyingItem(QDeclarativeItem *item);
+
+protected:
+ QDeclarativeVisualModel(QObjectPrivate &dd, QObject *parent = 0)
+ : QObject(dd, parent) {}
+
+private:
+ Q_DISABLE_COPY(QDeclarativeVisualModel)
+};
+
+class QDeclarativeVisualItemModelAttached;
+class QDeclarativeVisualItemModelPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeVisualItemModel : public QDeclarativeVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeVisualItemModel)
+
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ QDeclarativeVisualItemModel(QObject *parent=0);
+ virtual ~QDeclarativeVisualItemModel() {}
+
+ virtual int count() const;
+ virtual bool isValid() const;
+ virtual QDeclarativeItem *item(int index, bool complete=true);
+ virtual ReleaseFlags release(QDeclarativeItem *item);
+ virtual bool completePending() const;
+ virtual void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray>) {}
+
+ virtual int indexOf(QDeclarativeItem *item, QObject *objectContext) const;
+
+ QDeclarativeListProperty<QDeclarativeItem> children();
+
+ static QDeclarativeVisualItemModelAttached *qmlAttachedProperties(QObject *obj);
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeVisualItemModel)
+};
+
+
+class Q_AUTOTEST_EXPORT QDeclarativeVisualDataModel : public QDeclarativeVisualModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeVisualDataModel)
+
+ 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:
+ QDeclarativeVisualDataModel();
+ QDeclarativeVisualDataModel(QDeclarativeContext *, QObject *parent=0);
+ virtual ~QDeclarativeVisualDataModel();
+
+ 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; }
+ QDeclarativeItem *item(int index, bool complete=true);
+ QDeclarativeItem *item(int index, const QByteArray &, bool complete=true);
+ ReleaseFlags release(QDeclarativeItem *item);
+ bool completePending() const;
+ void completeItem();
+ virtual QString stringValue(int index, const QString &role);
+ virtual void setWatchedRoles(QList<QByteArray> roles);
+
+ int indexOf(QDeclarativeItem *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(QDeclarativeVisualDataModel)
+};
+
+class QDeclarativeVisualItemModelAttached : public QObject
+{
+ Q_OBJECT
+
+public:
+ QDeclarativeVisualItemModelAttached(QObject *parent)
+ : QObject(parent), m_index(0) {}
+ ~QDeclarativeVisualItemModelAttached() {
+ 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 QDeclarativeVisualItemModelAttached *properties(QObject *obj) {
+ QDeclarativeVisualItemModelAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QDeclarativeVisualItemModelAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+Q_SIGNALS:
+ void indexChanged();
+
+public:
+ int m_index;
+
+ static QHash<QObject*, QDeclarativeVisualItemModelAttached*> attachedProperties;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeVisualModel)
+QML_DECLARE_TYPE(QDeclarativeVisualItemModel)
+QML_DECLARE_TYPEINFO(QDeclarativeVisualItemModel, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QDeclarativeVisualDataModel)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEVISUALDATAMODEL_H
diff --git a/src/declarative/qml/parser/parser.pri b/src/declarative/qml/parser/parser.pri
new file mode 100644
index 0000000000..fd4361c2df
--- /dev/null
+++ b/src/declarative/qml/parser/parser.pri
@@ -0,0 +1,21 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qdeclarativejsast_p.h \
+ $$PWD/qdeclarativejsastfwd_p.h \
+ $$PWD/qdeclarativejsastvisitor_p.h \
+ $$PWD/qdeclarativejsengine_p.h \
+ $$PWD/qdeclarativejsgrammar_p.h \
+ $$PWD/qdeclarativejslexer_p.h \
+ $$PWD/qdeclarativejsmemorypool_p.h \
+ $$PWD/qdeclarativejsnodepool_p.h \
+ $$PWD/qdeclarativejsparser_p.h \
+ $$PWD/qdeclarativejsglobal_p.h
+
+SOURCES += \
+ $$PWD/qdeclarativejsast.cpp \
+ $$PWD/qdeclarativejsastvisitor.cpp \
+ $$PWD/qdeclarativejsengine_p.cpp \
+ $$PWD/qdeclarativejsgrammar.cpp \
+ $$PWD/qdeclarativejslexer.cpp \
+ $$PWD/qdeclarativejsparser.cpp
diff --git a/src/declarative/qml/parser/qdeclarativejs.g b/src/declarative/qml/parser/qdeclarativejs.g
new file mode 100644
index 0000000000..0e7454e42b
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejs.g
@@ -0,0 +1,3149 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 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-ONLY$
+-- GNU Lesser General Public License Usage
+-- This file may be used under the terms of the GNU Lesser
+-- General Public License version 2.1 as published by the Free Software
+-- Foundation and appearing in the file LICENSE.LGPL included in the
+-- packaging of this file. Please review the following information to
+-- ensure the GNU Lesser General Public License version 2.1 requirements
+-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+--
+-- If you have questions regarding the use of this file, please contact
+-- Nokia at qt-info@nokia.com.
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser QDeclarativeJSGrammar
+%decl qdeclarativejsparser_p.h
+%impl qdeclarativejsparser.cpp
+%expect 2
+%expect-rr 2
+
+%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
+%token T_BREAK "break" T_CASE "case" T_CATCH "catch"
+%token T_COLON ":" T_COMMA ";" T_CONTINUE "continue"
+%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/"
+%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "."
+%token T_ELSE "else" T_EQ "=" T_EQ_EQ "=="
+%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for"
+%token T_FUNCTION "function" T_GE ">=" T_GT ">"
+%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>"
+%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if"
+%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{"
+%token T_LBRACKET "[" T_LE "<=" T_LPAREN "("
+%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<="
+%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--"
+%token T_NEW "new" T_NOT "!" T_NOT_EQ "!="
+%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|"
+%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+"
+%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?"
+%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
+%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")"
+%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*"
+%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal"
+%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly"
+%token T_SWITCH "switch" T_THIS "this" T_THROW "throw"
+%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof"
+%token T_VAR "var" T_VOID "void" T_WHILE "while"
+%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
+%token T_NULL "null" T_TRUE "true" T_FALSE "false"
+%token T_CONST "const"
+%token T_DEBUGGER "debugger"
+%token T_RESERVED_WORD "reserved word"
+%token T_MULTILINE_STRING_LITERAL "multiline string literal"
+%token T_COMMENT "comment"
+
+--- context keywords.
+%token T_PUBLIC "public"
+%token T_IMPORT "import"
+%token T_AS "as"
+%token T_ON "on"
+
+--- feed tokens
+%token T_FEED_UI_PROGRAM
+%token T_FEED_UI_OBJECT_MEMBER
+%token T_FEED_JS_STATEMENT
+%token T_FEED_JS_EXPRESSION
+%token T_FEED_JS_SOURCE_ELEMENT
+%token T_FEED_JS_PROGRAM
+
+%nonassoc SHIFT_THERE
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY
+%nonassoc REDUCE_HERE
+
+%start TopLevel
+
+/./****************************************************************************
+**
+** Copyright (C) 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 <QtCore/QtDebug>
+#include <QtGui/QApplication>
+
+#include <string.h>
+
+#include "private/qdeclarativejsengine_p.h"
+#include "private/qdeclarativejslexer_p.h"
+#include "private/qdeclarativejsast_p.h"
+#include "private/qdeclarativejsnodepool_p.h"
+
+./
+
+/:/****************************************************************************
+**
+** Copyright (C) 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$
+**
+****************************************************************************/
+
+
+//
+// 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.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QDECLARATIVEJSPARSER_P_H
+#define QDECLARATIVEJSPARSER_P_H
+
+#include "private/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsgrammar_p.h"
+#include "private/qdeclarativejsast_p.h"
+#include "private/qdeclarativejsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Parser: protected $table
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ NameId *sval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ AST::UiSignature *UiSignature;
+ AST::UiFormalList *UiFormalList;
+ AST::UiFormal *UiFormal;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ };
+
+ double yylval;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QDeclarativeJS
+
+
+:/
+
+
+/.
+
+#include "private/qdeclarativejsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QDeclarativeJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+}
+
+inline static bool automatic(Engine *driver, int token)
+{
+ return token == $table::T_RBRACE
+ || token == 0
+ || driver->lexer()->prevTerminator();
+}
+
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ qFree(sym_stack);
+ qFree(state_stack);
+ qFree(location_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->startLineNo();
+ loc.startColumn = lexer->startColumnNo();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<NameId *, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->dval();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Declarative UI
+--------------------------------------------------------------------------------------------------------
+
+TopLevel: T_FEED_UI_PROGRAM UiProgram ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_STATEMENT Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_EXPRESSION Expression ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_PROGRAM Program ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+UiProgram: UiImportListOpt UiRootMember ;
+/.
+case $rule_number: {
+ sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+./
+
+UiImportListOpt: Empty ;
+UiImportListOpt: UiImportList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+./
+
+UiImportList: UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport);
+} break;
+./
+
+UiImportList: UiImportList UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(),
+ sym(1).UiImportList, sym(2).UiImport);
+} break;
+./
+
+ImportId: MemberExpression ;
+
+UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = sym(4).sval;
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+./
+
+UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = sym(3).sval;
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+./
+
+
+UiImportHead: T_IMPORT ImportId ;
+/.
+case $rule_number: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+./
+
+Empty: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiRootMember: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMemberList UiObjectMember ;
+/.
+case $rule_number: {
+ AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(),
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+./
+
+UiArrayMemberList: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+./
+
+UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ;
+/.
+case $rule_number: {
+ AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(),
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectDefinition: UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiObjectDefinition ;
+
+UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_COLON Block ;
+/.case $rule_number:./
+
+UiObjectMember: UiQualifiedId T_COLON EmptyStatement ;
+/.case $rule_number:./
+
+UiObjectMember: UiQualifiedId T_COLON ExpressionStatement ;
+/.case $rule_number:./
+
+UiObjectMember: UiQualifiedId T_COLON IfStatement ; --- ### do we really want if statement in a binding?
+/.case $rule_number:./
+
+/.
+{
+ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiPropertyType: T_VAR ;
+/.
+case $rule_number:
+./
+UiPropertyType: T_RESERVED_WORD ;
+/.
+case $rule_number: {
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+ break;
+}
+./
+
+UiPropertyType: T_IDENTIFIER ;
+
+UiParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiParameterListOpt: UiParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+./
+
+UiParameterList: UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
+ sym(5).Expression);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Expression);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Expression);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval);
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval);
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+./
+
+UiObjectMember: VariableStatement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+./
+
+JsIdentifier: T_IDENTIFIER;
+
+JsIdentifier: T_PROPERTY ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_PROPERTY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_SIGNAL ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_SIGNAL]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_READONLY ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_READONLY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+JsIdentifier: T_ON ;
+/.
+case $rule_number: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_ON]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Expressions
+--------------------------------------------------------------------------------------------------------
+
+PrimaryExpression: T_THIS ;
+/.
+case $rule_number: {
+ AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool());
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NULL ;
+/.
+case $rule_number: {
+ AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool());
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_TRUE ;
+/.
+case $rule_number: {
+ AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool());
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_FALSE ;
+/.
+case $rule_number: {
+ AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool());
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_MULTILINE_STRING_LITERAL ;
+/.case $rule_number:./
+
+PrimaryExpression: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_EQ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+-- PrimaryExpression: T_LBRACE T_RBRACE ;
+-- /.
+-- case $rule_number: {
+-- sym(1).Node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+-- } break;
+-- ./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LPAREN Expression T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiQualifiedId: MemberExpression ;
+/.
+case $rule_number: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+./
+
+ElementList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression);
+} break;
+./
+
+ElementList: Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression);
+} break;
+./
+
+ElementList: ElementList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ElementList: ElementList T_COMMA Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool());
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: Elision T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_SIGNAL ;
+/.case $rule_number:./
+
+PropertyName: T_PROPERTY ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: ReservedIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ReservedIdentifier: T_BREAK ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CASE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CATCH ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CONTINUE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DEFAULT ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DELETE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DO ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_ELSE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FALSE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FINALLY ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FOR ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_FUNCTION ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_IF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_IN ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_INSTANCEOF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_NEW ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_NULL ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_RETURN ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_SWITCH ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_THIS ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_THROW ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TRUE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TRY ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_TYPEOF ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_VAR ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_VOID ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_WHILE ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_CONST ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_DEBUGGER ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_RESERVED_WORD ;
+/.
+case $rule_number:
+./
+ReservedIdentifier: T_WITH ;
+/.
+case $rule_number:
+{
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+} break;
+./
+
+PropertyIdentifier: JsIdentifier ;
+PropertyIdentifier: ReservedIdentifier ;
+
+MemberExpression: PrimaryExpression ;
+MemberExpression: FunctionExpression ;
+
+MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: MemberExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+NewExpression: MemberExpression ;
+
+NewExpression: T_NEW NewExpression ;
+/.
+case $rule_number: {
+ AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ArgumentListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ArgumentListOpt: ArgumentList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+./
+
+ArgumentList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression);
+} break;
+./
+
+ArgumentList: ArgumentList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LeftHandSideExpression: NewExpression ;
+LeftHandSideExpression: CallExpression ;
+PostfixExpression: LeftHandSideExpression ;
+
+PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ;
+/.
+case $rule_number: {
+ AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ;
+/.
+case $rule_number: {
+ AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: PostfixExpression ;
+
+UnaryExpression: T_DELETE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_VOID UnaryExpression ;
+/.
+case $rule_number: {
+ AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TYPEOF UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TILDE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_NOT UnaryExpression ;
+/.
+case $rule_number: {
+ AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: UnaryExpression ;
+
+MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: MultiplicativeExpression ;
+
+AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: AdditiveExpression ;
+
+ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: ShiftExpression ;
+
+RelationalExpression: RelationalExpression T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_IN ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: ShiftExpression ;
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: RelationalExpression ;
+
+EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: RelationalExpressionNotIn ;
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpression: EqualityExpression ;
+
+BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpressionNotIn: EqualityExpressionNotIn ;
+
+BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpression: BitwiseANDExpression ;
+
+BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ;
+
+BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpression: BitwiseXORExpression ;
+
+BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ;
+
+BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpression: BitwiseORExpression ;
+
+LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ;
+
+LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpression: LogicalANDExpression ;
+
+LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpressionNotIn: LogicalANDExpressionNotIn ;
+
+LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpression: LogicalORExpression ;
+
+ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn ;
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpression: ConditionalExpression ;
+
+AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpressionNotIn: ConditionalExpressionNotIn ;
+
+AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentOperator: T_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+./
+
+AssignmentOperator: T_STAR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+./
+
+AssignmentOperator: T_DIVIDE_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+./
+
+AssignmentOperator: T_REMAINDER_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+./
+
+AssignmentOperator: T_PLUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+./
+
+AssignmentOperator: T_MINUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+./
+
+AssignmentOperator: T_LT_LT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+./
+
+AssignmentOperator: T_AND_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+./
+
+AssignmentOperator: T_XOR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+./
+
+AssignmentOperator: T_OR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+./
+
+Expression: AssignmentExpression ;
+
+Expression: Expression T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionOpt: Expression ;
+
+ExpressionNotIn: AssignmentExpressionNotIn ;
+
+ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionNotInOpt: ExpressionNotIn ;
+
+Statement: Block ;
+Statement: VariableStatement ;
+Statement: EmptyStatement ;
+Statement: ExpressionStatement ;
+Statement: IfStatement ;
+Statement: IterationStatement ;
+Statement: ContinueStatement ;
+Statement: BreakStatement ;
+Statement: ReturnStatement ;
+Statement: WithStatement ;
+Statement: LabelledStatement ;
+Statement: SwitchStatement ;
+Statement: ThrowStatement ;
+Statement: TryStatement ;
+Statement: DebuggerStatement ;
+
+
+Block: T_LBRACE StatementListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+StatementList: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement);
+} break;
+./
+
+StatementList: StatementList Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement);
+} break;
+./
+
+StatementListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+StatementListOpt: StatementList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+./
+
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(),
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationKind: T_CONST ;
+/.
+case $rule_number: {
+ sym(1).ival = T_CONST;
+} break;
+./
+
+VariableDeclarationKind: T_VAR ;
+/.
+case $rule_number: {
+ sym(1).ival = T_VAR;
+} break;
+./
+
+VariableDeclarationList: VariableDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ;
+/.
+case $rule_number: {
+ AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(),
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+./
+
+VariableDeclaration: JsIdentifier InitialiserOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Initialiser: T_EQ AssignmentExpression ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserOpt: Initialiser ;
+
+InitialiserNotIn: T_EQ AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserNotInOpt: InitialiserNotIn ;
+
+EmptyStatement: T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool());
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ExpressionStatement: Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(),
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(),
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool());
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval);
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval);
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ;
+/.
+case $rule_number: {
+ AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+CaseClauses: CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause);
+} break;
+./
+
+CaseClauses: CaseClauses CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+./
+
+CaseClausesOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+CaseClausesOpt: CaseClauses ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+./
+
+CaseClause: T_CASE Expression T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+DefaultClause: T_DEFAULT T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_SIGNAL T_COLON Statement ;
+/.case $rule_number:./
+
+LabelledStatement: T_PROPERTY T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_IDENTIFIER T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ThrowStatement: T_THROW Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ;
+/.
+case $rule_number: {
+ AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+Finally: T_FINALLY Block ;
+/.
+case $rule_number: {
+ AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+DebuggerStatement: T_DEBUGGER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool());
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (sym(2).sval)
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FormalParameterListOpt: FormalParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+./
+
+FunctionBodyOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FunctionBodyOpt: FunctionBody ;
+
+FunctionBody: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+./
+
+Program: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+./
+
+SourceElements: SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement);
+} break;
+./
+
+SourceElements: SourceElements SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement);
+} break;
+./
+
+SourceElement: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement);
+} break;
+./
+
+SourceElement: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration);
+} break;
+./
+
+IdentifierOpt: ;
+/.
+case $rule_number: {
+ sym(1).sval = 0;
+} break;
+./
+
+IdentifierOpt: JsIdentifier ;
+
+PropertyNameAndValueListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+PropertyNameAndValueListOpt: PropertyNameAndValueList ;
+
+/.
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QDeclarativeParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->dval();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QDeclarativeParser", "Syntax error");
+ else
+ msg = qApp->translate("QDeclarativeParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QDeclarativeParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
+./
+/:
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QDECLARATIVEJSPARSER_P_H
+:/
diff --git a/src/declarative/qml/parser/qdeclarativejsast.cpp b/src/declarative/qml/parser/qdeclarativejsast.cpp
new file mode 100644
index 0000000000..afb399abf0
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsast.cpp
@@ -0,0 +1,956 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativejsast_p.h"
+
+#include "private/qdeclarativejsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS { namespace AST {
+
+void Node::accept(Visitor *visitor)
+{
+ if (visitor->preVisit(this)) {
+ accept0(visitor);
+ }
+ visitor->postVisit(this);
+}
+
+void Node::accept(Node *node, Visitor *visitor)
+{
+ if (node)
+ node->accept(visitor);
+}
+
+ExpressionNode *Node::expressionCast()
+{
+ return 0;
+}
+
+BinaryExpression *Node::binaryExpressionCast()
+{
+ return 0;
+}
+
+Statement *Node::statementCast()
+{
+ return 0;
+}
+
+UiObjectMember *Node::uiObjectMemberCast()
+{
+ return 0;
+}
+
+ExpressionNode *ExpressionNode::expressionCast()
+{
+ return this;
+}
+
+BinaryExpression *BinaryExpression::binaryExpressionCast()
+{
+ return this;
+}
+
+Statement *Statement::statementCast()
+{
+ return this;
+}
+
+UiObjectMember *UiObjectMember::uiObjectMemberCast()
+{
+ return this;
+}
+
+void NestedExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void ThisExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NullExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void TrueLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void FalseLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void RegExpLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ accept(elision, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ObjectLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(properties, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ElementList *it = this; it; it = it->next) {
+ accept(it->elision, visitor);
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void Elision::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void PropertyNameAndValueList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PropertyNameAndValueList *it = this; it; it = it->next) {
+ accept(it->name, visitor);
+ accept(it->value, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FieldMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CallExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ArgumentList *it = this; it; it = it->next) {
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DeleteExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VoidExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeOfExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryPlusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryMinusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TildeExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NotExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void BinaryExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ConditionalExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Expression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Block::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementList *it = this; it; it = it->next) {
+ accept(it->statement, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclarationList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (VariableDeclarationList *it = this; it; it = it->next) {
+ accept(it->declaration, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void EmptyStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ExpressionStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void IfStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DoWhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ContinueStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void BreakStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ReturnStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WithStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SwitchStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(block, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseBlock::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(clauses, visitor);
+ accept(defaultClause, visitor);
+ accept(moreClauses, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClauses::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (CaseClauses *it = this; it; it = it->next) {
+ accept(it->clause, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DefaultClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LabelledStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ThrowStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TryStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catchExpression, visitor);
+ accept(finallyExpression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Catch::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Finally::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FormalParameterList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionBody::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Program::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SourceElements::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SourceElements *it = this; it; it = it->next) {
+ accept(it->element, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DebuggerStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiProgram::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(imports, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSignature::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void UiFormalList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiFormalList *it = this; it; it = it->next) {
+ accept(it->formal, visitor);
+ }
+ }
+ visitor->endVisit(this);
+}
+
+void UiFormal::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+ visitor->endVisit(this);
+}
+
+void UiPublicMember::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(binding, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectDefinition::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectInitializer::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiScriptBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiObjectMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiArrayMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiQualifiedId::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImport::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(importUri, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImportList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(import, visitor);
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(sourceElement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+} } // namespace QDeclarativeJS::AST
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/declarative/qml/parser/qdeclarativejsast_p.h b/src/declarative/qml/parser/qdeclarativejsast_p.h
new file mode 100644
index 0000000000..956d6e7545
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsast_p.h
@@ -0,0 +1,2546 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSAST_P_H
+#define QDECLARATIVEJSAST_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/qdeclarativejsastvisitor_p.h"
+#include "private/qdeclarativejsglobal_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+#define QDECLARATIVEJS_DECLARE_AST_NODE(name) \
+ enum { K = Kind_##name };
+
+namespace QSOperator // ### rename
+{
+
+enum Op {
+ Add,
+ And,
+ InplaceAnd,
+ Assign,
+ BitAnd,
+ BitOr,
+ BitXor,
+ InplaceSub,
+ Div,
+ InplaceDiv,
+ Equal,
+ Ge,
+ Gt,
+ In,
+ InplaceAdd,
+ InstanceOf,
+ Le,
+ LShift,
+ InplaceLeftShift,
+ Lt,
+ Mod,
+ InplaceMod,
+ Mul,
+ InplaceMul,
+ NotEqual,
+ Or,
+ InplaceOr,
+ RShift,
+ InplaceRightShift,
+ StrictEqual,
+ StrictNotEqual,
+ Sub,
+ URShift,
+ InplaceURightShift,
+ InplaceXor
+};
+
+} // namespace QSOperator
+
+namespace QDeclarativeJS {
+class NameId;
+namespace AST {
+
+template <typename _T1, typename _T2>
+_T1 cast(_T2 *ast)
+{
+ if (ast && ast->kind == static_cast<_T1>(0)->K)
+ return static_cast<_T1>(ast);
+
+ return 0;
+}
+
+class QML_PARSER_EXPORT Node
+{
+public:
+ enum Kind {
+ Kind_Undefined,
+
+ Kind_ArgumentList,
+ Kind_ArrayLiteral,
+ Kind_ArrayMemberExpression,
+ Kind_BinaryExpression,
+ Kind_Block,
+ Kind_BreakStatement,
+ Kind_CallExpression,
+ Kind_CaseBlock,
+ Kind_CaseClause,
+ Kind_CaseClauses,
+ Kind_Catch,
+ Kind_ConditionalExpression,
+ Kind_ContinueStatement,
+ Kind_DebuggerStatement,
+ Kind_DefaultClause,
+ Kind_DeleteExpression,
+ Kind_DoWhileStatement,
+ Kind_ElementList,
+ Kind_Elision,
+ Kind_EmptyStatement,
+ Kind_Expression,
+ Kind_ExpressionStatement,
+ Kind_FalseLiteral,
+ Kind_FieldMemberExpression,
+ Kind_Finally,
+ Kind_ForEachStatement,
+ Kind_ForStatement,
+ Kind_FormalParameterList,
+ Kind_FunctionBody,
+ Kind_FunctionDeclaration,
+ Kind_FunctionExpression,
+ Kind_FunctionSourceElement,
+ Kind_IdentifierExpression,
+ Kind_IdentifierPropertyName,
+ Kind_IfStatement,
+ Kind_LabelledStatement,
+ Kind_LocalForEachStatement,
+ Kind_LocalForStatement,
+ Kind_NewExpression,
+ Kind_NewMemberExpression,
+ Kind_NotExpression,
+ Kind_NullExpression,
+ Kind_NumericLiteral,
+ Kind_NumericLiteralPropertyName,
+ Kind_ObjectLiteral,
+ Kind_PostDecrementExpression,
+ Kind_PostIncrementExpression,
+ Kind_PreDecrementExpression,
+ Kind_PreIncrementExpression,
+ Kind_Program,
+ Kind_PropertyName,
+ Kind_PropertyNameAndValueList,
+ Kind_RegExpLiteral,
+ Kind_ReturnStatement,
+ Kind_SourceElement,
+ Kind_SourceElements,
+ Kind_StatementList,
+ Kind_StatementSourceElement,
+ Kind_StringLiteral,
+ Kind_StringLiteralPropertyName,
+ Kind_SwitchStatement,
+ Kind_ThisExpression,
+ Kind_ThrowStatement,
+ Kind_TildeExpression,
+ Kind_TrueLiteral,
+ Kind_TryStatement,
+ Kind_TypeOfExpression,
+ Kind_UnaryMinusExpression,
+ Kind_UnaryPlusExpression,
+ Kind_VariableDeclaration,
+ Kind_VariableDeclarationList,
+ Kind_VariableStatement,
+ Kind_VoidExpression,
+ Kind_WhileStatement,
+ Kind_WithStatement,
+ Kind_NestedExpression,
+
+ Kind_UiArrayBinding,
+ Kind_UiImport,
+ Kind_UiImportList,
+ Kind_UiObjectBinding,
+ Kind_UiObjectDefinition,
+ Kind_UiObjectInitializer,
+ Kind_UiObjectMemberList,
+ Kind_UiArrayMemberList,
+ Kind_UiProgram,
+ Kind_UiParameterList,
+ Kind_UiPublicMember,
+ Kind_UiQualifiedId,
+ Kind_UiScriptBinding,
+ Kind_UiSourceElement,
+ Kind_UiFormal,
+ Kind_UiFormalList,
+ Kind_UiSignature
+ };
+
+ inline Node()
+ : kind(Kind_Undefined) {}
+
+ // NOTE: node destructors are never called,
+ // instead we block free the memory
+ // (see the NodePool class)
+ virtual ~Node() {}
+
+ virtual ExpressionNode *expressionCast();
+ virtual BinaryExpression *binaryExpressionCast();
+ virtual Statement *statementCast();
+ virtual UiObjectMember *uiObjectMemberCast();
+
+ void accept(Visitor *visitor);
+ static void accept(Node *node, Visitor *visitor);
+
+ inline static void acceptChild(Node *node, Visitor *visitor)
+ { return accept(node, visitor); } // ### remove
+
+ virtual void accept0(Visitor *visitor) = 0;
+
+// attributes
+ int kind;
+};
+
+class QML_PARSER_EXPORT ExpressionNode: public Node
+{
+public:
+ ExpressionNode() {}
+
+ virtual ExpressionNode *expressionCast();
+
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+};
+
+class QML_PARSER_EXPORT Statement: public Node
+{
+public:
+ Statement() {}
+
+ virtual Statement *statementCast();
+
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+};
+
+class QML_PARSER_EXPORT UiFormal: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiFormal)
+
+ UiFormal(NameId *name, NameId *alias = 0)
+ : name(name), alias(alias)
+ { }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ NameId *alias;
+ SourceLocation identifierToken;
+ SourceLocation asToken;
+ SourceLocation aliasToken;
+};
+
+class QML_PARSER_EXPORT UiFormalList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiFormalList)
+
+ UiFormalList(UiFormal *formal)
+ : formal(formal), next(this) {}
+
+ UiFormalList(UiFormalList *previous, UiFormal *formal)
+ : formal(formal)
+ {
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiFormalList *finish()
+ {
+ UiFormalList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiFormal *formal;
+ UiFormalList *next;
+};
+
+class QML_PARSER_EXPORT UiSignature: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiSignature)
+
+ UiSignature(UiFormalList *formals = 0)
+ : formals(formals)
+ { }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return SourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceLocation lparenToken;
+ UiFormalList *formals;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NestedExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NestedExpression)
+
+ NestedExpression(ExpressionNode *expression)
+ : expression(expression)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lparenToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ThisExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ThisExpression)
+
+ ThisExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return thisToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return thisToken; }
+
+// attributes
+ SourceLocation thisToken;
+};
+
+class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(IdentifierExpression)
+
+ IdentifierExpression(NameId *n):
+ name (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+// attributes
+ NameId *name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NullExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NullExpression)
+
+ NullExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return nullToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return nullToken; }
+
+// attributes
+ SourceLocation nullToken;
+};
+
+class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(TrueLiteral)
+
+ TrueLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return trueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return trueToken; }
+
+// attributes
+ SourceLocation trueToken;
+};
+
+class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FalseLiteral)
+
+ FalseLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return falseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return falseToken; }
+
+// attributes
+ SourceLocation falseToken;
+};
+
+class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NumericLiteral)
+
+ NumericLiteral(double v):
+ value(v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ double value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT StringLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(StringLiteral)
+
+ StringLiteral(NameId *v):
+ value (v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ NameId *value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(RegExpLiteral)
+
+ RegExpLiteral(NameId *p, int f):
+ pattern (p), flags (f) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ NameId *pattern;
+ int flags;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ArrayLiteral)
+
+ ArrayLiteral(Elision *e):
+ elements (0), elision (e)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts):
+ elements (elts), elision (0)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts, Elision *e):
+ elements (elts), elision (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbracketToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ElementList *elements;
+ Elision *elision;
+ SourceLocation lbracketToken;
+ SourceLocation commaToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ObjectLiteral)
+
+ ObjectLiteral():
+ properties (0) { kind = K; }
+
+ ObjectLiteral(PropertyNameAndValueList *plist):
+ properties (plist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ PropertyNameAndValueList *properties;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT ElementList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ElementList)
+
+ ElementList(Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr), next (this)
+ { kind = K; }
+
+ ElementList(ElementList *previous, Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ inline ElementList *finish ()
+ {
+ ElementList *front = next;
+ next = 0;
+ return front;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Elision *elision;
+ ExpressionNode *expression;
+ ElementList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Elision: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Elision)
+
+ Elision():
+ next (this) { kind = K; }
+
+ Elision(Elision *previous)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline Elision *finish ()
+ {
+ Elision *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Elision *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyNameAndValueList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PropertyNameAndValueList)
+
+ PropertyNameAndValueList(PropertyName *n, ExpressionNode *v):
+ name (n), value (v), next (this)
+ { kind = K; }
+
+ PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v):
+ name (n), value (v)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline PropertyNameAndValueList *finish ()
+ {
+ PropertyNameAndValueList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ PropertyName *name;
+ ExpressionNode *value;
+ PropertyNameAndValueList *next;
+ SourceLocation colonToken;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyName: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PropertyName)
+
+ PropertyName() { kind = K; }
+
+// attributes
+ SourceLocation propertyNameToken;
+};
+
+class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(IdentifierPropertyName)
+
+ IdentifierPropertyName(NameId *n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *id;
+};
+
+class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(StringLiteralPropertyName)
+
+ StringLiteralPropertyName(NameId *n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *id;
+};
+
+class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NumericLiteralPropertyName)
+
+ NumericLiteralPropertyName(double n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ double id;
+};
+
+class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ArrayMemberExpression)
+
+ ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e):
+ base (b), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ExpressionNode *base;
+ ExpressionNode *expression;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FieldMemberExpression)
+
+ FieldMemberExpression(ExpressionNode *b, NameId *n):
+ base (b), name (n)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+ // attributes
+ ExpressionNode *base;
+ NameId *name;
+ SourceLocation dotToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NewMemberExpression)
+
+ NewMemberExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+ // attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation newToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NewExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NewExpression)
+
+ NewExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation newToken;
+};
+
+class QML_PARSER_EXPORT CallExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(CallExpression)
+
+ CallExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ArgumentList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ArgumentList)
+
+ ArgumentList(ExpressionNode *e):
+ expression (e), next (this)
+ { kind = K; }
+
+ ArgumentList(ArgumentList *previous, ExpressionNode *e):
+ expression (e)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline ArgumentList *finish ()
+ {
+ ArgumentList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ ExpressionNode *expression;
+ ArgumentList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PostIncrementExpression)
+
+ PostIncrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return incrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PostDecrementExpression)
+
+ PostDecrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return decrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(DeleteExpression)
+
+ DeleteExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return deleteToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation deleteToken;
+};
+
+class QML_PARSER_EXPORT VoidExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(VoidExpression)
+
+ VoidExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return voidToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation voidToken;
+};
+
+class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(TypeOfExpression)
+
+ TypeOfExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return typeofToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation typeofToken;
+};
+
+class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PreIncrementExpression)
+
+ PreIncrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return incrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(PreDecrementExpression)
+
+ PreDecrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return decrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UnaryPlusExpression)
+
+ UnaryPlusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return plusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation plusToken;
+};
+
+class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UnaryMinusExpression)
+
+ UnaryMinusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return minusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation minusToken;
+};
+
+class QML_PARSER_EXPORT TildeExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(TildeExpression)
+
+ TildeExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tildeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation tildeToken;
+};
+
+class QML_PARSER_EXPORT NotExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(NotExpression)
+
+ NotExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return notToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation notToken;
+};
+
+class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(BinaryExpression)
+
+ BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r):
+ left (l), op (o), right (r)
+ { kind = K; }
+
+ virtual BinaryExpression *binaryExpressionCast();
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ int op;
+ ExpressionNode *right;
+ SourceLocation operatorToken;
+};
+
+class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ConditionalExpression)
+
+ ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return ko->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ ExpressionNode *ok;
+ ExpressionNode *ko;
+ SourceLocation questionToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Expression)
+
+ Expression(ExpressionNode *l, ExpressionNode *r):
+ left (l), right (r) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ ExpressionNode *right;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Block: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Block)
+
+ Block(StatementList *slist):
+ statements (slist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+ // attributes
+ StatementList *statements;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT StatementList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(StatementList)
+
+ StatementList(Statement *stmt):
+ statement (stmt), next (this)
+ { kind = K; }
+
+ StatementList(StatementList *previous, Statement *stmt):
+ statement (stmt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline StatementList *finish ()
+ {
+ StatementList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Statement *statement;
+ StatementList *next;
+};
+
+class QML_PARSER_EXPORT VariableStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(VariableStatement)
+
+ VariableStatement(VariableDeclarationList *vlist):
+ declarations (vlist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declarationKindToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ VariableDeclarationList *declarations;
+ SourceLocation declarationKindToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclaration: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(VariableDeclaration)
+
+ VariableDeclaration(NameId *n, ExpressionNode *e):
+ name (n), expression (e), readOnly(false)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ ExpressionNode *expression;
+ bool readOnly;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclarationList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(VariableDeclarationList)
+
+ VariableDeclarationList(VariableDeclaration *decl):
+ declaration (decl), next (this)
+ { kind = K; }
+
+ VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl):
+ declaration (decl)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline VariableDeclarationList *finish (bool readOnly)
+ {
+ VariableDeclarationList *front = next;
+ next = 0;
+ if (readOnly) {
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next)
+ vdl->declaration->readOnly = true;
+ }
+ return front;
+ }
+
+// attributes
+ VariableDeclaration *declaration;
+ VariableDeclarationList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT EmptyStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(EmptyStatement)
+
+ EmptyStatement() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return semicolonToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ExpressionStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ExpressionStatement)
+
+ ExpressionStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT IfStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(IfStatement)
+
+ IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return ifToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (ko)
+ return ko->lastSourceLocation();
+
+ return ok->lastSourceLocation();
+ }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *ok;
+ Statement *ko;
+ SourceLocation ifToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation elseToken;
+};
+
+class QML_PARSER_EXPORT DoWhileStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(DoWhileStatement)
+
+ DoWhileStatement(Statement *stmt, ExpressionNode *e):
+ statement (stmt), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return doToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ Statement *statement;
+ ExpressionNode *expression;
+ SourceLocation doToken;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WhileStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(WhileStatement)
+
+ WhileStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return whileToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ForStatement)
+
+ ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ initialiser (i), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(LocalForStatement)
+
+ LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ declarations (vlist), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclarationList *declarations;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForEachStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ForEachStatement)
+
+ ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt):
+ initialiser (i), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForEachStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(LocalForEachStatement)
+
+ LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt):
+ declaration (v), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclaration *declaration;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ContinueStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ContinueStatement)
+
+ ContinueStatement(NameId *l = 0):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return continueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ NameId *label;
+ SourceLocation continueToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT BreakStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(BreakStatement)
+
+ BreakStatement(NameId *l = 0):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return breakToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ NameId *label;
+ SourceLocation breakToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ReturnStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ReturnStatement)
+
+ ReturnStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return returnToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation returnToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WithStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(WithStatement)
+
+ WithStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return withToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation withToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseBlock: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(CaseBlock)
+
+ CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0):
+ clauses (c), defaultClause (d), moreClauses (r)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ CaseClauses *clauses;
+ DefaultClause *defaultClause;
+ CaseClauses *moreClauses;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT SwitchStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(SwitchStatement)
+
+ SwitchStatement(ExpressionNode *e, CaseBlock *b):
+ expression (e), block (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return switchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return block->rbraceToken; }
+
+// attributes
+ ExpressionNode *expression;
+ CaseBlock *block;
+ SourceLocation switchToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseClauses: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(CaseClauses)
+
+ CaseClauses(CaseClause *c):
+ clause (c), next (this)
+ { kind = K; }
+
+ CaseClauses(CaseClauses *previous, CaseClause *c):
+ clause (c)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline CaseClauses *finish ()
+ {
+ CaseClauses *front = next;
+ next = 0;
+ return front;
+ }
+
+//attributes
+ CaseClause *clause;
+ CaseClauses *next;
+};
+
+class QML_PARSER_EXPORT CaseClause: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(CaseClause)
+
+ CaseClause(ExpressionNode *e, StatementList *slist):
+ expression (e), statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ ExpressionNode *expression;
+ StatementList *statements;
+ SourceLocation caseToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT DefaultClause: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(DefaultClause)
+
+ DefaultClause(StatementList *slist):
+ statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ StatementList *statements;
+ SourceLocation defaultToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT LabelledStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(LabelledStatement)
+
+ LabelledStatement(NameId *l, Statement *stmt):
+ label (l), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ NameId *label;
+ Statement *statement;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT ThrowStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(ThrowStatement)
+
+ ThrowStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return throwToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation throwToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT Catch: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Catch)
+
+ Catch(NameId *n, Block *stmt):
+ name (n), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *name;
+ Block *statement;
+ SourceLocation catchToken;
+ SourceLocation lparenToken;
+ SourceLocation identifierToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT Finally: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Finally)
+
+ Finally(Block *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Block *statement;
+ SourceLocation finallyToken;
+};
+
+class QML_PARSER_EXPORT TryStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(TryStatement)
+
+ TryStatement(Statement *stmt, Catch *c, Finally *f):
+ statement (stmt), catchExpression (c), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Finally *f):
+ statement (stmt), catchExpression (0), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Catch *c):
+ statement (stmt), catchExpression (c), finallyExpression (0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tryToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (finallyExpression)
+ return finallyExpression->statement->rbraceToken;
+ else if (catchExpression)
+ return catchExpression->statement->rbraceToken;
+
+ return statement->lastSourceLocation();
+ }
+
+// attributes
+ Statement *statement;
+ Catch *catchExpression;
+ Finally *finallyExpression;
+ SourceLocation tryToken;
+};
+
+class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FunctionExpression)
+
+ FunctionExpression(NameId *n, FormalParameterList *f, FunctionBody *b):
+ name (n), formals (f), body (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return functionToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ NameId *name;
+ FormalParameterList *formals;
+ FunctionBody *body;
+ SourceLocation functionToken;
+ SourceLocation identifierToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FunctionDeclaration)
+
+ FunctionDeclaration(NameId *n, FormalParameterList *f, FunctionBody *b):
+ FunctionExpression(n, f, b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+};
+
+class QML_PARSER_EXPORT FormalParameterList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FormalParameterList)
+
+ FormalParameterList(NameId *n):
+ name (n), next (this)
+ { kind = K; }
+
+ FormalParameterList(FormalParameterList *previous, NameId *n):
+ name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline FormalParameterList *finish ()
+ {
+ FormalParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ NameId *name;
+ FormalParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT FunctionBody: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FunctionBody)
+
+ FunctionBody(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT Program: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(Program)
+
+ Program(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT SourceElements: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(SourceElements)
+
+ SourceElements(SourceElement *elt):
+ element (elt), next (this)
+ { kind = K; }
+
+ SourceElements(SourceElements *previous, SourceElement *elt):
+ element (elt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ inline SourceElements *finish ()
+ {
+ SourceElements *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ SourceElement *element;
+ SourceElements *next;
+};
+
+class QML_PARSER_EXPORT SourceElement: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(SourceElement)
+
+ inline SourceElement()
+ { kind = K; }
+};
+
+class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(FunctionSourceElement)
+
+ FunctionSourceElement(FunctionDeclaration *f):
+ declaration (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ FunctionDeclaration *declaration;
+};
+
+class QML_PARSER_EXPORT StatementSourceElement: public SourceElement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(StatementSourceElement)
+
+ StatementSourceElement(Statement *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Statement *statement;
+};
+
+class QML_PARSER_EXPORT DebuggerStatement: public Statement
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(DebuggerStatement)
+
+ DebuggerStatement()
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return debuggerToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation debuggerToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiProgram: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiProgram)
+
+ UiProgram(UiImportList *imports, UiObjectMemberList *members)
+ : imports(imports), members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiImportList *imports;
+ UiObjectMemberList *members;
+};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(NameId *name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, NameId *name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *next;
+ NameId *name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiImport: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiImport)
+
+ UiImport(NameId *fileName)
+ : fileName(fileName), importUri(0), importId(0)
+ { kind = K; }
+
+ UiImport(UiQualifiedId *uri)
+ : fileName(0), importUri(uri), importId(0)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return importToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ NameId *fileName;
+ UiQualifiedId *importUri;
+ NameId *importId;
+ SourceLocation importToken;
+ SourceLocation fileNameToken;
+ SourceLocation versionToken;
+ SourceLocation asToken;
+ SourceLocation importIdToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiImportList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiImportList)
+
+ UiImportList(UiImport *import)
+ : import(import),
+ next(this)
+ { kind = K; }
+
+ UiImportList(UiImportList *previous, UiImport *import)
+ : import(import)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (import) return import->firstSourceLocation();
+ else return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ for (const UiImportList *it = this; it; it = it->next)
+ if (!it->next && it->import)
+ return it->import->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+ UiImportList *finish()
+ {
+ UiImportList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiImport *import;
+ UiImportList *next;
+};
+
+class QML_PARSER_EXPORT UiObjectMember: public Node
+{
+public:
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+ virtual UiObjectMember *uiObjectMemberCast();
+};
+
+class QML_PARSER_EXPORT UiObjectMemberList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectMemberList)
+
+ UiObjectMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ UiObjectMemberList *finish()
+ {
+ UiObjectMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiObjectMemberList *next;
+ UiObjectMember *member;
+};
+
+class QML_PARSER_EXPORT UiArrayMemberList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiArrayMemberList)
+
+ UiArrayMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ UiArrayMemberList *finish()
+ {
+ UiArrayMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiArrayMemberList *next;
+ UiObjectMember *member;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT UiObjectInitializer: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectInitializer)
+
+ UiObjectInitializer(UiObjectMemberList *members)
+ : members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ SourceLocation lbraceToken;
+ UiObjectMemberList *members;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT UiParameterList: public Node
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiParameterList)
+
+ UiParameterList(NameId *t, NameId *n):
+ type (t), name (n), next (this)
+ { kind = K; }
+
+ UiParameterList(UiParameterList *previous, NameId *t, NameId *n):
+ type (t), name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *) {}
+
+ inline UiParameterList *finish ()
+ {
+ UiParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ NameId *type;
+ NameId *name;
+ UiParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiPublicMember)
+
+ UiPublicMember(NameId *memberType,
+ NameId *name)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), expression(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ UiPublicMember(NameId *memberType,
+ NameId *name,
+ ExpressionNode *expression)
+ : type(Property), typeModifier(0), memberType(memberType), name(name), expression(expression), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (defaultToken.isValid())
+ return defaultToken;
+ else if (readonlyToken.isValid())
+ return readonlyToken;
+
+ return propertyToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (binding)
+ return binding->lastSourceLocation();
+
+ return semicolonToken;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ enum { Signal, Property } type;
+ NameId *typeModifier;
+ NameId *memberType;
+ NameId *name;
+ ExpressionNode *expression; // initialized with a JS expression
+ UiObjectMember *binding; // initialized with a QML object or array.
+ bool isDefaultMember;
+ bool isReadonlyMember;
+ UiParameterList *parameters;
+ SourceLocation defaultToken;
+ SourceLocation readonlyToken;
+ SourceLocation propertyToken;
+ SourceLocation typeModifierToken;
+ SourceLocation typeToken;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectDefinition)
+
+ UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedTypeNameId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+};
+
+class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiSourceElement)
+
+ UiSourceElement(Node *sourceElement)
+ : sourceElement(sourceElement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->firstSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->firstSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->lastSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ Node *sourceElement;
+};
+
+class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectBinding)
+
+ UiObjectBinding(UiQualifiedId *qualifiedId,
+ UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedId(qualifiedId),
+ qualifiedTypeNameId(qualifiedTypeNameId),
+ initializer(initializer),
+ hasOnToken(false)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (hasOnToken && qualifiedTypeNameId)
+ return qualifiedTypeNameId->identifierToken;
+
+ return qualifiedId->identifierToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+ SourceLocation colonToken;
+ bool hasOnToken;
+};
+
+class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiScriptBinding)
+
+ UiScriptBinding(UiQualifiedId *qualifiedId,
+ Statement *statement)
+ : qualifiedId(qualifiedId),
+ statement(statement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ Statement *statement;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember
+{
+public:
+ QDECLARATIVEJS_DECLARE_AST_NODE(UiArrayBinding)
+
+ UiArrayBinding(UiQualifiedId *qualifiedId,
+ UiArrayMemberList *members)
+ : qualifiedId(qualifiedId),
+ members(members)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiArrayMemberList *members;
+ SourceLocation colonToken;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+} } // namespace AST
+
+
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/parser/qdeclarativejsastfwd_p.h b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h
new file mode 100644
index 0000000000..8a20ab25c4
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSAST_FWD_P_H
+#define QDECLARATIVEJSAST_FWD_P_H
+
+#include "private/qdeclarativejsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS { namespace AST {
+
+class SourceLocation
+{
+public:
+ SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return length != 0; }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+};
+
+class Visitor;
+class Node;
+class ExpressionNode;
+class Statement;
+class ThisExpression;
+class IdentifierExpression;
+class NullExpression;
+class TrueLiteral;
+class FalseLiteral;
+class NumericLiteral;
+class StringLiteral;
+class RegExpLiteral;
+class ArrayLiteral;
+class ObjectLiteral;
+class ElementList;
+class Elision;
+class PropertyNameAndValueList;
+class PropertyName;
+class IdentifierPropertyName;
+class StringLiteralPropertyName;
+class NumericLiteralPropertyName;
+class ArrayMemberExpression;
+class FieldMemberExpression;
+class NewMemberExpression;
+class NewExpression;
+class CallExpression;
+class ArgumentList;
+class PostIncrementExpression;
+class PostDecrementExpression;
+class DeleteExpression;
+class VoidExpression;
+class TypeOfExpression;
+class PreIncrementExpression;
+class PreDecrementExpression;
+class UnaryPlusExpression;
+class UnaryMinusExpression;
+class TildeExpression;
+class NotExpression;
+class BinaryExpression;
+class ConditionalExpression;
+class Expression; // ### rename
+class Block;
+class StatementList;
+class VariableStatement;
+class VariableDeclarationList;
+class VariableDeclaration;
+class EmptyStatement;
+class ExpressionStatement;
+class IfStatement;
+class DoWhileStatement;
+class WhileStatement;
+class ForStatement;
+class LocalForStatement;
+class ForEachStatement;
+class LocalForEachStatement;
+class ContinueStatement;
+class BreakStatement;
+class ReturnStatement;
+class WithStatement;
+class SwitchStatement;
+class CaseBlock;
+class CaseClauses;
+class CaseClause;
+class DefaultClause;
+class LabelledStatement;
+class ThrowStatement;
+class TryStatement;
+class Catch;
+class Finally;
+class FunctionDeclaration;
+class FunctionExpression;
+class FormalParameterList;
+class FunctionBody;
+class Program;
+class SourceElements;
+class SourceElement;
+class FunctionSourceElement;
+class StatementSourceElement;
+class DebuggerStatement;
+class NestedExpression;
+
+// ui elements
+class UiProgram;
+class UiImportList;
+class UiImport;
+class UiPublicMember;
+class UiObjectDefinition;
+class UiObjectInitializer;
+class UiObjectBinding;
+class UiScriptBinding;
+class UiSourceElement;
+class UiArrayBinding;
+class UiObjectMember;
+class UiObjectMemberList;
+class UiArrayMemberList;
+class UiQualifiedId;
+class UiFormalList;
+class UiFormal;
+class UiSignature;
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp
new file mode 100644
index 0000000000..8df755a062
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativejsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS { namespace AST {
+
+Visitor::Visitor()
+{
+}
+
+Visitor::~Visitor()
+{
+}
+
+} } // namespace QDeclarativeJS::AST
+
+QT_QML_END_NAMESPACE
diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h
new file mode 100644
index 0000000000..519b8c8880
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSASTVISITOR_P_H
+#define QDECLARATIVEJSASTVISITOR_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/qdeclarativejsastfwd_p.h"
+#include "private/qdeclarativejsglobal_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS { namespace AST {
+
+class QML_PARSER_EXPORT Visitor
+{
+public:
+ Visitor();
+ virtual ~Visitor();
+
+ virtual bool preVisit(Node *) { return true; }
+ virtual void postVisit(Node *) {}
+
+ // Ui
+ virtual bool visit(UiProgram *) { return true; }
+ virtual bool visit(UiImportList *) { return true; }
+ virtual bool visit(UiImport *) { return true; }
+ virtual bool visit(UiPublicMember *) { return true; }
+ virtual bool visit(UiSourceElement *) { return true; }
+ virtual bool visit(UiObjectDefinition *) { return true; }
+ virtual bool visit(UiObjectInitializer *) { return true; }
+ virtual bool visit(UiObjectBinding *) { return true; }
+ virtual bool visit(UiScriptBinding *) { return true; }
+ virtual bool visit(UiArrayBinding *) { return true; }
+ virtual bool visit(UiObjectMemberList *) { return true; }
+ virtual bool visit(UiArrayMemberList *) { return true; }
+ virtual bool visit(UiQualifiedId *) { return true; }
+ virtual bool visit(UiSignature *) { return true; }
+ virtual bool visit(UiFormalList *) { return true; }
+ virtual bool visit(UiFormal *) { return true; }
+
+ virtual void endVisit(UiProgram *) {}
+ virtual void endVisit(UiImportList *) {}
+ virtual void endVisit(UiImport *) {}
+ virtual void endVisit(UiPublicMember *) {}
+ virtual void endVisit(UiSourceElement *) {}
+ virtual void endVisit(UiObjectDefinition *) {}
+ virtual void endVisit(UiObjectInitializer *) {}
+ virtual void endVisit(UiObjectBinding *) {}
+ virtual void endVisit(UiScriptBinding *) {}
+ virtual void endVisit(UiArrayBinding *) {}
+ virtual void endVisit(UiObjectMemberList *) {}
+ virtual void endVisit(UiArrayMemberList *) {}
+ virtual void endVisit(UiQualifiedId *) {}
+ virtual void endVisit(UiSignature *) {}
+ virtual void endVisit(UiFormalList *) {}
+ virtual void endVisit(UiFormal *) {}
+
+ // QDeclarativeJS
+ virtual bool visit(ThisExpression *) { return true; }
+ virtual void endVisit(ThisExpression *) {}
+
+ virtual bool visit(IdentifierExpression *) { return true; }
+ virtual void endVisit(IdentifierExpression *) {}
+
+ virtual bool visit(NullExpression *) { return true; }
+ virtual void endVisit(NullExpression *) {}
+
+ virtual bool visit(TrueLiteral *) { return true; }
+ virtual void endVisit(TrueLiteral *) {}
+
+ virtual bool visit(FalseLiteral *) { return true; }
+ virtual void endVisit(FalseLiteral *) {}
+
+ virtual bool visit(StringLiteral *) { return true; }
+ virtual void endVisit(StringLiteral *) {}
+
+ virtual bool visit(NumericLiteral *) { return true; }
+ virtual void endVisit(NumericLiteral *) {}
+
+ virtual bool visit(RegExpLiteral *) { return true; }
+ virtual void endVisit(RegExpLiteral *) {}
+
+ virtual bool visit(ArrayLiteral *) { return true; }
+ virtual void endVisit(ArrayLiteral *) {}
+
+ virtual bool visit(ObjectLiteral *) { return true; }
+ virtual void endVisit(ObjectLiteral *) {}
+
+ virtual bool visit(ElementList *) { return true; }
+ virtual void endVisit(ElementList *) {}
+
+ virtual bool visit(Elision *) { return true; }
+ virtual void endVisit(Elision *) {}
+
+ virtual bool visit(PropertyNameAndValueList *) { return true; }
+ virtual void endVisit(PropertyNameAndValueList *) {}
+
+ virtual bool visit(NestedExpression *) { return true; }
+ virtual void endVisit(NestedExpression *) {}
+
+ virtual bool visit(IdentifierPropertyName *) { return true; }
+ virtual void endVisit(IdentifierPropertyName *) {}
+
+ virtual bool visit(StringLiteralPropertyName *) { return true; }
+ virtual void endVisit(StringLiteralPropertyName *) {}
+
+ virtual bool visit(NumericLiteralPropertyName *) { return true; }
+ virtual void endVisit(NumericLiteralPropertyName *) {}
+
+ virtual bool visit(ArrayMemberExpression *) { return true; }
+ virtual void endVisit(ArrayMemberExpression *) {}
+
+ virtual bool visit(FieldMemberExpression *) { return true; }
+ virtual void endVisit(FieldMemberExpression *) {}
+
+ virtual bool visit(NewMemberExpression *) { return true; }
+ virtual void endVisit(NewMemberExpression *) {}
+
+ virtual bool visit(NewExpression *) { return true; }
+ virtual void endVisit(NewExpression *) {}
+
+ virtual bool visit(CallExpression *) { return true; }
+ virtual void endVisit(CallExpression *) {}
+
+ virtual bool visit(ArgumentList *) { return true; }
+ virtual void endVisit(ArgumentList *) {}
+
+ virtual bool visit(PostIncrementExpression *) { return true; }
+ virtual void endVisit(PostIncrementExpression *) {}
+
+ virtual bool visit(PostDecrementExpression *) { return true; }
+ virtual void endVisit(PostDecrementExpression *) {}
+
+ virtual bool visit(DeleteExpression *) { return true; }
+ virtual void endVisit(DeleteExpression *) {}
+
+ virtual bool visit(VoidExpression *) { return true; }
+ virtual void endVisit(VoidExpression *) {}
+
+ virtual bool visit(TypeOfExpression *) { return true; }
+ virtual void endVisit(TypeOfExpression *) {}
+
+ virtual bool visit(PreIncrementExpression *) { return true; }
+ virtual void endVisit(PreIncrementExpression *) {}
+
+ virtual bool visit(PreDecrementExpression *) { return true; }
+ virtual void endVisit(PreDecrementExpression *) {}
+
+ virtual bool visit(UnaryPlusExpression *) { return true; }
+ virtual void endVisit(UnaryPlusExpression *) {}
+
+ virtual bool visit(UnaryMinusExpression *) { return true; }
+ virtual void endVisit(UnaryMinusExpression *) {}
+
+ virtual bool visit(TildeExpression *) { return true; }
+ virtual void endVisit(TildeExpression *) {}
+
+ virtual bool visit(NotExpression *) { return true; }
+ virtual void endVisit(NotExpression *) {}
+
+ virtual bool visit(BinaryExpression *) { return true; }
+ virtual void endVisit(BinaryExpression *) {}
+
+ virtual bool visit(ConditionalExpression *) { return true; }
+ virtual void endVisit(ConditionalExpression *) {}
+
+ virtual bool visit(Expression *) { return true; }
+ virtual void endVisit(Expression *) {}
+
+ virtual bool visit(Block *) { return true; }
+ virtual void endVisit(Block *) {}
+
+ virtual bool visit(StatementList *) { return true; }
+ virtual void endVisit(StatementList *) {}
+
+ virtual bool visit(VariableStatement *) { return true; }
+ virtual void endVisit(VariableStatement *) {}
+
+ virtual bool visit(VariableDeclarationList *) { return true; }
+ virtual void endVisit(VariableDeclarationList *) {}
+
+ virtual bool visit(VariableDeclaration *) { return true; }
+ virtual void endVisit(VariableDeclaration *) {}
+
+ virtual bool visit(EmptyStatement *) { return true; }
+ virtual void endVisit(EmptyStatement *) {}
+
+ virtual bool visit(ExpressionStatement *) { return true; }
+ virtual void endVisit(ExpressionStatement *) {}
+
+ virtual bool visit(IfStatement *) { return true; }
+ virtual void endVisit(IfStatement *) {}
+
+ virtual bool visit(DoWhileStatement *) { return true; }
+ virtual void endVisit(DoWhileStatement *) {}
+
+ virtual bool visit(WhileStatement *) { return true; }
+ virtual void endVisit(WhileStatement *) {}
+
+ virtual bool visit(ForStatement *) { return true; }
+ virtual void endVisit(ForStatement *) {}
+
+ virtual bool visit(LocalForStatement *) { return true; }
+ virtual void endVisit(LocalForStatement *) {}
+
+ virtual bool visit(ForEachStatement *) { return true; }
+ virtual void endVisit(ForEachStatement *) {}
+
+ virtual bool visit(LocalForEachStatement *) { return true; }
+ virtual void endVisit(LocalForEachStatement *) {}
+
+ virtual bool visit(ContinueStatement *) { return true; }
+ virtual void endVisit(ContinueStatement *) {}
+
+ virtual bool visit(BreakStatement *) { return true; }
+ virtual void endVisit(BreakStatement *) {}
+
+ virtual bool visit(ReturnStatement *) { return true; }
+ virtual void endVisit(ReturnStatement *) {}
+
+ virtual bool visit(WithStatement *) { return true; }
+ virtual void endVisit(WithStatement *) {}
+
+ virtual bool visit(SwitchStatement *) { return true; }
+ virtual void endVisit(SwitchStatement *) {}
+
+ virtual bool visit(CaseBlock *) { return true; }
+ virtual void endVisit(CaseBlock *) {}
+
+ virtual bool visit(CaseClauses *) { return true; }
+ virtual void endVisit(CaseClauses *) {}
+
+ virtual bool visit(CaseClause *) { return true; }
+ virtual void endVisit(CaseClause *) {}
+
+ virtual bool visit(DefaultClause *) { return true; }
+ virtual void endVisit(DefaultClause *) {}
+
+ virtual bool visit(LabelledStatement *) { return true; }
+ virtual void endVisit(LabelledStatement *) {}
+
+ virtual bool visit(ThrowStatement *) { return true; }
+ virtual void endVisit(ThrowStatement *) {}
+
+ virtual bool visit(TryStatement *) { return true; }
+ virtual void endVisit(TryStatement *) {}
+
+ virtual bool visit(Catch *) { return true; }
+ virtual void endVisit(Catch *) {}
+
+ virtual bool visit(Finally *) { return true; }
+ virtual void endVisit(Finally *) {}
+
+ virtual bool visit(FunctionDeclaration *) { return true; }
+ virtual void endVisit(FunctionDeclaration *) {}
+
+ virtual bool visit(FunctionExpression *) { return true; }
+ virtual void endVisit(FunctionExpression *) {}
+
+ virtual bool visit(FormalParameterList *) { return true; }
+ virtual void endVisit(FormalParameterList *) {}
+
+ virtual bool visit(FunctionBody *) { return true; }
+ virtual void endVisit(FunctionBody *) {}
+
+ virtual bool visit(Program *) { return true; }
+ virtual void endVisit(Program *) {}
+
+ virtual bool visit(SourceElements *) { return true; }
+ virtual void endVisit(SourceElements *) {}
+
+ virtual bool visit(FunctionSourceElement *) { return true; }
+ virtual void endVisit(FunctionSourceElement *) {}
+
+ virtual bool visit(StatementSourceElement *) { return true; }
+ virtual void endVisit(StatementSourceElement *) {}
+
+ virtual bool visit(DebuggerStatement *) { return true; }
+ virtual void endVisit(DebuggerStatement *) {}
+};
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif // QDECLARATIVEJSASTVISITOR_P_H
diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.cpp b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp
new file mode 100644
index 0000000000..ec9271a0de
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativejsengine_p.h"
+
+#include "private/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsnodepool_p.h"
+
+#include <qnumeric.h>
+#include <QHash>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+uint qHash(const QDeclarativeJS::NameId &id)
+{ return qHash(id.asString()); }
+
+QString numberToString(double value)
+{ return QString::number(value); }
+
+int Ecma::RegExp::flagFromChar(const QChar &ch)
+{
+ static QHash<QChar, int> flagsHash;
+ if (flagsHash.isEmpty()) {
+ flagsHash[QLatin1Char('g')] = Global;
+ flagsHash[QLatin1Char('i')] = IgnoreCase;
+ flagsHash[QLatin1Char('m')] = Multiline;
+ }
+ QHash<QChar, int>::const_iterator it;
+ it = flagsHash.constFind(ch);
+ if (it == flagsHash.constEnd())
+ return 0;
+ return it.value();
+}
+
+QString Ecma::RegExp::flagsToString(int flags)
+{
+ QString result;
+ if (flags & Global)
+ result += QLatin1Char('g');
+ if (flags & IgnoreCase)
+ result += QLatin1Char('i');
+ if (flags & Multiline)
+ result += QLatin1Char('m');
+ return result;
+}
+
+NodePool::NodePool(const QString &fileName, Engine *engine)
+ : m_fileName(fileName), m_engine(engine)
+{
+ m_engine->setNodePool(this);
+}
+
+NodePool::~NodePool()
+{
+}
+
+Code *NodePool::createCompiledCode(AST::Node *, CompilationUnit &)
+{
+ Q_ASSERT(0);
+ return 0;
+}
+
+static int toDigit(char c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ return 10 + c - 'a';
+ else if ((c >= 'A') && (c <= 'Z'))
+ return 10 + c - 'A';
+ return -1;
+}
+
+double integerFromString(const char *buf, int size, int radix)
+{
+ if (size == 0)
+ return qSNaN();
+
+ double sign = 1.0;
+ int i = 0;
+ if (buf[0] == '+') {
+ ++i;
+ } else if (buf[0] == '-') {
+ sign = -1.0;
+ ++i;
+ }
+
+ if (((size-i) >= 2) && (buf[i] == '0')) {
+ if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
+ && (radix < 34)) {
+ if ((radix != 0) && (radix != 16))
+ return 0;
+ radix = 16;
+ i += 2;
+ } else {
+ if (radix == 0) {
+ radix = 8;
+ ++i;
+ }
+ }
+ } else if (radix == 0) {
+ radix = 10;
+ }
+
+ int j = i;
+ for ( ; i < size; ++i) {
+ int d = toDigit(buf[i]);
+ if ((d == -1) || (d >= radix))
+ break;
+ }
+ double result;
+ if (j == i) {
+ if (!qstrcmp(buf, "Infinity"))
+ result = qInf();
+ else
+ result = qSNaN();
+ } else {
+ result = 0;
+ double multiplier = 1;
+ for (--i ; i >= j; --i, multiplier *= radix)
+ result += toDigit(buf[i]) * multiplier;
+ }
+ result *= sign;
+ return result;
+}
+
+double integerFromString(const QString &str, int radix)
+{
+ QByteArray ba = str.trimmed().toLatin1();
+ return integerFromString(ba.constData(), ba.size(), radix);
+}
+
+
+Engine::Engine()
+ : _lexer(0), _nodePool(0)
+{ }
+
+Engine::~Engine()
+{ }
+
+QSet<NameId> Engine::literals() const
+{ return _literals; }
+
+void Engine::addComment(int pos, int len, int line, int col)
+{ if (len > 0) _comments.append(QDeclarativeJS::AST::SourceLocation(pos, len, line, col)); }
+
+QList<QDeclarativeJS::AST::SourceLocation> Engine::comments() const
+{ return _comments; }
+
+NameId *Engine::intern(const QChar *u, int s)
+{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); }
+
+QString Engine::toString(NameId *id)
+{ return id->asString(); }
+
+Lexer *Engine::lexer() const
+{ return _lexer; }
+
+void Engine::setLexer(Lexer *lexer)
+{ _lexer = lexer; }
+
+NodePool *Engine::nodePool() const
+{ return _nodePool; }
+
+void Engine::setNodePool(NodePool *nodePool)
+{ _nodePool = nodePool; }
+
+
+
+} // end of namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.h b/src/declarative/qml/parser/qdeclarativejsengine_p.h
new file mode 100644
index 0000000000..cacc9612fa
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsengine_p.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSENGINE_P_H
+#define QDECLARATIVEJSENGINE_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/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsastfwd_p.h"
+
+#include <QString>
+#include <QSet>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+class QML_PARSER_EXPORT NameId
+{
+ QString _text;
+
+public:
+ NameId(const QChar *u, int s)
+ : _text(u, s)
+ { }
+
+ const QString asString() const
+ { return _text; }
+
+ bool operator == (const NameId &other) const
+ { return _text == other._text; }
+
+ bool operator != (const NameId &other) const
+ { return _text != other._text; }
+
+ bool operator < (const NameId &other) const
+ { return _text < other._text; }
+};
+
+uint qHash(const QDeclarativeJS::NameId &id);
+
+} // end of namespace QDeclarativeJS
+
+namespace QDeclarativeJS {
+
+class Lexer;
+class NodePool;
+
+namespace Ecma {
+
+class QML_PARSER_EXPORT RegExp
+{
+public:
+ enum RegExpFlag {
+ Global = 0x01,
+ IgnoreCase = 0x02,
+ Multiline = 0x04
+ };
+
+public:
+ static int flagFromChar(const QChar &);
+ static QString flagsToString(int flags);
+};
+
+} // end of namespace Ecma
+
+class QML_PARSER_EXPORT DiagnosticMessage
+{
+public:
+ enum Kind { Warning, Error };
+
+ DiagnosticMessage()
+ : kind(Error) {}
+
+ DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
+ : kind(kind), loc(loc), message(message) {}
+
+ bool isWarning() const
+ { return kind == Warning; }
+
+ bool isError() const
+ { return kind == Error; }
+
+ Kind kind;
+ AST::SourceLocation loc;
+ QString message;
+};
+
+class QML_PARSER_EXPORT Engine
+{
+ Lexer *_lexer;
+ NodePool *_nodePool;
+ QSet<NameId> _literals;
+ QList<QDeclarativeJS::AST::SourceLocation> _comments;
+
+public:
+ Engine();
+ ~Engine();
+
+ QSet<NameId> literals() const;
+
+ void addComment(int pos, int len, int line, int col);
+ QList<QDeclarativeJS::AST::SourceLocation> comments() const;
+
+ NameId *intern(const QChar *u, int s);
+
+ static QString toString(NameId *id);
+
+ Lexer *lexer() const;
+ void setLexer(Lexer *lexer);
+
+ NodePool *nodePool() const;
+ void setNodePool(NodePool *nodePool);
+};
+
+} // end of namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
+
+#endif // QDECLARATIVEJSENGINE_P_H
diff --git a/src/declarative/qml/parser/qdeclarativejsglobal_p.h b/src/declarative/qml/parser/qdeclarativejsglobal_p.h
new file mode 100644
index 0000000000..776937cfdf
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsglobal_p.h
@@ -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 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 QDECLARATIVEJSGLOBAL_P_H
+#define QDECLARATIVEJSGLOBAL_P_H
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE
+
+# ifdef QDECLARATIVEJS_BUILD_DIR
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# elif QML_BUILD_STATIC_LIB
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif // QDECLARATIVEJS_BUILD_DIR
+
+#else // !QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
+# define QML_PARSER_EXPORT
+#endif // QT_CREATOR
+
+#endif // QDECLARATIVEJSGLOBAL_P_H
diff --git a/src/declarative/qml/parser/qdeclarativejsgrammar.cpp b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp
new file mode 100644
index 0000000000..ea19e1ccd5
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp
@@ -0,0 +1,989 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt 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 was generated by qlalr - DO NOT EDIT!
+#include "qdeclarativejsgrammar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+const char *const QDeclarativeJSGrammar::spell [] = {
+ "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue",
+ "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
+ "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
+ "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
+ "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
+ "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
+ ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
+ "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
+ "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public",
+ "import", "as", "on", 0, 0, 0, 0, 0, 0, 0,
+ 0};
+
+const short QDeclarativeJSGrammar::lhs [] = {
+ 101, 101, 101, 101, 101, 101, 102, 108, 108, 111,
+ 111, 113, 112, 112, 112, 112, 112, 112, 112, 112,
+ 115, 110, 109, 118, 118, 119, 119, 120, 120, 117,
+ 106, 106, 106, 106, 106, 106, 106, 106, 126, 126,
+ 126, 127, 127, 128, 128, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 116, 116, 116, 116, 116,
+ 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+ 131, 131, 131, 131, 131, 131, 131, 131, 121, 133,
+ 133, 133, 133, 132, 132, 135, 135, 137, 137, 137,
+ 137, 137, 137, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 139, 139, 114, 114, 114, 114,
+ 114, 142, 142, 143, 143, 143, 143, 141, 141, 144,
+ 144, 145, 145, 146, 146, 146, 147, 147, 147, 147,
+ 147, 147, 147, 147, 147, 147, 148, 148, 148, 148,
+ 149, 149, 149, 150, 150, 150, 150, 151, 151, 151,
+ 151, 151, 151, 151, 152, 152, 152, 152, 152, 152,
+ 153, 153, 153, 153, 153, 154, 154, 154, 154, 154,
+ 155, 155, 156, 156, 157, 157, 158, 158, 159, 159,
+ 160, 160, 161, 161, 162, 162, 163, 163, 164, 164,
+ 165, 165, 166, 166, 136, 136, 167, 167, 168, 168,
+ 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
+ 104, 104, 169, 169, 170, 170, 171, 171, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 122, 183, 183, 182, 182, 130, 130,
+ 184, 184, 185, 185, 187, 187, 186, 188, 191, 189,
+ 189, 192, 190, 190, 123, 124, 124, 125, 125, 172,
+ 172, 172, 172, 172, 172, 172, 173, 173, 173, 173,
+ 174, 174, 174, 174, 175, 175, 176, 178, 193, 193,
+ 196, 196, 194, 194, 197, 195, 177, 177, 177, 179,
+ 179, 180, 180, 180, 198, 199, 181, 181, 129, 140,
+ 203, 203, 200, 200, 201, 201, 204, 107, 205, 205,
+ 105, 105, 202, 202, 134, 134, 206};
+
+const short QDeclarativeJSGrammar::rhs [] = {
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 1, 2, 2, 3, 3, 5, 5, 4, 4,
+ 2, 0, 1, 1, 2, 1, 3, 2, 3, 2,
+ 1, 5, 4, 4, 3, 3, 3, 3, 1, 1,
+ 1, 0, 1, 2, 4, 6, 6, 3, 3, 7,
+ 7, 4, 4, 5, 5, 6, 6, 7, 7, 7,
+ 7, 10, 6, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 3, 3, 4, 5, 3, 4, 3, 1, 1,
+ 2, 3, 4, 1, 2, 3, 5, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 4, 3,
+ 5, 1, 2, 4, 4, 4, 3, 0, 1, 1,
+ 3, 1, 1, 1, 2, 2, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 3, 3, 3,
+ 1, 3, 3, 1, 3, 3, 3, 1, 3, 3,
+ 3, 3, 3, 3, 1, 3, 3, 3, 3, 3,
+ 1, 3, 3, 3, 3, 1, 3, 3, 3, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+ 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+ 1, 5, 1, 5, 1, 3, 1, 3, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 0, 1, 1, 3, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 1, 2, 0, 1, 3, 3,
+ 1, 1, 1, 3, 1, 3, 2, 2, 2, 0,
+ 1, 2, 0, 1, 1, 2, 2, 7, 5, 7,
+ 7, 5, 9, 10, 7, 8, 2, 2, 3, 3,
+ 2, 2, 3, 3, 3, 3, 5, 5, 3, 5,
+ 1, 2, 0, 1, 4, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 5, 2, 2, 2, 8, 8,
+ 1, 3, 0, 1, 0, 1, 1, 1, 1, 2,
+ 1, 1, 0, 1, 0, 1, 2};
+
+const short QDeclarativeJSGrammar::action_default [] = {
+ 0, 0, 0, 0, 0, 0, 22, 0, 174, 241,
+ 205, 213, 209, 153, 225, 201, 3, 138, 72, 154,
+ 217, 221, 142, 171, 152, 157, 137, 191, 178, 0,
+ 79, 80, 75, 343, 66, 345, 0, 0, 0, 0,
+ 77, 0, 0, 73, 76, 70, 0, 0, 67, 69,
+ 68, 78, 71, 0, 74, 0, 0, 167, 0, 0,
+ 154, 173, 156, 155, 0, 0, 0, 169, 170, 168,
+ 172, 0, 202, 0, 0, 0, 0, 192, 0, 0,
+ 0, 0, 0, 0, 182, 0, 0, 0, 176, 177,
+ 175, 180, 184, 183, 181, 179, 194, 193, 195, 0,
+ 210, 0, 206, 0, 0, 148, 135, 147, 136, 104,
+ 105, 106, 131, 107, 132, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120, 133, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129, 130, 134,
+ 0, 0, 146, 242, 149, 0, 150, 0, 151, 145,
+ 0, 238, 231, 229, 236, 237, 235, 234, 240, 233,
+ 232, 230, 239, 226, 0, 214, 0, 0, 218, 0,
+ 0, 222, 0, 0, 148, 140, 0, 139, 0, 144,
+ 158, 0, 344, 333, 334, 0, 331, 0, 332, 0,
+ 335, 249, 256, 255, 263, 251, 0, 252, 336, 0,
+ 342, 253, 254, 259, 257, 339, 337, 341, 260, 0,
+ 271, 0, 0, 0, 0, 343, 66, 0, 345, 67,
+ 243, 285, 68, 0, 0, 0, 272, 0, 0, 261,
+ 262, 0, 250, 258, 286, 287, 330, 340, 0, 301,
+ 302, 303, 304, 0, 297, 298, 299, 300, 327, 328,
+ 0, 0, 0, 0, 0, 290, 291, 247, 245, 207,
+ 215, 211, 227, 203, 248, 0, 154, 219, 223, 196,
+ 185, 0, 0, 204, 0, 0, 0, 0, 197, 0,
+ 0, 0, 0, 0, 189, 187, 190, 188, 186, 199,
+ 198, 200, 0, 212, 0, 208, 0, 246, 154, 0,
+ 228, 243, 244, 0, 243, 0, 0, 293, 0, 0,
+ 0, 295, 0, 216, 0, 0, 220, 0, 0, 224,
+ 283, 0, 275, 284, 278, 0, 282, 0, 243, 276,
+ 0, 243, 0, 0, 294, 0, 0, 0, 296, 344,
+ 333, 0, 0, 335, 0, 329, 0, 319, 0, 0,
+ 0, 289, 0, 288, 0, 346, 0, 103, 265, 268,
+ 0, 104, 271, 107, 132, 109, 110, 75, 114, 115,
+ 66, 116, 119, 73, 76, 67, 243, 68, 78, 122,
+ 71, 124, 74, 126, 127, 272, 129, 130, 134, 0,
+ 96, 0, 0, 98, 102, 100, 87, 99, 101, 0,
+ 97, 86, 266, 264, 142, 143, 148, 0, 141, 0,
+ 318, 0, 305, 306, 0, 317, 0, 0, 0, 308,
+ 313, 311, 314, 0, 0, 312, 313, 0, 309, 0,
+ 310, 267, 316, 0, 267, 315, 0, 320, 321, 0,
+ 267, 322, 323, 0, 0, 324, 0, 0, 0, 325,
+ 326, 160, 159, 0, 0, 0, 292, 0, 0, 0,
+ 307, 280, 273, 0, 281, 277, 0, 279, 269, 0,
+ 270, 274, 90, 0, 0, 94, 81, 0, 83, 92,
+ 0, 84, 93, 95, 85, 91, 82, 0, 88, 164,
+ 162, 166, 163, 161, 165, 6, 338, 4, 2, 64,
+ 89, 0, 0, 67, 69, 68, 31, 5, 0, 65,
+ 0, 41, 40, 39, 0, 0, 54, 0, 55, 0,
+ 60, 61, 0, 41, 0, 0, 0, 0, 0, 50,
+ 0, 51, 0, 0, 26, 0, 0, 62, 27, 0,
+ 30, 28, 24, 0, 29, 25, 0, 52, 0, 53,
+ 0, 142, 0, 56, 57, 63, 0, 0, 0, 0,
+ 0, 58, 59, 0, 48, 42, 49, 43, 0, 0,
+ 0, 0, 45, 0, 46, 47, 44, 0, 0, 35,
+ 36, 37, 38, 142, 267, 0, 0, 104, 271, 107,
+ 132, 109, 110, 75, 114, 115, 66, 116, 119, 73,
+ 76, 67, 243, 68, 78, 122, 71, 124, 74, 126,
+ 127, 272, 129, 130, 134, 0, 32, 33, 0, 34,
+ 8, 0, 10, 0, 9, 0, 1, 21, 12, 0,
+ 13, 0, 14, 0, 19, 20, 0, 15, 16, 0,
+ 17, 18, 11, 23, 7, 347};
+
+const short QDeclarativeJSGrammar::goto_default [] = {
+ 7, 626, 207, 196, 205, 507, 495, 625, 644, 620,
+ 624, 622, 627, 22, 623, 18, 506, 543, 533, 540,
+ 535, 191, 195, 197, 201, 524, 568, 567, 200, 232,
+ 26, 474, 473, 356, 355, 9, 354, 357, 107, 17,
+ 145, 24, 13, 144, 19, 25, 57, 23, 8, 28,
+ 27, 269, 15, 263, 10, 259, 12, 261, 11, 260,
+ 20, 267, 21, 268, 14, 262, 258, 299, 411, 264,
+ 265, 202, 193, 192, 204, 233, 203, 208, 229, 230,
+ 194, 360, 359, 231, 463, 462, 321, 322, 465, 324,
+ 464, 323, 419, 423, 426, 422, 421, 441, 442, 185,
+ 199, 181, 184, 198, 206, 0};
+
+const short QDeclarativeJSGrammar::action_index [] = {
+ 421, 1288, 2322, 2322, 2419, 1016, -52, 37, 140, -101,
+ 35, -13, -40, 190, -101, 272, 34, -101, -101, 658,
+ 42, 103, 194, 201, -101, -101, -101, 439, 256, 1288,
+ -101, -101, -101, 282, -101, 2128, 1751, 1288, 1288, 1288,
+ -101, 917, 1288, -101, -101, -101, 1288, 1288, -101, -101,
+ -101, -101, -101, 1288, -101, 1288, 1288, -101, 1288, 1288,
+ 109, 245, -101, -101, 1288, 1288, 1288, -101, -101, -101,
+ 185, 1288, 295, 1288, 1288, 1288, 1288, 461, 1288, 1288,
+ 1288, 1288, 1288, 1288, 256, 1288, 1288, 1288, 155, 119,
+ 114, 176, 256, 332, 202, 332, 560, 560, 471, 1288,
+ -23, 1288, 53, 2031, 1288, 1288, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ 100, 1288, -101, -101, 70, 59, -101, 1288, -101, -101,
+ 1288, -101, -101, -101, -101, -101, -101, -101, -101, -101,
+ -101, -101, -101, -101, 1288, 41, 1288, 1288, 98, 91,
+ 1288, -101, 2031, 1288, 1288, -101, 121, -101, 73, -101,
+ -101, 39, -101, 385, 180, 78, -101, 391, -101, 64,
+ 2322, -101, -101, -101, -101, -101, 208, -101, -101, 82,
+ -101, -101, -101, -101, -101, -101, 2322, -101, -101, 538,
+ -101, 495, 128, 2419, 54, 358, 62, 44, 2613, 67,
+ 1288, -101, 76, 63, 1288, 58, -101, 60, 46, -101,
+ -101, 309, -101, -101, -101, -101, -101, -101, 86, -101,
+ -101, -101, -101, 107, -101, -101, -101, -101, -101, -101,
+ 28, 52, 1288, 101, 102, -101, -101, 1472, -101, 83,
+ 75, 79, -101, 287, 84, 80, 585, 69, 89, 321,
+ 177, 482, 1288, 297, 1288, 1288, 1288, 1288, 331, 1288,
+ 1288, 1288, 1288, 1288, 332, 222, 332, 332, 332, 410,
+ 410, 410, 1288, 57, 1288, 72, 1288, -101, 658, 1288,
+ -101, 1288, 71, 45, 1288, 61, 2419, -101, 1288, 132,
+ 2419, -101, 1288, 47, 1288, 1288, 66, 65, 1288, -101,
+ 68, 112, 81, -101, -101, 1288, -101, 369, 1288, -101,
+ 85, 1288, 74, 2419, -101, 1288, 122, 2419, -101, 77,
+ 294, 16, -29, 2322, -53, -101, 2419, -101, 1288, 127,
+ 2419, -15, 2419, -101, 10, 11, -34, -101, -101, 2419,
+ -48, 504, 4, 476, 113, 1288, 2419, 2, -28, 420,
+ 6, -21, 719, 7, 87, -101, 1382, -101, -4, -16,
+ 5, 1288, 3, -27, 1288, 9, 1288, -18, -31, 1288,
+ -101, 2225, -7, -101, -101, -101, -101, -101, -101, 1288,
+ -101, -101, -101, -101, 246, -101, 1288, -38, -101, 2419,
+ -101, 88, -101, -101, 2419, -101, 1288, 106, 26, -101,
+ 55, -101, 50, 105, 1288, -101, 48, 38, -101, -8,
+ -101, 2419, -101, 94, 2419, -101, 238, -101, -101, 104,
+ 2419, 31, -101, 21, 19, -101, 305, 1, 30, -101,
+ -101, -101, -101, 1288, 136, 2419, -101, 1288, 134, 2419,
+ -101, 49, -101, 173, -101, -101, 1288, -101, -101, 363,
+ -101, -101, -101, 137, 1565, -101, -101, 1658, -101, -101,
+ 1844, -101, -101, -101, -101, -101, -101, 95, -101, -101,
+ -101, -101, -101, -101, -101, -101, 2322, -101, -101, -101,
+ 92, 15, 925, 169, 27, -6, -101, -101, 212, -101,
+ 191, -101, -101, -101, 323, 211, -101, 1288, -101, 214,
+ -101, -101, 216, 40, 317, 210, 43, 259, 236, -101,
+ 36, -101, 747, 96, -101, 29, 747, -101, -101, 1198,
+ -101, -101, -101, 1107, -101, -101, 231, -101, 1288, -101,
+ 217, 286, 32, -101, -101, -101, 188, 340, 51, 1288,
+ 175, -101, -101, 171, -101, 179, -101, 56, -11, 351,
+ 181, 336, -101, 110, -101, -101, -101, 1934, 647, -101,
+ -101, -101, -101, 253, 2516, 1751, -5, 460, 22, 468,
+ 138, 1288, 2419, 24, -2, 412, 23, -3, 836, 20,
+ 87, -101, 1382, -101, 17, -10, 18, 1288, 25, 8,
+ 1288, 33, 1288, 12, 14, 120, -101, -101, 13, -101,
+ -101, 747, -101, 248, -47, 828, -101, -101, 152, 482,
+ -101, 150, -101, 123, -101, -101, 398, -101, -101, 117,
+ -101, -101, -101, -101, -101, -101,
+
+ -106, 6, -92, 10, 5, 278, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -42,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, 109,
+ -106, -106, -106, -10, -106, -106, -35, 24, 73, 90,
+ -106, 219, 181, -106, -106, -106, 171, 120, -106, -106,
+ -106, -106, -106, 174, -106, 170, 167, -106, 175, 163,
+ -106, -106, -106, -106, 184, 177, 180, -106, -106, -106,
+ -106, 125, -106, 132, 134, 162, 130, -106, 121, 124,
+ 123, 141, 142, 152, -106, 154, 161, 160, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, 139,
+ -106, 143, -106, 156, 91, 55, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, 32, -106, -106, -106, -106, -106, 33, -106, -106,
+ 26, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, 96, -106, 119, 52, -106, -106,
+ 66, -106, 220, 69, 71, -106, -106, -106, -106, -106,
+ -106, -106, -106, 25, -106, -106, -106, 64, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, 70, -106, -106, 61,
+ -106, 41, -106, 39, -106, 37, -106, -106, 42, -106,
+ 79, -106, -106, -106, 81, 72, -106, -106, -106, -106,
+ -106, -5, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, 21, -106, -106, -106, -106, 112, -106, -106,
+ -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, 17, 237, -106, 192, 236, 224, 225, -106, 97,
+ 98, 101, 99, 113, -106, -106, -106, -106, -106, -106,
+ -106, -106, 204, -106, 223, -106, 235, -106, -106, 239,
+ -106, 197, -106, -106, 228, -106, 27, -106, 13, -106,
+ 2, -106, 233, -106, 190, 198, -106, -106, 196, -106,
+ -106, -106, -106, -106, -106, 200, -106, 107, 135, -106,
+ -106, 186, -106, 84, -106, 80, -106, 76, -106, -106,
+ 89, -106, -106, -49, -106, -106, 47, -106, 40, -106,
+ 44, -106, 68, -106, -106, -106, -106, -106, -106, 53,
+ -106, 35, -106, 49, -106, 87, 63, -106, -106, 30,
+ -106, -106, 103, -106, -106, -106, 51, -106, -106, -106,
+ -106, 86, -106, 67, 114, -106, 74, -106, -106, 65,
+ -106, 56, -106, -106, -106, -106, -106, -106, -106, 62,
+ -106, -106, -106, -106, -106, -106, 95, -106, -106, 78,
+ -106, -106, -106, -106, 75, -106, 88, -106, -106, -106,
+ -106, -106, -54, -106, 45, -106, -40, -106, -106, -106,
+ -106, 94, -106, -106, 100, -106, -106, -106, -106, -106,
+ 150, -41, -106, -106, 54, -106, 43, -106, 48, -106,
+ -106, -106, -106, 59, -106, 57, -106, 60, -106, 58,
+ -106, -106, -106, -106, -106, -106, 38, -106, -106, 144,
+ -106, -106, -106, -106, 31, -106, -106, 202, -106, -106,
+ 50, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106, 77, -106, -106, -106,
+ -106, -106, 82, -106, -106, -106, -106, -106, -106, -106,
+ -17, -106, -106, -106, -4, -106, -106, 12, -106, -106,
+ -106, -106, -106, -106, -14, 46, -106, -13, -106, -106,
+ -106, -106, 108, -106, -106, -106, 243, -106, -106, 295,
+ -106, -106, -106, 290, -106, -106, -106, -106, 346, -106,
+ -106, -106, 16, -106, -106, -106, 22, 23, -106, 34,
+ -106, -106, -106, -106, -106, 11, -106, -106, -106, 7,
+ 1, 8, -106, -106, -106, -106, -106, 307, 179, -106,
+ -106, -106, -106, -106, 18, 281, 9, 15, -106, 4,
+ -106, 83, 29, -106, -106, -2, -106, -106, 85, -106,
+ -106, -106, 3, -106, -106, -106, -106, 14, -106, 0,
+ 105, -106, 93, -106, -106, -106, -106, -106, -1, -106,
+ -106, 20, -106, -106, 28, 92, -106, -106, -106, 19,
+ -106, -106, -106, -106, -106, -106, -12, -106, -106, -106,
+ -106, -106, -106, -106, -106, -106};
+
+const short QDeclarativeJSGrammar::action_info [] = {
+ 399, 352, 345, -101, 343, 457, 440, 403, 257, -112,
+ -125, -131, -123, 346, -120, 348, -128, 389, 453, 391,
+ 416, 401, 408, 563, -101, -123, 416, -120, 539, -131,
+ 346, -112, -125, 348, 257, 99, 71, 645, 621, 101,
+ -128, 440, 141, 621, 164, 431, 539, 430, 453, 573,
+ 457, 444, 440, 424, 71, 424, 101, 446, 559, 420,
+ 424, 448, 539, 440, 570, 539, 466, 527, 312, 346,
+ 532, 312, 318, 272, 409, 183, 342, 525, 147, 141,
+ 348, 510, 457, 414, 272, 325, 0, 0, 252, 99,
+ 257, 440, 296, 556, -102, 292, 453, 190, 170, 416,
+ 164, 434, 141, 141, 536, 251, 304, 172, 141, 141,
+ 443, 0, 335, 340, 141, 427, 0, 0, 0, 149,
+ 327, 306, 0, 292, 444, 0, 173, 0, 536, 141,
+ 141, 0, 0, 179, 333, 141, 294, 236, 189, 314,
+ 141, 301, 141, 315, 141, 477, 331, 242, 241, 413,
+ 412, 62, 537, 166, 58, 488, 142, 167, 294, 58,
+ 428, 254, 63, 256, 255, 59, 418, 172, 247, 246,
+ 59, 575, 574, 328, 249, 248, 616, 177, 641, 640,
+ 58, 469, 337, 141, 635, 634, 173, 350, 187, 249,
+ 248, 59, 310, 478, 459, 58, 455, 64, 523, 249,
+ 248, 85, 85, 86, 86, 103, 59, 565, 511, 172,
+ 511, 638, 637, 64, 87, 87, 141, 511, 517, 577,
+ 511, 0, 141, 0, 104, 141, 105, 85, 173, 86,
+ 174, 172, 566, 564, 470, 468, 562, 561, 548, 511,
+ 87, 636, 65, 530, 513, 539, 141, 85, 66, 86,
+ 173, 0, 406, 0, 513, 512, 513, 64, 65, 0,
+ 87, 172, 0, 513, 66, 512, 513, 512, 172, 235,
+ 234, 0, 518, 516, 512, 521, 520, 512, 554, 553,
+ 173, 85, 406, 86, 0, 513, -89, 173, 34, 174,
+ 73, 74, 549, 547, 87, 631, 512, 531, 529, 438,
+ 437, 172, 65, 0, 578, 274, 275, 0, 66, 632,
+ 630, 34, 0, 73, 74, 274, 275, 75, 76, -89,
+ 173, 0, 174, 34, 0, 48, 50, 49, 0, 0,
+ 0, 0, 276, 277, 34, 0, 0, 0, 34, 629,
+ 75, 76, 276, 277, 279, 280, 34, 0, 48, 50,
+ 49, 45, 34, 281, 279, 280, 282, 85, 283, 86,
+ 48, 50, 49, 281, 0, 34, 282, 0, 283, 34,
+ 87, 48, 50, 49, 45, 48, 50, 49, 0, 0,
+ 34, 0, 0, 48, 50, 49, 45, 34, 0, 48,
+ 50, 49, 34, 0, 0, 0, 0, 45, 34, 0,
+ 0, 45, 48, 50, 49, 0, 48, 50, 49, 45,
+ 0, 0, 0, 0, 34, 45, 0, 48, 50, 49,
+ 34, 0, 0, 0, 48, 50, 49, 34, 45, 48,
+ 50, 49, 45, 279, 280, 48, 50, 49, 0, 0,
+ 0, 34, 281, 45, 0, 282, 0, 283, -343, 34,
+ 45, 48, 50, 49, 0, 45, -343, 48, 50, 49,
+ 0, 45, 78, 79, 48, 50, 49, 0, 0, 0,
+ 80, 81, 0, 0, 82, 0, 83, 45, 48, 50,
+ 49, 0, 0, 45, 78, 79, 48, 50, 49, 34,
+ 45, 0, 80, 81, 78, 79, 82, 34, 83, 0,
+ 0, 0, 80, 81, 45, 34, 82, 0, 83, 0,
+ 0, 34, 45, 0, 6, 5, 4, 1, 3, 2,
+ 0, 240, 239, 0, 34, 0, 48, 50, 49, 245,
+ 244, 0, 0, 34, 48, 50, 49, 245, 244, 0,
+ 0, 0, 48, 50, 49, 0, 0, 0, 48, 50,
+ 49, 0, 45, 0, 0, 0, 245, 244, 0, 0,
+ 45, 48, 50, 49, 0, 240, 239, 34, 45, 0,
+ 48, 50, 49, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 78, 79, 0, 0, 45, 151, 0,
+ 0, 80, 81, 0, 0, 82, 45, 83, 152, 240,
+ 239, 0, 153, 0, 48, 50, 49, 0, 0, 0,
+ 0, 154, 0, 155, 0, 0, 308, 0, 0, 0,
+ 0, 0, 0, 0, 156, 0, 157, 62, 0, 0,
+ 45, 0, 0, 0, 158, 0, 0, 159, 63, 0,
+ 0, 0, 0, 160, 0, 0, 0, 0, 0, 161,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
+ 31, 151, 0, 0, 0, 162, 0, 0, 0, 33,
+ 0, 152, 0, 0, 0, 153, 34, 0, 0, 0,
+ 35, 36, 0, 37, 154, 0, 155, 0, 0, 0,
+ 502, 0, 0, 0, 44, 0, 0, 156, 0, 157,
+ 62, 0, 0, 0, 0, 0, 0, 158, 0, 0,
+ 159, 63, 51, 48, 50, 49, 160, 52, 0, 0,
+ 0, 0, 161, 0, 0, 0, 0, 0, 43, 54,
+ 32, 30, 31, 0, 40, 0, 0, 0, 162, 45,
+ 0, 33, 0, 0, 0, 0, 0, 0, 34, 0,
+ 0, 0, 35, 36, 0, 37, 0, 0, 0, 30,
+ 31, 0, 41, 0, 0, 0, 44, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 34, 0, 0, 0,
+ 35, 36, 0, 37, 51, 48, 50, 49, 0, 52,
+ 502, 0, 0, 0, 44, 0, 0, 0, 0, 0,
+ 43, 54, 32, 0, 0, 0, 40, 0, 0, 0,
+ 0, 45, 51, 48, 50, 49, 0, 52, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 43, 54,
+ 32, 0, 0, 0, 40, 0, 0, 0, 0, 45,
+ 30, 31, 0, 0, 0, 0, 0, 0, 30, 31,
+ 33, 0, 0, 0, 0, 0, 0, 34, 33, 0,
+ 0, 35, 36, 0, 37, 34, 0, 0, 0, 35,
+ 36, 502, 37, 0, 0, 44, 0, 0, 0, 41,
+ 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 0, 51, 48, 50, 49, 0, 52, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 43, 54, 32,
+ 45, 0, 0, 40, 0, 0, 0, 0, 45, 30,
+ 31, 0, 0, 0, 0, 0, 0, 30, 31, 33,
+ 0, 0, 0, 0, 0, 0, 34, 33, 0, 0,
+ 35, 36, 0, 37, 34, 0, 0, 0, 35, 36,
+ 41, 37, 0, 0, 44, 0, 0, 0, 502, 0,
+ 0, 0, 44, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 48, 50, 49, 0, 52, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 0, 43, 54,
+ 32, 0, 0, 0, 40, 0, 43, 54, 32, 45,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 501, 0, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 215, 0,
+ 0, 0, 0, 0, 0, 34, 0, 0, 0, 35,
+ 36, 0, 37, 0, 0, 0, 0, 0, 0, 502,
+ 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 51, 503, 505, 504, 0, 52, 0, 0, 0,
+ 0, 226, 0, 0, 0, 0, 0, 43, 54, 32,
+ 210, 0, 0, 40, 0, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 0, 0, 501, 0, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 215,
+ 0, 0, 0, 0, 0, 0, 34, 0, 0, 0,
+ 35, 36, 0, 37, 0, 0, 0, 0, 0, 0,
+ 502, 0, 0, 0, 44, 0, 0, 0, 0, 0,
+ 0, 0, 544, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 503, 505, 504, 0, 52, 0, 0,
+ 0, 0, 226, 0, 0, 0, 0, 0, 43, 54,
+ 32, 210, 0, 0, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 501, 0,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 215, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 0, 0, 0, 0, 0,
+ 0, 502, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 0, 0, 541, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 503, 505, 504, 0, 52, 0,
+ 0, 0, 0, 226, 0, 0, 0, 0, 0, 43,
+ 54, 32, 210, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 53, 0, 55, 0, 56, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, -121,
+ 0, 0, 0, 29, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 35, 36, 0, 37, 0,
+ 0, 0, 38, 0, 39, 41, 42, 0, 0, 44,
+ 0, 0, 0, 46, 0, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 51, 48, 50,
+ 49, 0, 52, 0, 53, 0, 55, 0, 56, 0,
+ 0, 0, 0, 43, 54, 32, 0, 0, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 29, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 35, 36, 0, 37, 0,
+ 0, 0, 38, 0, 39, 41, 42, 0, 0, 44,
+ 0, 0, 0, 46, 0, 47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 51, 48, 50,
+ 49, 0, 52, 0, 53, 0, 55, 271, 56, 0,
+ 0, 0, 0, 43, 54, 32, 0, 0, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 483, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 486, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 475, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 481, 0, 0, 0, 0, 0,
+ 0, 0, 0, 51, 48, 50, 49, 0, 52, 0,
+ 53, 0, 55, 0, 56, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 475,
+ 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 476, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 53, 0, 55, 0, 56, 0, 0,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 483, 0, 0, 29, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
+ 0, 0, 0, 34, 0, 0, 0, 35, 36, 0,
+ 37, 0, 0, 0, 38, 0, 39, 41, 42, 0,
+ 0, 44, 0, 0, 0, 46, 0, 47, 0, 0,
+ 484, 0, 0, 0, 0, 0, 0, 0, 0, 51,
+ 48, 50, 49, 0, 52, 0, 53, 0, 55, 0,
+ 56, 0, 0, 0, 0, 43, 54, 32, 0, 0,
+ 0, 40, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 29, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
+ 0, 0, 0, 34, 217, 0, 0, 584, 585, 0,
+ 37, 0, 0, 0, 38, 0, 39, 41, 42, 0,
+ 0, 44, 0, 0, 0, 46, 0, 47, 0, 0,
+ 0, 0, 0, 0, 0, 221, 0, 0, 0, 51,
+ 48, 50, 49, 0, 52, 0, 53, 0, 55, 0,
+ 56, 0, 0, 0, 0, 43, 54, 32, 0, 0,
+ 0, 40, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 109, 110, 111, 0, 0,
+ 113, 115, 116, 0, 0, 117, 0, 118, 0, 0,
+ 0, 120, 121, 122, 0, 0, 0, 0, 0, 0,
+ 34, 123, 124, 125, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 126, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 129, 0, 0, 0, 0, 0, 0, 48, 50, 49,
+ 130, 131, 132, 0, 134, 135, 136, 137, 138, 139,
+ 0, 0, 127, 133, 119, 112, 114, 128, 0, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 109, 110, 111, 0, 0, 113, 115, 116,
+ 0, 0, 117, 0, 118, 0, 0, 0, 120, 121,
+ 122, 0, 0, 0, 0, 0, 0, 393, 123, 124,
+ 125, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 126, 0, 0, 0, 394, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 129, 0, 0,
+ 0, 0, 0, 398, 395, 397, 0, 130, 131, 132,
+ 0, 134, 135, 136, 137, 138, 139, 0, 0, 127,
+ 133, 119, 112, 114, 128, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 109,
+ 110, 111, 0, 0, 113, 115, 116, 0, 0, 117,
+ 0, 118, 0, 0, 0, 120, 121, 122, 0, 0,
+ 0, 0, 0, 0, 393, 123, 124, 125, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 126, 0,
+ 0, 0, 394, 0, 0, 0, 0, 0, 0, 0,
+ 396, 0, 0, 0, 129, 0, 0, 0, 0, 0,
+ 398, 395, 397, 0, 130, 131, 132, 0, 134, 135,
+ 136, 137, 138, 139, 0, 0, 127, 133, 119, 112,
+ 114, 128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 209, 0, 0, 0,
+ 0, 211, 0, 29, 30, 31, 213, 0, 0, 0,
+ 0, 0, 0, 214, 215, 0, 0, 0, 0, 0,
+ 0, 216, 217, 0, 0, 218, 36, 0, 37, 0,
+ 0, 0, 38, 0, 39, 41, 42, 0, 0, 44,
+ 0, 0, 0, 46, 0, 47, 0, 0, 0, 0,
+ 0, 220, 0, 221, 0, 0, 0, 51, 219, 222,
+ 49, 223, 52, 224, 53, 225, 55, 226, 56, 227,
+ 228, 0, 0, 43, 54, 32, 210, 212, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 209, 0, 0, 0, 0, 211, 0,
+ 29, 30, 31, 213, 0, 0, 0, 0, 0, 0,
+ 214, 33, 0, 0, 0, 0, 0, 0, 216, 217,
+ 0, 0, 218, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 220, 0,
+ 221, 0, 0, 0, 51, 219, 222, 49, 223, 52,
+ 224, 53, 225, 55, 226, 56, 227, 228, 0, 0,
+ 43, 54, 32, 210, 212, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 587, 110, 111, 0, 0, 589, 115, 591, 30, 31,
+ 592, 0, 118, 0, 0, 0, 120, 594, 595, 0,
+ 0, 0, 0, 0, 0, 596, 597, 124, 125, 218,
+ 36, 0, 37, 0, 0, 0, 38, 0, 39, 598,
+ 42, 0, 0, 600, 0, 0, 0, 46, 0, 47,
+ 0, 0, 0, 0, 0, 602, 0, 221, 0, 0,
+ 0, 604, 601, 603, 49, 605, 606, 607, 53, 609,
+ 610, 611, 612, 613, 614, 0, 0, 599, 608, 593,
+ 588, 590, 128, 40, 0, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 0, 0, 361, 110, 111,
+ 0, 0, 363, 115, 365, 30, 31, 366, 0, 118,
+ 0, 0, 0, 120, 368, 369, 0, 0, 0, 0,
+ 0, 0, 370, 371, 124, 125, 218, 36, 0, 37,
+ 0, 0, 0, 38, 0, 39, 372, 42, 0, 0,
+ 374, 0, 0, 0, 46, 0, 47, 0, -267, 0,
+ 0, 0, 376, 0, 221, 0, 0, 0, 378, 375,
+ 377, 49, 379, 380, 381, 53, 383, 384, 385, 386,
+ 387, 388, 0, 0, 373, 382, 367, 362, 364, 128,
+ 40, 0, 0, 0, 0, 45, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+
+ 472, 546, 528, 639, 311, 182, 302, 498, 514, 16,
+ 461, 515, 496, 182, 497, 519, 309, 436, 619, 243,
+ 358, 439, 576, 572, 253, 150, 571, 487, 617, 307,
+ 238, 250, 320, 628, 633, 555, 569, 560, 558, 642,
+ 186, 250, 425, 349, 358, 182, 351, 557, 433, 347,
+ 238, 344, 339, 429, 302, 402, 243, 445, 447, 456,
+ 460, 163, 454, 458, 243, 250, 485, 143, 148, 449,
+ 353, 526, 176, 467, 237, 450, 238, 415, 338, 188,
+ 410, 237, 302, 336, 436, 482, 334, 169, 439, 436,
+ 146, 417, 392, 439, 140, 522, 358, 400, 404, 0,
+ 390, 171, 358, 0, 186, 500, 146, 0, 643, 0,
+ 0, 178, 0, 0, 0, 0, 404, 60, 60, 489,
+ 452, 500, 320, 0, 534, 0, 405, 60, 0, 180,
+ 146, 60, 0, 180, 60, 407, 490, 60, 302, 452,
+ 60, 60, 60, 60, 405, 60, 284, 285, 287, 60,
+ 286, 451, 358, 60, 165, 180, 266, 60, 60, 461,
+ 451, 270, 288, 60, 60, 60, 493, 60, 60, 60,
+ 84, 106, 92, 91, 60, 432, 60, 72, 60, 168,
+ 98, 435, 77, 60, 96, 60, 60, 60, 341, 302,
+ 93, 94, 500, 108, 329, 100, 60, 102, 60, 618,
+ 302, 95, 88, 330, 60, 60, 60, 60, 90, 89,
+ 70, 60, 97, 452, 60, 60, 451, 492, 60, 60,
+ 494, 60, 61, 68, 60, 60, 69, 491, 60, 471,
+ 67, 302, 404, 480, 60, 106, 60, 479, 0, 270,
+ 298, 270, 298, 278, 298, 270, 0, 270, 60, 270,
+ 0, 316, 0, 270, 332, 0, 500, 108, 175, 538,
+ 405, 293, 319, 0, 317, 303, 326, 60, 60, 60,
+ 0, 0, 270, 270, 270, 290, 291, 60, 295, 298,
+ 60, 60, 270, 298, 270, 270, 270, 289, 270, 0,
+ 273, 500, 313, 0, 551, 545, 305, 534, 508, 615,
+ 542, 297, 0, 500, 0, 300, 499, 509, 500, 0,
+ 508, 0, 0, 0, 0, 508, 472, 0, 499, 509,
+ 583, 0, 0, 499, 509, 0, 0, 586, 579, 580,
+ 581, 582, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 550,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 551,
+ 0, 0, 0, 0, 0, 0, 552, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0};
+
+const short QDeclarativeJSGrammar::action_check [] = {
+ 7, 16, 55, 7, 33, 36, 33, 55, 36, 7,
+ 7, 7, 7, 7, 7, 36, 7, 7, 36, 8,
+ 36, 55, 60, 29, 7, 7, 36, 7, 33, 7,
+ 7, 7, 7, 36, 36, 48, 1, 0, 90, 79,
+ 7, 33, 8, 90, 2, 7, 33, 55, 36, 60,
+ 36, 20, 33, 5, 1, 5, 79, 36, 7, 33,
+ 5, 60, 33, 33, 8, 33, 17, 24, 2, 7,
+ 34, 2, 7, 1, 7, 36, 60, 37, 8, 8,
+ 36, 66, 36, 7, 1, 17, -1, -1, 36, 48,
+ 36, 33, 8, 66, 7, 48, 36, 33, 7, 36,
+ 2, 7, 8, 8, 8, 77, 61, 15, 8, 8,
+ 6, -1, 31, 36, 8, 10, -1, -1, -1, 60,
+ 8, 60, -1, 48, 20, -1, 34, -1, 8, 8,
+ 8, -1, -1, 60, 60, 8, 79, 55, 60, 50,
+ 8, 61, 8, 54, 8, 8, 61, 61, 62, 61,
+ 62, 42, 56, 50, 40, 60, 56, 54, 79, 40,
+ 55, 60, 53, 61, 62, 51, 60, 15, 61, 62,
+ 51, 61, 62, 61, 61, 62, 56, 56, 61, 62,
+ 40, 8, 60, 8, 61, 62, 34, 60, 8, 61,
+ 62, 51, 60, 56, 60, 40, 60, 12, 29, 61,
+ 62, 25, 25, 27, 27, 15, 51, 36, 29, 15,
+ 29, 61, 62, 12, 38, 38, 8, 29, 7, 7,
+ 29, -1, 8, -1, 34, 8, 36, 25, 34, 27,
+ 36, 15, 61, 62, 61, 62, 61, 62, 7, 29,
+ 38, 91, 57, 7, 75, 33, 8, 25, 63, 27,
+ 34, -1, 36, -1, 75, 86, 75, 12, 57, -1,
+ 38, 15, -1, 75, 63, 86, 75, 86, 15, 61,
+ 62, -1, 61, 62, 86, 61, 62, 86, 61, 62,
+ 34, 25, 36, 27, -1, 75, 33, 34, 29, 36,
+ 18, 19, 61, 62, 38, 47, 86, 61, 62, 61,
+ 62, 15, 57, -1, 92, 18, 19, -1, 63, 61,
+ 62, 29, -1, 18, 19, 18, 19, 45, 46, 33,
+ 34, -1, 36, 29, -1, 66, 67, 68, -1, -1,
+ -1, -1, 45, 46, 29, -1, -1, -1, 29, 91,
+ 45, 46, 45, 46, 23, 24, 29, -1, 66, 67,
+ 68, 92, 29, 32, 23, 24, 35, 25, 37, 27,
+ 66, 67, 68, 32, -1, 29, 35, -1, 37, 29,
+ 38, 66, 67, 68, 92, 66, 67, 68, -1, -1,
+ 29, -1, -1, 66, 67, 68, 92, 29, -1, 66,
+ 67, 68, 29, -1, -1, -1, -1, 92, 29, -1,
+ -1, 92, 66, 67, 68, -1, 66, 67, 68, 92,
+ -1, -1, -1, -1, 29, 92, -1, 66, 67, 68,
+ 29, -1, -1, -1, 66, 67, 68, 29, 92, 66,
+ 67, 68, 92, 23, 24, 66, 67, 68, -1, -1,
+ -1, 29, 32, 92, -1, 35, -1, 37, 36, 29,
+ 92, 66, 67, 68, -1, 92, 36, 66, 67, 68,
+ -1, 92, 23, 24, 66, 67, 68, -1, -1, -1,
+ 31, 32, -1, -1, 35, -1, 37, 92, 66, 67,
+ 68, -1, -1, 92, 23, 24, 66, 67, 68, 29,
+ 92, -1, 31, 32, 23, 24, 35, 29, 37, -1,
+ -1, -1, 31, 32, 92, 29, 35, -1, 37, -1,
+ -1, 29, 92, -1, 93, 94, 95, 96, 97, 98,
+ -1, 61, 62, -1, 29, -1, 66, 67, 68, 61,
+ 62, -1, -1, 29, 66, 67, 68, 61, 62, -1,
+ -1, -1, 66, 67, 68, -1, -1, -1, 66, 67,
+ 68, -1, 92, -1, -1, -1, 61, 62, -1, -1,
+ 92, 66, 67, 68, -1, 61, 62, 29, 92, -1,
+ 66, 67, 68, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, 23, 24, -1, -1, 92, 3, -1,
+ -1, 31, 32, -1, -1, 35, 92, 37, 13, 61,
+ 62, -1, 17, -1, 66, 67, 68, -1, -1, -1,
+ -1, 26, -1, 28, -1, -1, 31, -1, -1, -1,
+ -1, -1, -1, -1, 39, -1, 41, 42, -1, -1,
+ 92, -1, -1, -1, 49, -1, -1, 52, 53, -1,
+ -1, -1, -1, 58, -1, -1, -1, -1, -1, 64,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 12,
+ 13, 3, -1, -1, -1, 80, -1, -1, -1, 22,
+ -1, 13, -1, -1, -1, 17, 29, -1, -1, -1,
+ 33, 34, -1, 36, 26, -1, 28, -1, -1, -1,
+ 43, -1, -1, -1, 47, -1, -1, 39, -1, 41,
+ 42, -1, -1, -1, -1, -1, -1, 49, -1, -1,
+ 52, 53, 65, 66, 67, 68, 58, 70, -1, -1,
+ -1, -1, 64, -1, -1, -1, -1, -1, 81, 82,
+ 83, 12, 13, -1, 87, -1, -1, -1, 80, 92,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 12,
+ 13, -1, 43, -1, -1, -1, 47, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, 65, 66, 67, 68, -1, 70,
+ 43, -1, -1, -1, 47, -1, -1, -1, -1, -1,
+ 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
+ -1, 92, 65, 66, 67, 68, -1, 70, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 81, 82,
+ 83, -1, -1, -1, 87, -1, -1, -1, -1, 92,
+ 12, 13, -1, -1, -1, -1, -1, -1, 12, 13,
+ 22, -1, -1, -1, -1, -1, -1, 29, 22, -1,
+ -1, 33, 34, -1, 36, 29, -1, -1, -1, 33,
+ 34, 43, 36, -1, -1, 47, -1, -1, -1, 43,
+ -1, -1, -1, 47, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, 81, 82, 83,
+ 92, -1, -1, 87, -1, -1, -1, -1, 92, 12,
+ 13, -1, -1, -1, -1, -1, -1, 12, 13, 22,
+ -1, -1, -1, -1, -1, -1, 29, 22, -1, -1,
+ 33, 34, -1, 36, 29, -1, -1, -1, 33, 34,
+ 43, 36, -1, -1, 47, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, -1, 81, 82,
+ 83, -1, -1, -1, 87, -1, 81, 82, 83, 92,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 10, -1, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, -1, -1, -1, 43,
+ -1, -1, -1, 47, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, -1, -1,
+ -1, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ 84, -1, -1, 87, -1, -1, -1, -1, 92, -1,
+ -1, -1, -1, -1, -1, -1, -1, 10, -1, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, -1, -1, -1,
+ 43, -1, -1, -1, 47, -1, -1, -1, -1, -1,
+ -1, -1, 55, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, -1,
+ -1, -1, 75, -1, -1, -1, -1, -1, 81, 82,
+ 83, 84, -1, -1, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, 10, -1,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
+ -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, -1, -1, 55, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, -1, 75, -1, -1, -1, -1, -1, 81,
+ 82, 83, 84, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 7,
+ -1, -1, -1, 11, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
+ 68, -1, 70, -1, 72, -1, 74, -1, 76, -1,
+ -1, -1, -1, 81, 82, 83, -1, -1, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, 11, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
+ 68, -1, 70, -1, 72, -1, 74, 75, 76, -1,
+ -1, -1, -1, 81, 82, 83, -1, -1, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, 8, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, 8, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, 56, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, 8,
+ -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, 56, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, 72, -1, 74, -1, 76, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, 8, -1, -1, 11, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
+ -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
+ 56, -1, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
+ 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, 87, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, 11, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, 30, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
+ -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
+ -1, -1, -1, -1, -1, 61, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
+ 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, 87, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, 5, 6, -1, -1,
+ 9, 10, 11, -1, -1, 14, -1, 16, -1, -1,
+ -1, 20, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 59, -1, -1, -1, -1, -1, -1, 66, 67, 68,
+ 69, 70, 71, -1, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, 86, -1, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, 4, 5, 6, -1, -1, 9, 10, 11,
+ -1, -1, 14, -1, 16, -1, -1, -1, 20, 21,
+ 22, -1, -1, -1, -1, -1, -1, 29, 30, 31,
+ 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 59, -1, -1,
+ -1, -1, -1, 65, 66, 67, -1, 69, 70, 71,
+ -1, 73, 74, 75, 76, 77, 78, -1, -1, 81,
+ 82, 83, 84, 85, 86, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ 55, -1, -1, -1, 59, -1, -1, -1, -1, -1,
+ 65, 66, 67, -1, 69, 70, 71, -1, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 4, -1, -1, -1,
+ -1, 9, -1, 11, 12, 13, 14, -1, -1, -1,
+ -1, -1, -1, 21, 22, -1, -1, -1, -1, -1,
+ -1, 29, 30, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, 59, -1, 61, -1, -1, -1, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, -1, -1, 81, 82, 83, 84, 85, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, -1, -1, -1, -1, 9, -1,
+ 11, 12, 13, 14, -1, -1, -1, -1, -1, -1,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, 59, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ 4, 5, 6, -1, -1, 9, 10, 11, 12, 13,
+ 14, -1, 16, -1, -1, -1, 20, 21, 22, -1,
+ -1, -1, -1, -1, -1, 29, 30, 31, 32, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, -1, -1, -1, 59, -1, 61, -1, -1,
+ -1, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, -1, -1, 81, 82, 83,
+ 84, 85, 86, 87, -1, -1, -1, -1, 92, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
+ -1, -1, 9, 10, 11, 12, 13, 14, -1, 16,
+ -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, 31, 32, 33, 34, -1, 36,
+ -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
+ 47, -1, -1, -1, 51, -1, 53, -1, 55, -1,
+ -1, -1, 59, -1, 61, -1, -1, -1, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
+ 87, -1, -1, -1, -1, 92, -1, -1, -1, -1,
+ -1, -1, -1, -1,
+
+ 35, 15, 15, 15, 2, 15, 3, 2, 25, 3,
+ 15, 15, 104, 15, 4, 3, 3, 3, 19, 15,
+ 2, 21, 15, 15, 3, 67, 25, 3, 19, 2,
+ 15, 2, 15, 13, 15, 19, 25, 3, 15, 11,
+ 15, 2, 96, 3, 2, 15, 2, 25, 3, 2,
+ 15, 100, 15, 93, 3, 2, 15, 98, 15, 2,
+ 2, 35, 3, 3, 15, 2, 35, 35, 35, 21,
+ 2, 25, 3, 35, 4, 21, 15, 2, 2, 15,
+ 2, 4, 3, 3, 3, 35, 2, 35, 21, 3,
+ 35, 3, 36, 21, 3, 13, 2, 35, 13, -1,
+ 35, 35, 2, -1, 15, 13, 35, -1, 16, -1,
+ -1, 40, -1, -1, -1, -1, 13, 44, 44, 46,
+ 46, 13, 15, -1, 16, -1, 41, 44, -1, 46,
+ 35, 44, -1, 46, 44, 40, 46, 44, 3, 46,
+ 44, 44, 44, 44, 41, 44, 49, 49, 49, 44,
+ 49, 46, 2, 44, 58, 46, 44, 44, 44, 15,
+ 46, 49, 49, 44, 44, 44, 46, 44, 44, 44,
+ 49, 15, 49, 49, 44, 81, 44, 52, 44, 60,
+ 50, 81, 50, 44, 50, 44, 44, 44, 99, 3,
+ 49, 49, 13, 37, 87, 56, 44, 54, 44, 20,
+ 3, 49, 48, 68, 44, 44, 44, 44, 48, 48,
+ 47, 44, 50, 46, 44, 44, 46, 46, 44, 44,
+ 46, 44, 47, 46, 44, 44, 46, 46, 44, 85,
+ 46, 3, 13, 31, 44, 15, 44, 35, -1, 49,
+ 44, 49, 44, 51, 44, 49, -1, 49, 44, 49,
+ -1, 61, -1, 49, 68, -1, 13, 37, 38, 16,
+ 41, 57, 66, -1, 66, 68, 66, 44, 44, 44,
+ -1, -1, 49, 49, 49, 51, 51, 44, 55, 44,
+ 44, 44, 49, 44, 49, 49, 49, 51, 49, -1,
+ 53, 13, 59, -1, 13, 5, 68, 16, 20, 18,
+ 5, 66, -1, 13, -1, 66, 28, 29, 13, -1,
+ 20, -1, -1, -1, -1, 20, 35, -1, 28, 29,
+ 13, -1, -1, 28, 29, -1, -1, 20, 21, 22,
+ 23, 24, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 3,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 13,
+ -1, -1, -1, -1, -1, -1, 20, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1};
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/parser/qdeclarativejsgrammar_p.h b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h
new file mode 100644
index 0000000000..ed3ca19041
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef QDECLARATIVEJSGRAMMAR_P_H
+#define QDECLARATIVEJSGRAMMAR_P_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeJSGrammar
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ REDUCE_HERE = 100,
+ SHIFT_THERE = 99,
+ T_AND = 1,
+ T_AND_AND = 2,
+ T_AND_EQ = 3,
+ T_AS = 91,
+ T_AUTOMATIC_SEMICOLON = 62,
+ T_BREAK = 4,
+ T_CASE = 5,
+ T_CATCH = 6,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_COMMENT = 88,
+ T_CONST = 84,
+ T_CONTINUE = 9,
+ T_DEBUGGER = 85,
+ T_DEFAULT = 10,
+ T_DELETE = 11,
+ T_DIVIDE_ = 12,
+ T_DIVIDE_EQ = 13,
+ T_DO = 14,
+ T_DOT = 15,
+ T_ELSE = 16,
+ T_EQ = 17,
+ T_EQ_EQ = 18,
+ T_EQ_EQ_EQ = 19,
+ T_FALSE = 83,
+ T_FEED_JS_EXPRESSION = 96,
+ T_FEED_JS_PROGRAM = 98,
+ T_FEED_JS_SOURCE_ELEMENT = 97,
+ T_FEED_JS_STATEMENT = 95,
+ T_FEED_UI_OBJECT_MEMBER = 94,
+ T_FEED_UI_PROGRAM = 93,
+ T_FINALLY = 20,
+ T_FOR = 21,
+ T_FUNCTION = 22,
+ T_GE = 23,
+ T_GT = 24,
+ T_GT_GT = 25,
+ T_GT_GT_EQ = 26,
+ T_GT_GT_GT = 27,
+ T_GT_GT_GT_EQ = 28,
+ T_IDENTIFIER = 29,
+ T_IF = 30,
+ T_IMPORT = 90,
+ T_IN = 31,
+ T_INSTANCEOF = 32,
+ T_LBRACE = 33,
+ T_LBRACKET = 34,
+ T_LE = 35,
+ T_LPAREN = 36,
+ T_LT = 37,
+ T_LT_LT = 38,
+ T_LT_LT_EQ = 39,
+ T_MINUS = 40,
+ T_MINUS_EQ = 41,
+ T_MINUS_MINUS = 42,
+ T_MULTILINE_STRING_LITERAL = 87,
+ T_NEW = 43,
+ T_NOT = 44,
+ T_NOT_EQ = 45,
+ T_NOT_EQ_EQ = 46,
+ T_NULL = 81,
+ T_NUMERIC_LITERAL = 47,
+ T_ON = 92,
+ T_OR = 48,
+ T_OR_EQ = 49,
+ T_OR_OR = 50,
+ T_PLUS = 51,
+ T_PLUS_EQ = 52,
+ T_PLUS_PLUS = 53,
+ T_PROPERTY = 66,
+ T_PUBLIC = 89,
+ T_QUESTION = 54,
+ T_RBRACE = 55,
+ T_RBRACKET = 56,
+ T_READONLY = 68,
+ T_REMAINDER = 57,
+ T_REMAINDER_EQ = 58,
+ T_RESERVED_WORD = 86,
+ T_RETURN = 59,
+ T_RPAREN = 60,
+ T_SEMICOLON = 61,
+ T_SIGNAL = 67,
+ T_STAR = 63,
+ T_STAR_EQ = 64,
+ T_STRING_LITERAL = 65,
+ T_SWITCH = 69,
+ T_THIS = 70,
+ T_THROW = 71,
+ T_TILDE = 72,
+ T_TRUE = 82,
+ T_TRY = 73,
+ T_TYPEOF = 74,
+ T_VAR = 75,
+ T_VOID = 76,
+ T_WHILE = 77,
+ T_WITH = 78,
+ T_XOR = 79,
+ T_XOR_EQ = 80,
+
+ ACCEPT_STATE = 645,
+ RULE_COUNT = 347,
+ STATE_COUNT = 646,
+ TERMINAL_COUNT = 101,
+ NON_TERMINAL_COUNT = 106,
+
+ GOTO_INDEX_OFFSET = 646,
+ GOTO_INFO_OFFSET = 2714,
+ GOTO_CHECK_OFFSET = 2714
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+QT_END_NAMESPACE
+#endif // QDECLARATIVEJSGRAMMAR_P_H
+
diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp
new file mode 100644
index 0000000000..4dfef45ed5
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp
@@ -0,0 +1,1258 @@
+/****************************************************************************
+**
+** Copyright (C) 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$
+**
+****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/qdeclarativejslexer_p.h"
+
+#include "private/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsengine_p.h"
+#include "private/qdeclarativejsgrammar_p.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+QT_END_NAMESPACE
+
+QT_QML_BEGIN_NAMESPACE
+
+#define shiftWindowsLineBreak() \
+ do { \
+ if (((current == '\r') && (next1 == '\n')) \
+ || ((current == '\n') && (next1 == '\r'))) { \
+ shift(1); \
+ } \
+ } \
+ while (0)
+
+namespace QDeclarativeJS {
+extern double integerFromString(const char *buf, int size, int radix);
+}
+
+using namespace QDeclarativeJS;
+
+Lexer::Lexer(Engine *eng, bool tokenizeComments)
+ : driver(eng),
+ yylineno(0),
+ done(false),
+ size8(128), size16(128),
+ pos8(0), pos16(0),
+ terminator(false),
+ restrKeyword(false),
+ delimited(false),
+ stackToken(-1),
+ state(Start),
+ pos(0),
+ code(0), length(0),
+ yycolumn(0),
+ startpos(0),
+ startlineno(0), startcolumn(0),
+ bol(true),
+ current(0), next1(0), next2(0), next3(0),
+ err(NoError),
+ wantRx(false),
+ check_reserved(true),
+ parenthesesState(IgnoreParentheses),
+ parenthesesCount(0),
+ prohibitAutomaticSemicolon(false),
+ tokenizeComments(tokenizeComments)
+{
+ if (driver) driver->setLexer(this);
+ // allocate space for read buffers
+ buffer8 = new char[size8];
+ buffer16 = new QChar[size16];
+ pattern = 0;
+ flags = 0;
+
+}
+
+Lexer::~Lexer()
+{
+ delete [] buffer8;
+ delete [] buffer16;
+}
+
+void Lexer::setCode(const QString &c, int lineno)
+{
+ errmsg.clear();
+ yylineno = lineno;
+ yycolumn = 1;
+ restrKeyword = false;
+ delimited = false;
+ stackToken = -1;
+ pos = 0;
+ code = c.unicode();
+ length = c.length();
+ bol = true;
+
+ // read first characters
+ current = (length > 0) ? code[0].unicode() : 0;
+ next1 = (length > 1) ? code[1].unicode() : 0;
+ next2 = (length > 2) ? code[2].unicode() : 0;
+ next3 = (length > 3) ? code[3].unicode() : 0;
+}
+
+void Lexer::shift(uint p)
+{
+ while (p--) {
+ ++pos;
+ ++yycolumn;
+ current = next1;
+ next1 = next2;
+ next2 = next3;
+ next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
+ }
+}
+
+void Lexer::setDone(State s)
+{
+ state = s;
+ done = true;
+}
+
+int Lexer::findReservedWord(const QChar *c, int size) const
+{
+ switch (size) {
+ case 2: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o'))
+ return QDeclarativeJSGrammar::T_DO;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f'))
+ return QDeclarativeJSGrammar::T_IF;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n'))
+ return QDeclarativeJSGrammar::T_IN;
+ else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_AS;
+ else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n'))
+ return QDeclarativeJSGrammar::T_ON;
+ } break;
+
+ case 3: {
+ if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r'))
+ return QDeclarativeJSGrammar::T_FOR;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w'))
+ return QDeclarativeJSGrammar::T_NEW;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y'))
+ return QDeclarativeJSGrammar::T_TRY;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r'))
+ return QDeclarativeJSGrammar::T_VAR;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 4: {
+ if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_CASE;
+ else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_ELSE;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_THIS;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d'))
+ return QDeclarativeJSGrammar::T_VOID;
+ else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h'))
+ return QDeclarativeJSGrammar::T_WITH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_TRUE;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l'))
+ return QDeclarativeJSGrammar::T_NULL;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 5: {
+ if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('k'))
+ return QDeclarativeJSGrammar::T_BREAK;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('h'))
+ return QDeclarativeJSGrammar::T_CATCH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('w'))
+ return QDeclarativeJSGrammar::T_THROW;
+ else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_WHILE;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_CONST;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_FALSE;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r')
+ && c[4] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('r'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('l'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s')
+ && c[4] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 6: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_DELETE;
+ else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n'))
+ return QDeclarativeJSGrammar::T_RETURN;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h'))
+ return QDeclarativeJSGrammar::T_SWITCH;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f'))
+ return QDeclarativeJSGrammar::T_TYPEOF;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_IMPORT;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l'))
+ return QDeclarativeJSGrammar::T_SIGNAL;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b')
+ && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
+ return QDeclarativeJSGrammar::T_PUBLIC;
+ else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i')
+ && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
+ && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
+ && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 7: {
+ if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l')
+ && c[6] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_DEFAULT;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l')
+ && c[6] == QLatin1Char('y'))
+ return QDeclarativeJSGrammar::T_FINALLY;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a')
+ && c[6] == QLatin1Char('n'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d')
+ && c[6] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a')
+ && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g')
+ && c[6] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t')
+ && c[6] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 8: {
+ if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_CONTINUE;
+ else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n'))
+ return QDeclarativeJSGrammar::T_FUNCTION;
+ else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u')
+ && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r'))
+ return QDeclarativeJSGrammar::T_DEBUGGER;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r')
+ && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y'))
+ return QDeclarativeJSGrammar::T_PROPERTY;
+ else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d')
+ && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y'))
+ return QDeclarativeJSGrammar::T_READONLY;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a')
+ && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
+ && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a')
+ && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 9: {
+ if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
+ && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f')
+ && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c')
+ && c[8] == QLatin1Char('e'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n')
+ && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('t'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
+ && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c')
+ && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e')
+ && c[8] == QLatin1Char('d'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 10: {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
+ && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
+ && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n')
+ && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e')
+ && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f'))
+ return QDeclarativeJSGrammar::T_INSTANCEOF;
+ else if (check_reserved) {
+ if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
+ && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l')
+ && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m')
+ && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ case 12: {
+ if (check_reserved) {
+ if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y')
+ && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
+ && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r')
+ && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')
+ && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z')
+ && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d'))
+ return QDeclarativeJSGrammar::T_RESERVED_WORD;
+ }
+ } break;
+
+ } // switch
+
+ return -1;
+}
+
+int Lexer::lex()
+{
+ int token = 0;
+ state = Start;
+ ushort stringType = 0; // either single or double quotes
+ bool multiLineString = false;
+ pos8 = pos16 = 0;
+ done = false;
+ terminator = false;
+
+ // did we push a token on the stack previously ?
+ // (after an automatic semicolon insertion)
+ if (stackToken >= 0) {
+ setDone(Other);
+ token = stackToken;
+ stackToken = -1;
+ }
+
+ bool identifierWithEscapedUnicode = false;
+
+ while (!done) {
+ switch (state) {
+ case Start:
+ if (isWhiteSpace()) {
+ // do nothing
+ } else if (current == '/' && next1 == '/') {
+ recordStartPos();
+ shift(1);
+ state = InSingleLineComment;
+ } else if (current == '/' && next1 == '*') {
+ recordStartPos();
+ shift(1);
+ state = InMultiLineComment;
+ } else if (current == 0) {
+ syncProhibitAutomaticSemicolon();
+ if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
+ // automatic semicolon insertion if program incomplete
+ token = QDeclarativeJSGrammar::T_SEMICOLON;
+ stackToken = 0;
+ setDone(Other);
+ } else {
+ setDone(Eof);
+ }
+ } else if (isLineTerminator()) {
+ if (restrKeyword) {
+ // automatic semicolon insertion
+ recordStartPos();
+ token = QDeclarativeJSGrammar::T_SEMICOLON;
+ setDone(Other);
+ } else {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ bol = true;
+ terminator = true;
+ syncProhibitAutomaticSemicolon();
+ }
+ } else if (current == '"' || current == '\'') {
+ recordStartPos();
+ state = InString;
+ multiLineString = false;
+ stringType = current;
+ } else if (current == '\\' && next1 == 'u') {
+ identifierWithEscapedUnicode = true;
+ recordStartPos();
+
+ shift(2); // skip the unicode escape prefix `\u'
+
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ state = InIdentifier;
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
+ break;
+ }
+
+ } else if (isIdentLetter(current)) {
+ identifierWithEscapedUnicode = false;
+ recordStartPos();
+ record16(current);
+ state = InIdentifier;
+ } else if (current == '0') {
+ recordStartPos();
+ record8(current);
+ state = InNum0;
+ } else if (isDecimalDigit(current)) {
+ recordStartPos();
+ record8(current);
+ state = InNum;
+ } else if (current == '.' && isDecimalDigit(next1)) {
+ recordStartPos();
+ record8(current);
+ state = InDecimal;
+ } else {
+ recordStartPos();
+ token = matchPunctuator(current, next1, next2, next3);
+ if (token != -1) {
+ if (terminator && !delimited && !prohibitAutomaticSemicolon
+ && (token == QDeclarativeJSGrammar::T_PLUS_PLUS
+ || token == QDeclarativeJSGrammar::T_MINUS_MINUS)) {
+ // automatic semicolon insertion
+ stackToken = token;
+ token = QDeclarativeJSGrammar::T_SEMICOLON;
+ }
+ setDone(Other);
+ }
+ else {
+ setDone(Bad);
+ err = IllegalCharacter;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal character");
+ }
+ }
+ break;
+ case InString:
+ if (current == stringType) {
+ shift(1);
+ setDone(String);
+ } else if (isLineTerminator()) {
+ multiLineString = true;
+ record16(current);
+ } else if (current == 0 || isLineTerminator()) {
+ setDone(Bad);
+ err = UnclosedStringLiteral;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line");
+ } else if (current == '\\') {
+ state = InEscapeSequence;
+ } else {
+ record16(current);
+ }
+ break;
+ // Escape Sequences inside of strings
+ case InEscapeSequence:
+ if (isOctalDigit(current)) {
+ if (current >= '0' && current <= '3' &&
+ isOctalDigit(next1) && isOctalDigit(next2)) {
+ record16(convertOctal(current, next1, next2));
+ shift(2);
+ state = InString;
+ } else if (isOctalDigit(current) &&
+ isOctalDigit(next1)) {
+ record16(convertOctal('0', current, next1));
+ shift(1);
+ state = InString;
+ } else if (isOctalDigit(current)) {
+ record16(convertOctal('0', '0', current));
+ state = InString;
+ } else {
+ setDone(Bad);
+ err = IllegalEscapeSequence;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal escape sequence");
+ }
+ } else if (current == 'x')
+ state = InHexEscape;
+ else if (current == 'u')
+ state = InUnicodeEscape;
+ else {
+ if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ bol = true;
+ } else {
+ record16(singleEscape(current));
+ }
+ state = InString;
+ }
+ break;
+ case InHexEscape:
+ if (isHexDigit(current) && isHexDigit(next1)) {
+ state = InString;
+ record16(QLatin1Char(convertHex(current, next1)));
+ shift(1);
+ } else if (current == stringType) {
+ record16(QLatin1Char('x'));
+ shift(1);
+ setDone(String);
+ } else {
+ record16(QLatin1Char('x'));
+ record16(current);
+ state = InString;
+ }
+ break;
+ case InUnicodeEscape:
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ state = InString;
+ } else if (current == stringType) {
+ record16(QLatin1Char('u'));
+ shift(1);
+ setDone(String);
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
+ }
+ break;
+ case InSingleLineComment:
+ if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ yycolumn = 0;
+ terminator = true;
+ bol = true;
+ if (restrKeyword) {
+ token = QDeclarativeJSGrammar::T_SEMICOLON;
+ setDone(Other);
+ } else
+ state = Start;
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ } else if (current == 0) {
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ setDone(Eof);
+ }
+
+ break;
+ case InMultiLineComment:
+ if (current == 0) {
+ setDone(Bad);
+ err = UnclosedComment;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file");
+ if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
+ } else if (isLineTerminator()) {
+ shiftWindowsLineBreak();
+ yylineno++;
+ } else if (current == '*' && next1 == '/') {
+ state = Start;
+ shift(1);
+ if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2);
+ }
+
+ break;
+ case InIdentifier:
+ if (isIdentLetter(current) || isDecimalDigit(current)) {
+ record16(current);
+ break;
+ } else if (current == '\\' && next1 == 'u') {
+ identifierWithEscapedUnicode = true;
+ shift(2); // skip the unicode escape prefix `\u'
+
+ if (isHexDigit(current) && isHexDigit(next1) &&
+ isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ break;
+ } else {
+ setDone(Bad);
+ err = IllegalUnicodeEscapeSequence;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
+ break;
+ }
+ }
+ setDone(Identifier);
+ break;
+ case InNum0:
+ if (current == 'x' || current == 'X') {
+ record8(current);
+ state = InHex;
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else if (isOctalDigit(current)) {
+ record8(current);
+ state = InOctal;
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InHex:
+ if (isHexDigit(current))
+ record8(current);
+ else
+ setDone(Hex);
+ break;
+ case InOctal:
+ if (isOctalDigit(current)) {
+ record8(current);
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else {
+ setDone(Octal);
+ }
+ break;
+ case InNum:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InDecimal:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InExponentIndicator:
+ if (current == '+' || current == '-') {
+ record8(current);
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InExponent;
+ } else {
+ setDone(Bad);
+ err = IllegalExponentIndicator;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number");
+ }
+ break;
+ case InExponent:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else {
+ setDone(Number);
+ }
+ break;
+ default:
+ Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
+ }
+
+ // move on to the next character
+ if (!done)
+ shift(1);
+ if (state != Start && state != InSingleLineComment)
+ bol = false;
+ }
+
+ // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
+ if ((state == Number || state == Octal || state == Hex)
+ && isIdentLetter(current)) {
+ state = Bad;
+ err = IllegalIdentifier;
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Identifier cannot start with numeric literal");
+ }
+
+ // terminate string
+ buffer8[pos8] = '\0';
+
+ double dval = 0;
+ if (state == Number) {
+ dval = qstrtod(buffer8, 0, 0);
+ } else if (state == Hex) { // scan hex numbers
+ dval = integerFromString(buffer8, pos8, 16);
+ state = Number;
+ } else if (state == Octal) { // scan octal number
+ dval = integerFromString(buffer8, pos8, 8);
+ state = Number;
+ }
+
+ restrKeyword = false;
+ delimited = false;
+
+ switch (parenthesesState) {
+ case IgnoreParentheses:
+ break;
+ case CountParentheses:
+ if (token == QDeclarativeJSGrammar::T_RPAREN) {
+ --parenthesesCount;
+ if (parenthesesCount == 0)
+ parenthesesState = BalancedParentheses;
+ } else if (token == QDeclarativeJSGrammar::T_LPAREN) {
+ ++parenthesesCount;
+ }
+ break;
+ case BalancedParentheses:
+ parenthesesState = IgnoreParentheses;
+ break;
+ }
+
+ switch (state) {
+ case Eof:
+ return 0;
+ case Other:
+ if (token == QDeclarativeJSGrammar::T_RBRACE || token == QDeclarativeJSGrammar::T_SEMICOLON)
+ delimited = true;
+ return token;
+ case Identifier:
+ token = -1;
+ if (! identifierWithEscapedUnicode)
+ token = findReservedWord(buffer16, pos16);
+
+ if (token < 0) {
+ /* TODO: close leak on parse error. same holds true for String */
+ if (driver)
+ qsyylval.ustr = driver->intern(buffer16, pos16);
+ else
+ qsyylval.ustr = 0;
+ return QDeclarativeJSGrammar::T_IDENTIFIER;
+ }
+ if (token == QDeclarativeJSGrammar::T_CONTINUE || token == QDeclarativeJSGrammar::T_BREAK
+ || token == QDeclarativeJSGrammar::T_RETURN || token == QDeclarativeJSGrammar::T_THROW) {
+ restrKeyword = true;
+ } else if (token == QDeclarativeJSGrammar::T_IF || token == QDeclarativeJSGrammar::T_FOR
+ || token == QDeclarativeJSGrammar::T_WHILE || token == QDeclarativeJSGrammar::T_WITH) {
+ parenthesesState = CountParentheses;
+ parenthesesCount = 0;
+ } else if (token == QDeclarativeJSGrammar::T_DO) {
+ parenthesesState = BalancedParentheses;
+ }
+ return token;
+ case String:
+ if (driver)
+ qsyylval.ustr = driver->intern(buffer16, pos16);
+ else
+ qsyylval.ustr = 0;
+ return multiLineString?QDeclarativeJSGrammar::T_MULTILINE_STRING_LITERAL:QDeclarativeJSGrammar::T_STRING_LITERAL;
+ case Number:
+ qsyylval.dval = dval;
+ return QDeclarativeJSGrammar::T_NUMERIC_LITERAL;
+ case Bad:
+ return -1;
+ default:
+ Q_ASSERT(!"unhandled numeration value in switch");
+ return -1;
+ }
+}
+
+bool Lexer::isWhiteSpace() const
+{
+ return (current == ' ' || current == '\t' ||
+ current == 0x0b || current == 0x0c);
+}
+
+bool Lexer::isLineTerminator() const
+{
+ return (current == '\n' || current == '\r');
+}
+
+bool Lexer::isIdentLetter(ushort c)
+{
+ // ASCII-biased, since all reserved words are ASCII, aand hence the
+ // bulk of content to be parsed.
+ if ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || c == '$'
+ || c == '_')
+ return true;
+ if (c < 128)
+ return false;
+ return QChar(c).isLetterOrNumber();
+}
+
+bool Lexer::isDecimalDigit(ushort c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+bool Lexer::isHexDigit(ushort c) const
+{
+ return ((c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F'));
+}
+
+bool Lexer::isOctalDigit(ushort c) const
+{
+ return (c >= '0' && c <= '7');
+}
+
+int Lexer::matchPunctuator(ushort c1, ushort c2,
+ ushort c3, ushort c4)
+{
+ if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
+ shift(4);
+ return QDeclarativeJSGrammar::T_GT_GT_GT_EQ;
+ } else if (c1 == '=' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return QDeclarativeJSGrammar::T_EQ_EQ_EQ;
+ } else if (c1 == '!' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return QDeclarativeJSGrammar::T_NOT_EQ_EQ;
+ } else if (c1 == '>' && c2 == '>' && c3 == '>') {
+ shift(3);
+ return QDeclarativeJSGrammar::T_GT_GT_GT;
+ } else if (c1 == '<' && c2 == '<' && c3 == '=') {
+ shift(3);
+ return QDeclarativeJSGrammar::T_LT_LT_EQ;
+ } else if (c1 == '>' && c2 == '>' && c3 == '=') {
+ shift(3);
+ return QDeclarativeJSGrammar::T_GT_GT_EQ;
+ } else if (c1 == '<' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_LE;
+ } else if (c1 == '>' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_GE;
+ } else if (c1 == '!' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_NOT_EQ;
+ } else if (c1 == '+' && c2 == '+') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_PLUS_PLUS;
+ } else if (c1 == '-' && c2 == '-') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_MINUS_MINUS;
+ } else if (c1 == '=' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_EQ_EQ;
+ } else if (c1 == '+' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_PLUS_EQ;
+ } else if (c1 == '-' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_MINUS_EQ;
+ } else if (c1 == '*' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_STAR_EQ;
+ } else if (c1 == '/' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_DIVIDE_EQ;
+ } else if (c1 == '&' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_AND_EQ;
+ } else if (c1 == '^' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_XOR_EQ;
+ } else if (c1 == '%' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_REMAINDER_EQ;
+ } else if (c1 == '|' && c2 == '=') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_OR_EQ;
+ } else if (c1 == '<' && c2 == '<') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_LT_LT;
+ } else if (c1 == '>' && c2 == '>') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_GT_GT;
+ } else if (c1 == '&' && c2 == '&') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_AND_AND;
+ } else if (c1 == '|' && c2 == '|') {
+ shift(2);
+ return QDeclarativeJSGrammar::T_OR_OR;
+ }
+
+ switch(c1) {
+ case '=': shift(1); return QDeclarativeJSGrammar::T_EQ;
+ case '>': shift(1); return QDeclarativeJSGrammar::T_GT;
+ case '<': shift(1); return QDeclarativeJSGrammar::T_LT;
+ case ',': shift(1); return QDeclarativeJSGrammar::T_COMMA;
+ case '!': shift(1); return QDeclarativeJSGrammar::T_NOT;
+ case '~': shift(1); return QDeclarativeJSGrammar::T_TILDE;
+ case '?': shift(1); return QDeclarativeJSGrammar::T_QUESTION;
+ case ':': shift(1); return QDeclarativeJSGrammar::T_COLON;
+ case '.': shift(1); return QDeclarativeJSGrammar::T_DOT;
+ case '+': shift(1); return QDeclarativeJSGrammar::T_PLUS;
+ case '-': shift(1); return QDeclarativeJSGrammar::T_MINUS;
+ case '*': shift(1); return QDeclarativeJSGrammar::T_STAR;
+ case '/': shift(1); return QDeclarativeJSGrammar::T_DIVIDE_;
+ case '&': shift(1); return QDeclarativeJSGrammar::T_AND;
+ case '|': shift(1); return QDeclarativeJSGrammar::T_OR;
+ case '^': shift(1); return QDeclarativeJSGrammar::T_XOR;
+ case '%': shift(1); return QDeclarativeJSGrammar::T_REMAINDER;
+ case '(': shift(1); return QDeclarativeJSGrammar::T_LPAREN;
+ case ')': shift(1); return QDeclarativeJSGrammar::T_RPAREN;
+ case '{': shift(1); return QDeclarativeJSGrammar::T_LBRACE;
+ case '}': shift(1); return QDeclarativeJSGrammar::T_RBRACE;
+ case '[': shift(1); return QDeclarativeJSGrammar::T_LBRACKET;
+ case ']': shift(1); return QDeclarativeJSGrammar::T_RBRACKET;
+ case ';': shift(1); return QDeclarativeJSGrammar::T_SEMICOLON;
+
+ default: return -1;
+ }
+}
+
+ushort Lexer::singleEscape(ushort c) const
+{
+ switch(c) {
+ case 'b':
+ return 0x08;
+ case 't':
+ return 0x09;
+ case 'n':
+ return 0x0A;
+ case 'v':
+ return 0x0B;
+ case 'f':
+ return 0x0C;
+ case 'r':
+ return 0x0D;
+ case '"':
+ return 0x22;
+ case '\'':
+ return 0x27;
+ case '\\':
+ return 0x5C;
+ default:
+ return c;
+ }
+}
+
+ushort Lexer::convertOctal(ushort c1, ushort c2,
+ ushort c3) const
+{
+ return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
+}
+
+unsigned char Lexer::convertHex(ushort c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+unsigned char Lexer::convertHex(ushort c1, ushort c2)
+{
+ return ((convertHex(c1) << 4) + convertHex(c2));
+}
+
+QChar Lexer::convertUnicode(ushort c1, ushort c2,
+ ushort c3, ushort c4)
+{
+ return QChar((convertHex(c3) << 4) + convertHex(c4),
+ (convertHex(c1) << 4) + convertHex(c2));
+}
+
+void Lexer::record8(ushort c)
+{
+ Q_ASSERT(c <= 0xff);
+
+ // enlarge buffer if full
+ if (pos8 >= size8 - 1) {
+ char *tmp = new char[2 * size8];
+ memcpy(tmp, buffer8, size8 * sizeof(char));
+ delete [] buffer8;
+ buffer8 = tmp;
+ size8 *= 2;
+ }
+
+ buffer8[pos8++] = (char) c;
+}
+
+void Lexer::record16(QChar c)
+{
+ // enlarge buffer if full
+ if (pos16 >= size16 - 1) {
+ QChar *tmp = new QChar[2 * size16];
+ memcpy(tmp, buffer16, size16 * sizeof(QChar));
+ delete [] buffer16;
+ buffer16 = tmp;
+ size16 *= 2;
+ }
+
+ buffer16[pos16++] = c;
+}
+
+void Lexer::recordStartPos()
+{
+ startpos = pos;
+ startlineno = yylineno;
+ startcolumn = yycolumn;
+}
+
+bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
+{
+ pos16 = 0;
+ pattern = 0;
+
+ if (prefix == EqualPrefix)
+ record16(QLatin1Char('='));
+
+ while (true) {
+ switch (current) {
+
+ case 0: // eof
+ case '\n': case '\r': // line terminator
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression literal");
+ return false;
+
+ case '/':
+ shift(1);
+
+ if (driver) // create the pattern
+ pattern = driver->intern(buffer16, pos16);
+
+ // scan the flags
+ pos16 = 0;
+ flags = 0;
+ while (isIdentLetter(current)) {
+ int flag = Ecma::RegExp::flagFromChar(current);
+ if (flag == 0) {
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(current));
+ return false;
+ }
+ flags |= flag;
+ record16(current);
+ shift(1);
+ }
+ return true;
+
+ case '\\':
+ // regular expression backslash sequence
+ record16(current);
+ shift(1);
+
+ if (! current || isLineTerminator()) {
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ record16(current);
+ shift(1);
+ break;
+
+ case '[':
+ // regular expression class
+ record16(current);
+ shift(1);
+
+ while (current && ! isLineTerminator()) {
+ if (current == ']')
+ break;
+ else if (current == '\\') {
+ // regular expression backslash sequence
+ record16(current);
+ shift(1);
+
+ if (! current || isLineTerminator()) {
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ record16(current);
+ shift(1);
+ } else {
+ record16(current);
+ shift(1);
+ }
+ }
+
+ if (current != ']') {
+ errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression class");
+ return false;
+ }
+
+ record16(current);
+ shift(1); // skip ]
+ break;
+
+ default:
+ record16(current);
+ shift(1);
+ } // switch
+ } // while
+
+ return false;
+}
+
+void Lexer::syncProhibitAutomaticSemicolon()
+{
+ if (parenthesesState == BalancedParentheses) {
+ // we have seen something like "if (foo)", which means we should
+ // never insert an automatic semicolon at this point, since it would
+ // then be expanded into an empty statement (ECMA-262 7.9.1)
+ prohibitAutomaticSemicolon = true;
+ parenthesesState = IgnoreParentheses;
+ } else {
+ prohibitAutomaticSemicolon = false;
+ }
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/declarative/qml/parser/qdeclarativejslexer_p.h b/src/declarative/qml/parser/qdeclarativejslexer_p.h
new file mode 100644
index 0000000000..e41337dd8b
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejslexer_p.h
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSLEXER_P_H
+#define QDECLARATIVEJSLEXER_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/qdeclarativejsglobal_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Lexer
+{
+public:
+ Lexer(Engine *eng, bool tokenizeComments = false);
+ ~Lexer();
+
+ void setCode(const QString &c, int lineno);
+ int lex();
+
+ int currentLineNo() const { return yylineno; }
+ int currentColumnNo() const { return yycolumn; }
+
+ int tokenOffset() const { return startpos; }
+ int tokenLength() const { return pos - startpos; }
+
+ int startLineNo() const { return startlineno; }
+ int startColumnNo() const { return startcolumn; }
+
+ int endLineNo() const { return currentLineNo(); }
+ int endColumnNo() const
+ { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; }
+
+ bool prevTerminator() const { return terminator; }
+
+ enum State { Start,
+ Identifier,
+ InIdentifier,
+ InSingleLineComment,
+ InMultiLineComment,
+ InNum,
+ InNum0,
+ InHex,
+ InOctal,
+ InDecimal,
+ InExponentIndicator,
+ InExponent,
+ Hex,
+ Octal,
+ Number,
+ String,
+ Eof,
+ InString,
+ InEscapeSequence,
+ InHexEscape,
+ InUnicodeEscape,
+ Other,
+ Bad };
+
+ enum Error {
+ NoError,
+ IllegalCharacter,
+ UnclosedStringLiteral,
+ IllegalEscapeSequence,
+ IllegalUnicodeEscapeSequence,
+ UnclosedComment,
+ IllegalExponentIndicator,
+ IllegalIdentifier
+ };
+
+ enum ParenthesesState {
+ IgnoreParentheses,
+ CountParentheses,
+ BalancedParentheses
+ };
+
+ enum RegExpBodyPrefix {
+ NoPrefix,
+ EqualPrefix
+ };
+
+ bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
+
+ NameId *pattern;
+ int flags;
+
+ State lexerState() const
+ { return state; }
+
+ QString errorMessage() const
+ { return errmsg; }
+ void setErrorMessage(const QString &err)
+ { errmsg = err; }
+ void setErrorMessage(const char *err)
+ { setErrorMessage(QString::fromLatin1(err)); }
+
+ Error error() const
+ { return err; }
+ void clearError()
+ { err = NoError; }
+
+private:
+ Engine *driver;
+ int yylineno;
+ bool done;
+ char *buffer8;
+ QChar *buffer16;
+ uint size8, size16;
+ uint pos8, pos16;
+ bool terminator;
+ bool restrKeyword;
+ // encountered delimiter like "'" and "}" on last run
+ bool delimited;
+ int stackToken;
+
+ State state;
+ void setDone(State s);
+ uint pos;
+ void shift(uint p);
+ int lookupKeyword(const char *);
+
+ bool isWhiteSpace() const;
+ bool isLineTerminator() const;
+ bool isHexDigit(ushort c) const;
+ bool isOctalDigit(ushort c) const;
+
+ int matchPunctuator(ushort c1, ushort c2,
+ ushort c3, ushort c4);
+ ushort singleEscape(ushort c) const;
+ ushort convertOctal(ushort c1, ushort c2,
+ ushort c3) const;
+public:
+ static unsigned char convertHex(ushort c1);
+ static unsigned char convertHex(ushort c1, ushort c2);
+ static QChar convertUnicode(ushort c1, ushort c2,
+ ushort c3, ushort c4);
+ static bool isIdentLetter(ushort c);
+ static bool isDecimalDigit(ushort c);
+
+ inline int ival() const { return qsyylval.ival; }
+ inline double dval() const { return qsyylval.dval; }
+ inline NameId *ustr() const { return qsyylval.ustr; }
+
+ const QChar *characterBuffer() const { return buffer16; }
+ int characterCount() const { return pos16; }
+
+private:
+ void record8(ushort c);
+ void record16(QChar c);
+ void recordStartPos();
+
+ int findReservedWord(const QChar *buffer, int size) const;
+
+ void syncProhibitAutomaticSemicolon();
+
+ const QChar *code;
+ uint length;
+ int yycolumn;
+ int startpos;
+ int startlineno;
+ int startcolumn;
+ int bol; // begin of line
+
+ union {
+ int ival;
+ double dval;
+ NameId *ustr;
+ } qsyylval;
+
+ // current and following unicode characters
+ ushort current, next1, next2, next3;
+
+ struct keyword {
+ const char *name;
+ int token;
+ };
+
+ QString errmsg;
+ Error err;
+
+ bool wantRx;
+ bool check_reserved;
+
+ ParenthesesState parenthesesState;
+ int parenthesesCount;
+ bool prohibitAutomaticSemicolon;
+ bool tokenizeComments;
+};
+
+} // namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h
new file mode 100644
index 0000000000..7eea9750a3
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.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 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 QDECLARATIVEJSMEMORYPOOL_P_H
+#define QDECLARATIVEJSMEMORYPOOL_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/qdeclarativejsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+
+#include <string.h>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+class QML_PARSER_EXPORT MemoryPool : public QSharedData
+{
+public:
+ enum { maxBlockCount = -1 };
+ enum { defaultBlockSize = 1 << 12 };
+
+ MemoryPool() {
+ m_blockIndex = maxBlockCount;
+ m_currentIndex = 0;
+ m_storage = 0;
+ m_currentBlock = 0;
+ m_currentBlockSize = 0;
+ }
+
+ virtual ~MemoryPool() {
+ for (int index = 0; index < m_blockIndex + 1; ++index)
+ qFree(m_storage[index]);
+
+ qFree(m_storage);
+ }
+
+ char *allocate(int bytes) {
+ bytes += (8 - bytes) & 7; // ensure multiple of 8 bytes (maintain alignment)
+ if (m_currentBlock == 0 || m_currentBlockSize < m_currentIndex + bytes) {
+ ++m_blockIndex;
+ m_currentBlockSize = defaultBlockSize << m_blockIndex;
+
+ m_storage = reinterpret_cast<char**>(qRealloc(m_storage, sizeof(char*) * (1 + m_blockIndex)));
+ m_currentBlock = m_storage[m_blockIndex] = reinterpret_cast<char*>(qMalloc(m_currentBlockSize));
+ ::memset(m_currentBlock, 0, m_currentBlockSize);
+
+ m_currentIndex = (8 - quintptr(m_currentBlock)) & 7; // ensure first chunk is 64-bit aligned
+ Q_ASSERT(m_currentIndex + bytes <= m_currentBlockSize);
+ }
+
+ char *p = reinterpret_cast<char *>
+ (m_currentBlock + m_currentIndex);
+
+ m_currentIndex += bytes;
+
+ return p;
+ }
+
+ int bytesAllocated() const {
+ int bytes = 0;
+ for (int index = 0; index < m_blockIndex; ++index)
+ bytes += (defaultBlockSize << index);
+ bytes += m_currentIndex;
+ return bytes;
+ }
+
+private:
+ int m_blockIndex;
+ int m_currentIndex;
+ char *m_currentBlock;
+ int m_currentBlockSize;
+ char **m_storage;
+
+private:
+ Q_DISABLE_COPY(MemoryPool)
+};
+
+} // namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/parser/qdeclarativejsnodepool_p.h b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h
new file mode 100644
index 0000000000..fde4897873
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEJSNODEPOOL_P_H
+#define QDECLARATIVEJSNODEPOOL_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/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsmemorypool_p.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+namespace AST {
+class Node;
+} // namespace AST
+
+class Code;
+class CompilationUnit;
+class Engine;
+
+template <typename NodeType>
+inline NodeType *makeAstNode(MemoryPool *storage)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType();
+ return node;
+}
+
+template <typename NodeType, typename Arg1>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2, typename Arg3>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3);
+ return node;
+}
+
+template <typename NodeType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+{
+ NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3, arg4);
+ return node;
+}
+
+class QML_PARSER_EXPORT NodePool : public MemoryPool
+{
+public:
+ NodePool(const QString &fileName, Engine *engine);
+ virtual ~NodePool();
+
+ Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation);
+
+ inline QString fileName() const { return m_fileName; }
+ inline Engine *engine() const { return m_engine; }
+#ifndef J_SCRIPT_NO_EVENT_NOTIFY
+ inline qint64 id() const { return m_id; }
+#endif
+
+private:
+ QHash<AST::Node*, Code*> m_codeCache;
+ QString m_fileName;
+ Engine *m_engine;
+#ifndef J_SCRIPT_NO_EVENT_NOTIFY
+ qint64 m_id;
+#endif
+
+private:
+ Q_DISABLE_COPY(NodePool)
+};
+
+} // namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/parser/qdeclarativejsparser.cpp b/src/declarative/qml/parser/qdeclarativejsparser.cpp
new file mode 100644
index 0000000000..9a93fa1b4c
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsparser.cpp
@@ -0,0 +1,1904 @@
+/****************************************************************************
+**
+** Copyright (C) 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 <QtCore/QtDebug>
+#include <QtGui/QApplication>
+
+#include <string.h>
+
+#include "private/qdeclarativejsengine_p.h"
+#include "private/qdeclarativejslexer_p.h"
+#include "private/qdeclarativejsast_p.h"
+#include "private/qdeclarativejsnodepool_p.h"
+
+
+
+#include "private/qdeclarativejsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QDeclarativeJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+}
+
+inline static bool automatic(Engine *driver, int token)
+{
+ return token == QDeclarativeJSGrammar::T_RBRACE
+ || token == 0
+ || driver->lexer()->prevTerminator();
+}
+
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ qFree(sym_stack);
+ qFree(state_stack);
+ qFree(location_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->startLineNo();
+ loc.startColumn = lexer->startColumnNo();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<NameId *, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->dval();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+
+case 0: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 1: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 2: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 3: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 4: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 5: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 6: {
+ sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+
+case 8: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+
+case 9: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport);
+} break;
+
+case 10: {
+ sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(),
+ sym(1).UiImportList, sym(2).UiImport);
+} break;
+
+case 13: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+
+case 15: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+
+case 17: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = sym(4).sval;
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+
+case 19: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = sym(3).sval;
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+
+case 20: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+
+case 21: {
+ sym(1).Node = 0;
+} break;
+
+case 22: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 23: {
+ sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 24: {
+ AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(),
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+
+case 25: {
+ sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember);
+} break;
+
+case 26: {
+ AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(),
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 27: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 28: {
+ AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 29: {
+ AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+
+case 31: {
+ AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 32: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 33: {
+ AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+case 34:case 35:case 36:case 37:
+{
+ AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(),
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 38:
+
+case 39: {
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+ break;
+}
+
+case 41: {
+ sym(1).Node = 0;
+} break;
+
+case 42: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+
+case 43: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 44: {
+ AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 46: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 48: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval);
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 50: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 52: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 54: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 56: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval,
+ sym(5).Expression);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 58: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Expression);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 60: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval,
+ sym(6).Expression);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 61: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval);
+ node->typeModifier = sym(2).sval;
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval);
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(),
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 62: {
+ AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval);
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(),
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 63: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+
+case 64: {
+ sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node);
+} break;
+
+case 66: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_PROPERTY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 67: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_SIGNAL]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 68: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_READONLY]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 69: {
+ QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_ON]);
+ sym(1).sval = driver->intern(s.constData(), s.length());
+ break;
+}
+
+case 70: {
+ AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool());
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 71: {
+ AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 72: {
+ AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool());
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 73: {
+ AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool());
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 74: {
+ AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool());
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 75: {
+ AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 76:
+case 77: {
+ AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 78: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 79: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+
+ AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 80: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 81: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 82: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 83: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 84: {
+ AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 85: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = makeAstNode<AST::ObjectLiteral> (driver->nodePool());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 86: {
+ AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(),
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 87: {
+ AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 88: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+
+case 89: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression);
+} break;
+
+case 90: {
+ sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression);
+} break;
+
+case 91: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 92: {
+ AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 93: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool());
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 94: {
+ AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 95: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 96: {
+ AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(),
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 97: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 98:
+case 99: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 100: {
+ AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 101: {
+ AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 102: {
+ AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 103:
+
+case 104:
+
+case 105:
+
+case 106:
+
+case 107:
+
+case 108:
+
+case 109:
+
+case 110:
+
+case 111:
+
+case 112:
+
+case 113:
+
+case 114:
+
+case 115:
+
+case 116:
+
+case 117:
+
+case 118:
+
+case 119:
+
+case 120:
+
+case 121:
+
+case 122:
+
+case 123:
+
+case 124:
+
+case 125:
+
+case 126:
+
+case 127:
+
+case 128:
+
+case 129:
+
+case 130:
+
+case 131:
+
+case 132:
+
+case 133:
+{
+ sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount());
+} break;
+
+case 138: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 139: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 140: {
+ AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 142: {
+ AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 143: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 144: {
+ AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 145: {
+ AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 146: {
+ AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval);
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 147: {
+ sym(1).Node = 0;
+} break;
+
+case 148: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+
+case 149: {
+ sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression);
+} break;
+
+case 150: {
+ AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 154: {
+ AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 155: {
+ AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 157: {
+ AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 158: {
+ AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 159: {
+ AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 160: {
+ AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 161: {
+ AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 162: {
+ AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 163: {
+ AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 164: {
+ AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 165: {
+ AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 167: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 168: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 169: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 171: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 172: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 174: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 175: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 176: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 178: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 179: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 180: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 181: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 182: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 183: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 185: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 186: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 187: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 188: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 189: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 191: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 192: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 193: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 194: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 196: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 197: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 198: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 199: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 201: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 203: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 205: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 207: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 209: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 211: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 213: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 215: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 217: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 219: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 221: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 223: {
+ AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 225: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 227: {
+ AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 228: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+
+case 229: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+
+case 230: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+
+case 231: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+
+case 232: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+
+case 233: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+
+case 234: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+
+case 235: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+
+case 236: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+
+case 237: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+
+case 238: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+
+case 239: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+
+case 241: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 242: {
+ sym(1).Node = 0;
+} break;
+
+case 245: {
+ AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 246: {
+ sym(1).Node = 0;
+} break;
+
+case 263: {
+ AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 264: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement);
+} break;
+
+case 265: {
+ sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement);
+} break;
+
+case 266: {
+ sym(1).Node = 0;
+} break;
+
+case 267: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+
+case 269: {
+ AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(),
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 270: {
+ sym(1).ival = T_CONST;
+} break;
+
+case 271: {
+ sym(1).ival = T_VAR;
+} break;
+
+case 272: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+
+case 273: {
+ AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(),
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 274: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration);
+} break;
+
+case 275: {
+ sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+
+case 276: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 277: {
+ AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 278: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 279: {
+ sym(1).Node = 0;
+} break;
+
+case 281: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 282: {
+ sym(1).Node = 0;
+} break;
+
+case 284: {
+ AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool());
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 286: {
+ AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 287: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 288: {
+ AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 290: {
+ AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 291: {
+ AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 292: {
+ AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 293: {
+ AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(),
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+
+case 294: {
+ AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 295: {
+ AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(),
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 297: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool());
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 299: {
+ AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval);
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 301: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 303: {
+ AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval);
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 305: {
+ AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 306: {
+ AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 307: {
+ AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 308: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 309: {
+ AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 310: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause);
+} break;
+
+case 311: {
+ sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+
+case 312: {
+ sym(1).Node = 0;
+} break;
+
+case 313: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+
+case 314: {
+ AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 315: {
+ AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+case 316:
+case 317: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 318: {
+ AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 320: {
+ AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 321: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 322: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 323: {
+ AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 324: {
+ AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 325: {
+ AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 327: {
+ AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool());
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 328: {
+ AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 329: {
+ AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (sym(2).sval)
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 330: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 331: {
+ AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 332: {
+ sym(1).Node = 0;
+} break;
+
+case 333: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+
+case 334: {
+ sym(1).Node = 0;
+} break;
+
+case 336: {
+ sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+
+case 337: {
+ sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ());
+} break;
+
+case 338: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement);
+} break;
+
+case 339: {
+ sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement);
+} break;
+
+case 340: {
+ sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement);
+} break;
+
+case 341: {
+ sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration);
+} break;
+
+case 342: {
+ sym(1).sval = 0;
+} break;
+
+case 344: {
+ sym(1).Node = 0;
+} break;
+
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QDeclarativeParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->dval();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QDeclarativeParser", "Syntax error");
+ else
+ msg = qApp->translate("QDeclarativeParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QDeclarativeParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/declarative/qml/parser/qdeclarativejsparser_p.h b/src/declarative/qml/parser/qdeclarativejsparser_p.h
new file mode 100644
index 0000000000..ad46bfff1d
--- /dev/null
+++ b/src/declarative/qml/parser/qdeclarativejsparser_p.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 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$
+**
+****************************************************************************/
+
+
+//
+// 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.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QDECLARATIVEJSPARSER_P_H
+#define QDECLARATIVEJSPARSER_P_H
+
+#include "private/qdeclarativejsglobal_p.h"
+#include "private/qdeclarativejsgrammar_p.h"
+#include "private/qdeclarativejsast_p.h"
+#include "private/qdeclarativejsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+class Engine;
+class NameId;
+
+class QML_PARSER_EXPORT Parser: protected QDeclarativeJSGrammar
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ NameId *sval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ AST::UiSignature *UiSignature;
+ AST::UiFormalList *UiFormalList;
+ AST::UiFormal *UiFormal;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ };
+
+ double yylval;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QDeclarativeJS
+
+
+
+#define J_SCRIPT_REGEXPLITERAL_RULE1 78
+
+#define J_SCRIPT_REGEXPLITERAL_RULE2 79
+
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QDECLARATIVEJSPARSER_P_H
diff --git a/src/declarative/qml/qbitfield_p.h b/src/declarative/qml/qbitfield_p.h
new file mode 100644
index 0000000000..53f666a675
--- /dev/null
+++ b/src/declarative/qml/qbitfield_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QBITFIELD_P_H
+#define QBITFIELD_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 QBitField
+{
+public:
+ inline QBitField();
+ inline QBitField(const quint32 *, int bits);
+ inline QBitField(const QBitField &);
+ inline ~QBitField();
+
+ inline QBitField &operator=(const QBitField &);
+
+ inline quint32 size() const;
+ inline QBitField united(const QBitField &);
+ inline bool testBit(int) const;
+
+private:
+ quint32 bits:31;
+ quint32 *ownData;
+ const quint32 *data;
+};
+
+QBitField::QBitField()
+: bits(0), ownData(0), data(0)
+{
+}
+
+QBitField::QBitField(const quint32 *bitData, int bitCount)
+: bits((quint32)bitCount), ownData(0), data(bitData)
+{
+}
+
+QBitField::QBitField(const QBitField &other)
+: bits(other.bits), ownData(other.ownData), data(other.data)
+{
+ if (ownData)
+ ++(*ownData);
+}
+
+QBitField::~QBitField()
+{
+ if (ownData)
+ if(0 == --(*ownData)) delete [] ownData;
+}
+
+QBitField &QBitField::operator=(const QBitField &other)
+{
+ if (other.data == data)
+ return *this;
+
+ if (ownData)
+ if(0 == --(*ownData)) delete [] ownData;
+
+ bits = other.bits;
+ ownData = other.ownData;
+ data = other.data;
+
+ if (ownData)
+ ++(*ownData);
+
+ return *this;
+}
+
+inline quint32 QBitField::size() const
+{
+ return bits;
+}
+
+QBitField QBitField::united(const QBitField &o)
+{
+ if (o.bits == 0) {
+ return *this;
+ } else if (bits == 0) {
+ return o;
+ } else {
+ int max = (bits > o.bits)?bits:o.bits;
+ int length = (max + 31) / 32;
+ QBitField rv;
+ rv.bits = max;
+ rv.ownData = new quint32[length + 1];
+ *(rv.ownData) = 1;
+ rv.data = rv.ownData + 1;
+ if (bits > o.bits) {
+ ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32));
+ for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii)
+ ((quint32 *)rv.data)[ii] |= o.data[ii];
+ } else {
+ ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32));
+ for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii)
+ ((quint32 *)rv.data)[ii] |= data[ii];
+ }
+ return rv;
+ }
+}
+
+bool QBitField::testBit(int b) const
+{
+ Q_ASSERT(b >= 0);
+ if ((quint32)b < bits) {
+ return data[b / 32] & (1 << (b % 32));
+ } else {
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QBITFIELD_P_H
diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h
new file mode 100644
index 0000000000..5da7901528
--- /dev/null
+++ b/src/declarative/qml/qdeclarative.h
@@ -0,0 +1,415 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVE_H
+#define QDECLARATIVE_H
+
+#include <QtDeclarative/qdeclarativeprivate.h>
+#include <QtDeclarative/qdeclarativeparserstatus.h>
+#include <QtDeclarative/qdeclarativepropertyvaluesource.h>
+#include <QtDeclarative/qdeclarativepropertyvalueinterceptor.h>
+#include <QtDeclarative/qdeclarativelist.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_HEADER
+
+#define QML_DECLARE_TYPE(TYPE) \
+ Q_DECLARE_METATYPE(TYPE *) \
+ Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>)
+
+#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \
+ Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>)
+
+#define QML_DECLARE_INTERFACE(INTERFACE) \
+ QML_DECLARE_TYPE(INTERFACE)
+
+#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \
+ QML_DECLARE_TYPE_HASMETATYPE(INTERFACE)
+
+enum { /* TYPEINFO flags */
+ QML_HAS_ATTACHED_PROPERTIES = 0x01
+};
+
+#define QML_DECLARE_TYPEINFO(TYPE, FLAGS) \
+QT_BEGIN_NAMESPACE \
+template <> \
+class QDeclarativeTypeInfo<TYPE > \
+{ \
+public: \
+ enum { \
+ hasAttachedProperties = (((FLAGS) & QML_HAS_ATTACHED_PROPERTIES) == QML_HAS_ATTACHED_PROPERTIES) \
+ }; \
+}; \
+QT_END_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+template<typename T>
+int qmlRegisterType()
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ 0, 0,
+ QString(),
+
+ 0, 0, 0, 0, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+int Q_AUTOTEST_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
+
+template<typename T>
+int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ 0, 0,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+template<typename T>
+int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ sizeof(T), QDeclarativePrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+template<typename T, int metaObjectRevision>
+int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 1,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ sizeof(T), QDeclarativePrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ metaObjectRevision
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+template<typename T, int metaObjectRevision>
+int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 1,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ sizeof(T), QDeclarativePrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, 0, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ 0,
+ metaObjectRevision
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+
+template<typename T, typename E>
+int qmlRegisterExtendedType()
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ 0, 0,
+ QString(),
+
+ 0, 0, 0, 0, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ QDeclarativePrivate::createParent<E>, &E::staticMetaObject,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+template<typename T, typename E>
+int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativeAttachedPropertiesFunc attached = QDeclarativePrivate::attachedPropertiesFunc<E>();
+ const QMetaObject * attachedMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<E>();
+ if (!attached) {
+ attached = QDeclarativePrivate::attachedPropertiesFunc<T>();
+ attachedMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<T>();
+ }
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ sizeof(T), QDeclarativePrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ attached,
+ attachedMetaObject,
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ QDeclarativePrivate::createParent<E>, &E::staticMetaObject,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+template<typename T>
+int qmlRegisterInterface(const char *typeName)
+{
+ QByteArray name(typeName);
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterInterface qmlInterface = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+
+ qobject_interface_iid<T *>()
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::InterfaceRegistration, &qmlInterface);
+}
+
+template<typename T>
+int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, QDeclarativeCustomParser *parser)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+ QByteArray listName("QDeclarativeListProperty<" + name + ">");
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()),
+ qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()),
+ sizeof(T), QDeclarativePrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ QDeclarativePrivate::attachedPropertiesFunc<T>(),
+ QDeclarativePrivate::attachedPropertiesMetaObject<T>(),
+
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(),
+ QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(),
+
+ 0, 0,
+
+ parser,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+class QDeclarativeContext;
+class QDeclarativeEngine;
+Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *);
+Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *);
+Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *);
+Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *, const QMetaObject *, bool create);
+
+template<typename T>
+QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
+{
+ static int idx = -1;
+ return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QObject)
+Q_DECLARE_METATYPE(QVariant)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVE_H
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
new file mode 100644
index 0000000000..a5bd604c53
--- /dev/null
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -0,0 +1,570 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativebinding_p.h"
+#include "private/qdeclarativebinding_p_p.h"
+
+#include "qdeclarative.h"
+#include "qdeclarativecontext.h"
+#include "qdeclarativeinfo.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qdeclarativestate_p_p.h"
+#include "private/qdeclarativedebugtrace_p.h"
+
+#include <QVariant>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeAbstractBinding::QDeclarativeAbstractBinding()
+: m_object(0), m_propertyIndex(-1), m_mePtr(0), m_prevBinding(0), m_nextBinding(0)
+{
+}
+
+QDeclarativeAbstractBinding::~QDeclarativeAbstractBinding()
+{
+ Q_ASSERT(m_prevBinding == 0);
+ Q_ASSERT(m_mePtr == 0);
+}
+
+/*!
+Destroy the binding. Use this instead of calling delete.
+
+Bindings are free to implement their own memory management, so the delete operator is not
+necessarily safe. The default implementation clears the binding, removes it from the object
+and calls delete.
+*/
+void QDeclarativeAbstractBinding::destroy()
+{
+ removeFromObject();
+ clear();
+
+ delete this;
+}
+
+/*!
+Add this binding to \a object.
+
+This transfers ownership of the binding to the object, marks the object's property as
+being bound.
+
+However, it does not enable the binding itself or call update() on it.
+*/
+void QDeclarativeAbstractBinding::addToObject(QObject *object, int index)
+{
+ Q_ASSERT(object);
+
+ if (m_object == object && m_propertyIndex == index)
+ return;
+
+ removeFromObject();
+
+ Q_ASSERT(!m_prevBinding);
+
+ m_object = object;
+ m_propertyIndex = index;
+
+ QDeclarativeData *data = QDeclarativeData::get(object, true);
+
+ if (index & 0xFF000000) {
+ // Value type
+
+ int coreIndex = index & 0xFFFFFF;
+
+ // Find the value type proxy (if there is one)
+ QDeclarativeValueTypeProxyBinding *proxy = 0;
+ if (data->hasBindingBit(coreIndex)) {
+ QDeclarativeAbstractBinding *b = data->bindings;
+ while (b && b->propertyIndex() != coreIndex)
+ b = b->m_nextBinding;
+ Q_ASSERT(b && b->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy);
+ proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(b);
+ }
+
+ if (!proxy) {
+ proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex);
+ proxy->addToObject(object, coreIndex);
+ }
+
+ m_nextBinding = proxy->m_bindings;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+ m_prevBinding = &proxy->m_bindings;
+ proxy->m_bindings = this;
+
+ } else {
+ m_nextBinding = data->bindings;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+ m_prevBinding = &data->bindings;
+ data->bindings = this;
+
+ data->setBindingBit(m_object, index);
+ }
+}
+
+/*!
+Remove the binding from the object.
+*/
+void QDeclarativeAbstractBinding::removeFromObject()
+{
+ if (m_prevBinding) {
+ int index = propertyIndex();
+
+ *m_prevBinding = m_nextBinding;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
+ m_prevBinding = 0;
+ m_nextBinding = 0;
+
+ if (index & 0xFF000000) {
+ // Value type - we don't remove the proxy from the object. It will sit their happily
+ // doing nothing until it is removed by a write, a binding change or it is reused
+ // to hold more sub-bindings.
+ } else if (m_object) {
+ QDeclarativeData *data = QDeclarativeData::get(m_object, false);
+ if (data) data->clearBindingBit(index);
+ }
+
+ m_object = 0;
+ m_propertyIndex = -1;
+ }
+}
+
+static void bindingDummyDeleter(QDeclarativeAbstractBinding *)
+{
+}
+
+QDeclarativeAbstractBinding::Pointer QDeclarativeAbstractBinding::weakPointer()
+{
+ if (m_selfPointer.isNull())
+ m_selfPointer = QSharedPointer<QDeclarativeAbstractBinding>(this, bindingDummyDeleter);
+
+ return m_selfPointer.toWeakRef();
+}
+
+void QDeclarativeAbstractBinding::clear()
+{
+ if (m_mePtr) {
+ *m_mePtr = 0;
+ m_mePtr = 0;
+ }
+}
+
+QString QDeclarativeAbstractBinding::expression() const
+{
+ return QLatin1String("<Unknown>");
+}
+
+QObject *QDeclarativeAbstractBinding::object() const
+{
+ return m_object;
+}
+
+int QDeclarativeAbstractBinding::propertyIndex() const
+{
+ return m_propertyIndex;
+}
+
+void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (enabled) update(flags);
+}
+
+QDeclarativeBinding::Identifier QDeclarativeBinding::Invalid = -1;
+
+void QDeclarativeBindingPrivate::refresh()
+{
+ Q_Q(QDeclarativeBinding);
+ q->update();
+}
+
+QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
+: updating(false), enabled(false), deleted(0)
+{
+}
+
+QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate()
+{
+ if (deleted) *deleted = true;
+}
+
+QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj,
+ QDeclarativeContextData *ctxt, const QString &url, int lineNumber,
+ QObject *parent)
+: QDeclarativeExpression(ctxt, data, rc, obj, url, lineNumber, *new QDeclarativeBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QDeclarativeBinding *
+QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt,
+ const QString &url, int lineNumber, QObject *parent)
+{
+ if (id < 0)
+ return 0;
+
+ QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt);
+
+ QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(obj));
+ QDeclarativeCompiledData *cdata = 0;
+ QDeclarativeTypeData *typeData = 0;
+ if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+ typeData = engine->typeLoader.get(ctxtdata->url);
+ cdata = typeData->compiledData();
+ }
+ QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0;
+ if (typeData)
+ typeData->release();
+ return rv;
+}
+
+QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt,
+ QObject *parent)
+: QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContextData *ctxt,
+ QObject *parent)
+: QDeclarativeExpression(ctxt, obj, str, *new QDeclarativeBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QDeclarativeBinding::QDeclarativeBinding(const QScriptValue &func, QObject *obj, QDeclarativeContextData *ctxt, QObject *parent)
+: QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate)
+{
+ setParent(parent);
+ setNotifyOnValueChanged(true);
+}
+
+QDeclarativeBinding::~QDeclarativeBinding()
+{
+}
+
+void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
+{
+ Q_D(QDeclarativeBinding);
+ d->property = prop;
+
+ update();
+}
+
+QDeclarativeProperty QDeclarativeBinding::property() const
+{
+ Q_D(const QDeclarativeBinding);
+ return d->property;
+}
+
+void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags)
+{
+ Q_D(QDeclarativeBinding);
+ d->setEvaluateFlags(QDeclarativeQtScriptExpression::EvaluateFlags(static_cast<int>(flags)));
+}
+
+QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const
+{
+ Q_D(const QDeclarativeBinding);
+ return QDeclarativeBinding::EvaluateFlags(static_cast<int>(d->evaluateFlags()));
+}
+
+
+class QDeclarativeBindingProfiler {
+public:
+ QDeclarativeBindingProfiler(QDeclarativeBinding *bind)
+ {
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression());
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Binding, bind->sourceFile(), bind->lineNumber());
+ }
+
+ ~QDeclarativeBindingProfiler()
+ {
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
+ }
+};
+
+void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ Q_D(QDeclarativeBinding);
+
+ if (!d->enabled || !d->context() || !d->context()->isValid())
+ return;
+
+ if (!d->updating) {
+ QDeclarativeBindingProfiler prof(this);
+ d->updating = true;
+ bool wasDeleted = false;
+ d->deleted = &wasDeleted;
+
+ if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
+
+ int idx = d->property.index();
+ Q_ASSERT(idx != -1);
+
+ QDeclarativeBinding *t = this;
+ int status = -1;
+ void *a[] = { &t, 0, &status, &flags };
+ QMetaObject::metacall(d->property.object(),
+ QMetaObject::WriteProperty,
+ idx, a);
+
+ if (wasDeleted)
+ return;
+
+ } else {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
+
+ bool isUndefined = false;
+ QVariant value;
+
+ QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
+ if (wasDeleted)
+ return;
+
+ if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
+ value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
+ } else if (scriptValue.isNull() &&
+ d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
+ value = QVariant::fromValue((QObject *)0);
+ } else {
+ value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
+ if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
+ // If the object is null, we extract the predicted type. While this isn't
+ // 100% reliable, in many cases it gives us better error messages if we
+ // assign this null-object to an incompatible property
+ int type = ep->objectClass->objectType(scriptValue);
+ QObject *o = 0;
+ value = QVariant(type, (void *)&o);
+ }
+ }
+
+
+ if (d->error.isValid()) {
+
+ } else if (isUndefined && d->property.isResettable()) {
+
+ d->property.reset();
+
+ } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) {
+
+ QDeclarativePropertyPrivate::write(d->property, QVariant(), flags);
+
+ } else if (isUndefined) {
+
+ QUrl url = QUrl(d->url);
+ int line = d->line;
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(d->property.propertyType())) +
+ QLatin1String(" ") + d->property.name());
+
+ } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
+
+ QUrl url = QUrl(d->url);
+ int line = d->line;
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign a function to a property."));
+
+ } else if (d->property.object() &&
+ !QDeclarativePropertyPrivate::write(d->property, value, flags)) {
+
+ if (wasDeleted)
+ return;
+
+ QUrl url = QUrl(d->url);
+ int line = d->line;
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ const char *valueType = 0;
+ if (value.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(value.userType());
+
+ d->error.setUrl(url);
+ d->error.setLine(line);
+ d->error.setColumn(-1);
+ d->error.setDescription(QLatin1String("Unable to assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(d->property.propertyType())));
+ }
+
+ if (wasDeleted)
+ return;
+
+ if (d->error.isValid()) {
+ if (!d->addError(ep)) ep->warning(this->error());
+ } else {
+ d->removeError();
+ }
+ }
+
+ d->updating = false;
+ d->deleted = 0;
+ } else {
+ qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name());
+ }
+}
+
+void QDeclarativeBindingPrivate::emitValueChanged()
+{
+ Q_Q(QDeclarativeBinding);
+ q->update();
+}
+
+void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ Q_D(QDeclarativeBinding);
+ d->enabled = e;
+ setNotifyOnValueChanged(e);
+
+ if (e)
+ update(flags);
+}
+
+bool QDeclarativeBinding::enabled() const
+{
+ Q_D(const QDeclarativeBinding);
+
+ return d->enabled;
+}
+
+QString QDeclarativeBinding::expression() const
+{
+ return QDeclarativeExpression::expression();
+}
+
+QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
+: m_object(o), m_index(index), m_bindings(0)
+{
+}
+
+QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding()
+{
+ while (m_bindings) {
+ QDeclarativeAbstractBinding *binding = m_bindings;
+ binding->setEnabled(false, 0);
+ binding->destroy();
+ }
+}
+
+void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (e) {
+ QDeclarativeAbstractBinding *bindings = m_bindings;
+ recursiveEnable(bindings, flags);
+ } else {
+ QDeclarativeAbstractBinding *bindings = m_bindings;
+ recursiveDisable(bindings);
+ }
+}
+
+void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ if (!b)
+ return;
+
+ recursiveEnable(b->m_nextBinding, flags);
+
+ if (b)
+ b->setEnabled(true, flags);
+}
+
+void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b)
+{
+ if (!b)
+ return;
+
+ recursiveDisable(b->m_nextBinding);
+
+ if (b)
+ b->setEnabled(false, 0);
+}
+
+void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
+{
+}
+
+QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
+{
+ QDeclarativeAbstractBinding *binding = m_bindings;
+
+ while (binding && binding->propertyIndex() != propertyIndex)
+ binding = binding->m_nextBinding;
+
+ return binding;
+}
+
+/*!
+Removes a collection of bindings, corresponding to the set bits in \a mask.
+*/
+void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask)
+{
+ QDeclarativeAbstractBinding *binding = m_bindings;
+ while (binding) {
+ if (mask & (1 << (binding->propertyIndex() >> 24))) {
+ QDeclarativeAbstractBinding *remove = binding;
+ binding = remove->m_nextBinding;
+ *remove->m_prevBinding = remove->m_nextBinding;
+ if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
+ remove->m_prevBinding = 0;
+ remove->m_nextBinding = 0;
+ remove->destroy();
+ } else {
+ binding = binding->m_nextBinding;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h
new file mode 100644
index 0000000000..0260b95fb8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativebinding_p.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 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 QDECLARATIVEBINDING_P_H
+#define QDECLARATIVEBINDING_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 "qdeclarativepropertyvaluesource.h"
+#include "qdeclarativeexpression.h"
+#include "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaProperty>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAbstractBinding
+{
+public:
+ typedef QWeakPointer<QDeclarativeAbstractBinding> Pointer;
+
+ QDeclarativeAbstractBinding();
+
+ virtual void destroy();
+
+ virtual QString expression() const;
+
+ enum Type { PropertyBinding, ValueTypeProxy };
+ virtual Type bindingType() const { return PropertyBinding; }
+
+ QObject *object() const;
+ int propertyIndex() const;
+
+ void setEnabled(bool e) { setEnabled(e, QDeclarativePropertyPrivate::DontRemoveBinding); }
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags) = 0;
+
+ void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); }
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags) = 0;
+
+ void addToObject(QObject *, int);
+ void removeFromObject();
+
+ static Pointer getPointer(QDeclarativeAbstractBinding *p) { return p ? p->weakPointer() : Pointer(); }
+
+protected:
+ virtual ~QDeclarativeAbstractBinding();
+ void clear();
+
+private:
+ Pointer weakPointer();
+
+ friend class QDeclarativeData;
+ friend class QDeclarativeComponentPrivate;
+ friend class QDeclarativeValueTypeProxyBinding;
+ friend class QDeclarativePropertyPrivate;
+ friend class QDeclarativeVME;
+ friend class QtSharedPointer::ExternalRefCount<QDeclarativeAbstractBinding>;
+
+ QObject *m_object;
+ int m_propertyIndex;
+ QDeclarativeAbstractBinding **m_mePtr;
+ QDeclarativeAbstractBinding **m_prevBinding;
+ QDeclarativeAbstractBinding *m_nextBinding;
+ QSharedPointer<QDeclarativeAbstractBinding> m_selfPointer;
+};
+
+class QDeclarativeValueTypeProxyBinding : public QDeclarativeAbstractBinding
+{
+public:
+ QDeclarativeValueTypeProxyBinding(QObject *o, int coreIndex);
+
+ virtual Type bindingType() const { return ValueTypeProxy; }
+
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags);
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags);
+
+ QDeclarativeAbstractBinding *binding(int propertyIndex);
+
+ void removeBindings(quint32 mask);
+
+protected:
+ ~QDeclarativeValueTypeProxyBinding();
+
+private:
+ void recursiveEnable(QDeclarativeAbstractBinding *, QDeclarativePropertyPrivate::WriteFlags);
+ void recursiveDisable(QDeclarativeAbstractBinding *);
+
+ friend class QDeclarativeAbstractBinding;
+ QObject *m_object;
+ int m_index;
+ QDeclarativeAbstractBinding *m_bindings;
+};
+
+class QDeclarativeContext;
+class QDeclarativeBindingPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeBinding : public QDeclarativeExpression, public QDeclarativeAbstractBinding
+{
+Q_OBJECT
+public:
+ enum EvaluateFlag { RequiresThisObject = 0x01 };
+ Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag)
+
+ QDeclarativeBinding(const QString &, QObject *, QDeclarativeContext *, QObject *parent=0);
+ QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0);
+ QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *,
+ const QString &, int, QObject *parent);
+ QDeclarativeBinding(const QScriptValue &, QObject *, QDeclarativeContextData *, QObject *parent=0);
+
+ void setTarget(const QDeclarativeProperty &);
+ QDeclarativeProperty property() const;
+
+ void setEvaluateFlags(EvaluateFlags flags);
+ EvaluateFlags evaluateFlags() const;
+
+ bool enabled() const;
+
+ // Inherited from QDeclarativeAbstractBinding
+ virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
+ virtual QString expression() const;
+
+ typedef int Identifier;
+ static Identifier Invalid;
+ static QDeclarativeBinding *createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0);
+
+public Q_SLOTS:
+ void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); }
+
+protected:
+ ~QDeclarativeBinding();
+ void emitValueChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeBinding)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeBinding::EvaluateFlags)
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeBinding*)
+
+#endif // QDECLARATIVEBINDING_P_H
diff --git a/src/declarative/qml/qdeclarativebinding_p_p.h b/src/declarative/qml/qdeclarativebinding_p_p.h
new file mode 100644
index 0000000000..b80818a6ce
--- /dev/null
+++ b/src/declarative/qml/qdeclarativebinding_p_p.h
@@ -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 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 QDECLARATIVEBINDING_P_P_H
+#define QDECLARATIVEBINDING_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/qdeclarativebinding_p.h"
+
+#include "qdeclarativeproperty.h"
+#include "private/qdeclarativeexpression_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBindingPrivate : public QDeclarativeExpressionPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeBinding)
+public:
+ QDeclarativeBindingPrivate();
+ ~QDeclarativeBindingPrivate();
+
+ virtual void emitValueChanged();
+
+protected:
+ virtual void refresh();
+
+private:
+ bool updating:1;
+ bool enabled:1;
+ QDeclarativeProperty property;
+
+ bool *deleted;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEBINDING_P_P_H
diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp
new file mode 100644
index 0000000000..47a15cb0ce
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeboundsignal.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeboundsignal_p.h"
+
+#include "private/qmetaobjectbuilder_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "qdeclarative.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativedebugtrace_p.h"
+
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBoundSignalParameters : public QObject
+{
+Q_OBJECT
+public:
+ QDeclarativeBoundSignalParameters(const QMetaMethod &, QObject * = 0);
+ ~QDeclarativeBoundSignalParameters();
+
+ void setValues(void **);
+ void clearValues();
+
+private:
+ friend class MetaObject;
+ int metaCall(QMetaObject::Call, int _id, void **);
+ struct MetaObject : public QAbstractDynamicMetaObject {
+ MetaObject(QDeclarativeBoundSignalParameters *b)
+ : parent(b) {}
+
+ int metaCall(QMetaObject::Call c, int id, void **a) {
+ return parent->metaCall(c, id, a);
+ }
+ QDeclarativeBoundSignalParameters *parent;
+ };
+
+ int *types;
+ void **values;
+ QMetaObject *myMetaObject;
+};
+
+static int evaluateIdx = -1;
+
+QDeclarativeAbstractBoundSignal::QDeclarativeAbstractBoundSignal(QObject *parent)
+: QObject(parent)
+{
+}
+
+QDeclarativeAbstractBoundSignal::~QDeclarativeAbstractBoundSignal()
+{
+}
+
+QDeclarativeBoundSignal::QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal,
+ QObject *parent)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+{
+ // This is thread safe. Although it may be updated by two threads, they
+ // will both set it to the same value - so the worst thing that can happen
+ // is that they both do the work to figure it out. Boo hoo.
+ if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
+
+ QDeclarative_setParent_noEvent(this, parent);
+ QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+}
+
+QDeclarativeBoundSignal::QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val,
+ QObject *scope, const QMetaMethod &signal,
+ QObject *parent)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+{
+ // This is thread safe. Although it may be updated by two threads, they
+ // will both set it to the same value - so the worst thing that can happen
+ // is that they both do the work to figure it out. Boo hoo.
+ if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
+
+ QDeclarative_setParent_noEvent(this, parent);
+ QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+
+ m_expression = new QDeclarativeExpression(ctxt, scope, val);
+}
+
+QDeclarativeBoundSignal::~QDeclarativeBoundSignal()
+{
+ delete m_expression;
+ m_expression = 0;
+}
+
+int QDeclarativeBoundSignal::index() const
+{
+ return m_signal.methodIndex();
+}
+
+/*!
+ Returns the signal expression.
+*/
+QDeclarativeExpression *QDeclarativeBoundSignal::expression() const
+{
+ return m_expression;
+}
+
+/*!
+ Sets the signal expression to \a e. Returns the current signal expression,
+ or null if there is no signal expression.
+
+ The QDeclarativeBoundSignal instance takes ownership of \a e. The caller is
+ assumes ownership of the returned QDeclarativeExpression.
+*/
+QDeclarativeExpression *QDeclarativeBoundSignal::setExpression(QDeclarativeExpression *e)
+{
+ QDeclarativeExpression *rv = m_expression;
+ m_expression = e;
+ if (m_expression) m_expression->setNotifyOnValueChanged(false);
+ return rv;
+}
+
+QDeclarativeBoundSignal *QDeclarativeBoundSignal::cast(QObject *o)
+{
+ QDeclarativeAbstractBoundSignal *s = qobject_cast<QDeclarativeAbstractBoundSignal*>(o);
+ return static_cast<QDeclarativeBoundSignal *>(s);
+}
+
+int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) {
+ if (!m_expression)
+ return -1;
+ if (QDeclarativeDebugService::isDebuggingEnabled()) {
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::HandlingSignal);
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::HandlingSignal, QLatin1String(m_signal.signature()) % QLatin1String(": ") % m_expression->expression());
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::HandlingSignal, m_expression->sourceFile(), m_expression->lineNumber());
+ }
+ m_isEvaluating = true;
+ if (!m_paramsValid) {
+ if (!m_signal.parameterTypes().isEmpty())
+ m_params = new QDeclarativeBoundSignalParameters(m_signal, this);
+ m_paramsValid = true;
+ }
+
+ if (m_params) m_params->setValues(a);
+ if (m_expression && m_expression->engine()) {
+ QDeclarativeExpressionPrivate::get(m_expression)->value(m_params);
+ if (m_expression && m_expression->hasError())
+ QDeclarativeEnginePrivate::warning(m_expression->engine(), m_expression->error());
+ }
+ if (m_params) m_params->clearValues();
+ m_isEvaluating = false;
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::HandlingSignal);
+ return -1;
+ } else {
+ return QObject::qt_metacall(c, id, a);
+ }
+}
+
+QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMetaMethod &method,
+ QObject *parent)
+: QObject(parent), types(0), values(0)
+{
+ MetaObject *mo = new MetaObject(this);
+
+ // ### Optimize!
+ QMetaObjectBuilder mob;
+ mob.setSuperClass(&QDeclarativeBoundSignalParameters::staticMetaObject);
+ mob.setClassName("QDeclarativeBoundSignalParameters");
+
+ QList<QByteArray> paramTypes = method.parameterTypes();
+ QList<QByteArray> paramNames = method.parameterNames();
+ types = new int[paramTypes.count()];
+ for (int ii = 0; ii < paramTypes.count(); ++ii) {
+ const QByteArray &type = paramTypes.at(ii);
+ const QByteArray &name = paramNames.at(ii);
+
+ if (name.isEmpty() || type.isEmpty()) {
+ types[ii] = 0;
+ continue;
+ }
+
+ QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData());
+ if (QDeclarativeMetaType::isQObject(t)) {
+ types[ii] = QMetaType::QObjectStar;
+ QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*");
+ prop.setWritable(false);
+ } else {
+ QByteArray propType = type;
+ if (t >= QVariant::UserType || t == QVariant::Invalid) {
+ //copy of QDeclarativeObjectScriptClass::enumType()
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = propType.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = propType.left(scopeIdx);
+ name = propType.mid(scopeIdx + 2);
+ } else {
+ name = propType;
+ }
+ const QMetaObject *meta;
+ if (scope == "Qt")
+ meta = &QObject::staticQtMetaObject;
+ else
+ meta = parent->parent()->metaObject(); //### assumes parent->parent()
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
+ t = QVariant::Int;
+ propType = "int";
+ break;
+ }
+ }
+ }
+ if (QDeclarativeMetaType::canCopy(t)) {
+ types[ii] = t;
+ QMetaPropertyBuilder prop = mob.addProperty(name, propType);
+ prop.setWritable(false);
+ } else {
+ types[ii] = 0x80000000 | t;
+ QMetaPropertyBuilder prop = mob.addProperty(name, "QVariant");
+ prop.setWritable(false);
+ }
+ }
+ }
+ myMetaObject = mob.toMetaObject();
+ *static_cast<QMetaObject *>(mo) = *myMetaObject;
+
+ d_ptr->metaObject = mo;
+}
+
+QDeclarativeBoundSignalParameters::~QDeclarativeBoundSignalParameters()
+{
+ delete [] types;
+ qFree(myMetaObject);
+}
+
+void QDeclarativeBoundSignalParameters::setValues(void **v)
+{
+ values = v;
+}
+
+void QDeclarativeBoundSignalParameters::clearValues()
+{
+ values = 0;
+}
+
+int QDeclarativeBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (!values)
+ return -1;
+
+ if (c == QMetaObject::ReadProperty && id >= 1) {
+ if (types[id - 1] & 0x80000000) {
+ *((QVariant *)a[0]) = QVariant(types[id - 1] & 0x7FFFFFFF, values[id]);
+ } else {
+ QDeclarativeMetaType::copy(types[id - 1], a[0], values[id]);
+ }
+ return -1;
+ } else {
+ return qt_metacall(c, id, a);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativeboundsignal.moc>
diff --git a/src/declarative/qml/qdeclarativeboundsignal_p.h b/src/declarative/qml/qdeclarativeboundsignal_p.h
new file mode 100644
index 0000000000..6cd1c99fa8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeboundsignal_p.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 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 QDECLARATIVEBOUNDSIGNAL_P_H
+#define QDECLARATIVEBOUNDSIGNAL_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 "qdeclarativeexpression.h"
+
+#include <QtCore/qmetaobject.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAbstractBoundSignal : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeAbstractBoundSignal(QObject *parent = 0);
+ virtual ~QDeclarativeAbstractBoundSignal() = 0;
+};
+
+class QDeclarativeBoundSignalParameters;
+class QDeclarativeBoundSignal : public QDeclarativeAbstractBoundSignal
+{
+public:
+ QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent);
+ QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val, QObject *scope,
+ const QMetaMethod &signal, QObject *parent);
+ virtual ~QDeclarativeBoundSignal();
+
+ int index() const;
+
+ QDeclarativeExpression *expression() const;
+ QDeclarativeExpression *setExpression(QDeclarativeExpression *);
+
+ bool isEvaluating() const { return m_isEvaluating; }
+
+ static QDeclarativeBoundSignal *cast(QObject *);
+
+protected:
+ virtual int qt_metacall(QMetaObject::Call c, int id, void **a);
+
+private:
+ QDeclarativeExpression *m_expression;
+ QMetaMethod m_signal;
+ bool m_paramsValid : 1;
+ bool m_isEvaluating : 1;
+ QDeclarativeBoundSignalParameters *m_params;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEBOUNDSIGNAL_P_H
diff --git a/src/declarative/qml/qdeclarativecleanup.cpp b/src/declarative/qml/qdeclarativecleanup.cpp
new file mode 100644
index 0000000000..3a8f7bbda8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecleanup.cpp
@@ -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 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/qdeclarativecleanup_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\internal
+\class QDeclarativeCleanup
+\brief The QDeclarativeCleanup provides a callback when a QDeclarativeEngine is deleted.
+
+Any object that needs cleanup to occur before the QDeclarativeEngine's QScriptEngine is
+destroyed should inherit from QDeclarativeCleanup. The clear() virtual method will be
+called by QDeclarativeEngine just before it deletes the QScriptEngine.
+*/
+
+/*!
+\internal
+
+Create a QDeclarativeCleanup for \a engine
+*/
+QDeclarativeCleanup::QDeclarativeCleanup(QDeclarativeEngine *engine)
+: prev(0), next(0)
+{
+ if (!engine)
+ return;
+
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+
+ if (p->cleanup) next = p->cleanup;
+ p->cleanup = this;
+ prev = &p->cleanup;
+ if (next) next->prev = &next;
+}
+
+/*!
+\internal
+*/
+QDeclarativeCleanup::~QDeclarativeCleanup()
+{
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecleanup_p.h b/src/declarative/qml/qdeclarativecleanup_p.h
new file mode 100644
index 0000000000..b0aafa312a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecleanup_p.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 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 QDECLARATIVECLEANUP_P_H
+#define QDECLARATIVECLEANUP_P_H
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeCleanup
+{
+public:
+ QDeclarativeCleanup(QDeclarativeEngine *);
+ virtual ~QDeclarativeCleanup();
+
+protected:
+ virtual void clear() = 0;
+
+private:
+ friend class QDeclarativeEnginePrivate;
+ QDeclarativeCleanup **prev;
+ QDeclarativeCleanup *next;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECLEANUP_P_H
+
diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp
new file mode 100644
index 0000000000..a6fcce4c99
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp
@@ -0,0 +1,2906 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativecompiledbindings_p.h b/src/declarative/qml/qdeclarativecompiledbindings_p.h
new file mode 100644
index 0000000000..f3d8b4b804
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecompiledbindings_p.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 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 QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+#define QDECLARATIVEBINDINGOPTIMIZATIONS_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"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeBindingCompilerPrivate;
+class QDeclarativeBindingCompiler
+{
+public:
+ QDeclarativeBindingCompiler();
+ ~QDeclarativeBindingCompiler();
+
+ // Returns true if bindings were compiled
+ bool isValid() const;
+
+ struct Expression
+ {
+ QDeclarativeParser::Object *component;
+ QDeclarativeParser::Object *context;
+ QDeclarativeParser::Property *property;
+ QDeclarativeParser::Variant expression;
+ QHash<QString, QDeclarativeParser::Object *> ids;
+ QDeclarativeImports imports;
+ };
+
+ // -1 on failure, otherwise the binding index to use
+ int compile(const Expression &, QDeclarativeEnginePrivate *);
+
+ // Returns the compiled program
+ QByteArray program() const;
+
+ static void dump(const QByteArray &);
+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)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEBINDINGOPTIMIZATIONS_P_H
+
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp
new file mode 100644
index 0000000000..03deea1e36
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecompileddata.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativecompiler_p.h"
+#include "qdeclarativeengine.h"
+#include "qdeclarativecomponent.h"
+#include "private/qdeclarativecomponent_p.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+int QDeclarativeCompiledData::pack(const char *data, size_t size)
+{
+ const char *p = packData.constData();
+ unsigned int ps = packData.size();
+
+ for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) {
+ if (0 == ::memcmp(p + ii, data, size))
+ return ii;
+ }
+
+ int rv = packData.size();
+ packData.append(data, size);
+ return rv;
+}
+
+int QDeclarativeCompiledData::indexForString(const QString &data)
+{
+ int idx = primitives.indexOf(data);
+ if (idx == -1) {
+ idx = primitives.count();
+ primitives << data;
+ }
+ return idx;
+}
+
+int QDeclarativeCompiledData::indexForByteArray(const QByteArray &data)
+{
+ int idx = datas.indexOf(data);
+ if (idx == -1) {
+ idx = datas.count();
+ datas << data;
+ }
+ return idx;
+}
+
+int QDeclarativeCompiledData::indexForUrl(const QUrl &data)
+{
+ int idx = urls.indexOf(data);
+ if (idx == -1) {
+ idx = urls.count();
+ urls << data;
+ }
+ return idx;
+}
+
+int QDeclarativeCompiledData::indexForFloat(float *data, int count)
+{
+ Q_ASSERT(count > 0);
+
+ for (int ii = 0; ii <= floatData.count() - count; ++ii) {
+ bool found = true;
+ for (int jj = 0; jj < count; ++jj) {
+ if (floatData.at(ii + jj) != data[jj]) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ return ii;
+ }
+
+ int idx = floatData.count();
+ for (int ii = 0; ii < count; ++ii)
+ floatData << data[ii];
+
+ return idx;
+}
+
+int QDeclarativeCompiledData::indexForInt(int *data, int count)
+{
+ Q_ASSERT(count > 0);
+
+ for (int ii = 0; ii <= intData.count() - count; ++ii) {
+ bool found = true;
+ for (int jj = 0; jj < count; ++jj) {
+ if (intData.at(ii + jj) != data[jj]) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ return ii;
+ }
+
+ int idx = intData.count();
+ for (int ii = 0; ii < count; ++ii)
+ intData << data[ii];
+
+ return idx;
+}
+
+int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::Location &l)
+{
+ // ### FIXME
+ int rv = locations.count();
+ locations << l;
+ return rv;
+}
+
+int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::LocationSpan &l)
+{
+ // ### FIXME
+ int rv = locations.count();
+ locations << l.start << l.end;
+ return rv;
+}
+
+QDeclarativeCompiledData::QDeclarativeCompiledData(QDeclarativeEngine *engine)
+: QDeclarativeCleanup(engine), importCache(0), root(0), rootPropertyCache(0)
+{
+}
+
+QDeclarativeCompiledData::~QDeclarativeCompiledData()
+{
+ for (int ii = 0; ii < types.count(); ++ii) {
+ if (types.at(ii).component)
+ types.at(ii).component->release();
+ if (types.at(ii).typePropertyCache)
+ types.at(ii).typePropertyCache->release();
+ }
+
+ for (int ii = 0; ii < propertyCaches.count(); ++ii)
+ propertyCaches.at(ii)->release();
+
+ for (int ii = 0; ii < contextCaches.count(); ++ii)
+ contextCaches.at(ii)->release();
+
+ if (importCache)
+ importCache->release();
+
+ if (rootPropertyCache)
+ rootPropertyCache->release();
+
+ qDeleteAll(cachedPrograms);
+ qDeleteAll(cachedClosures);
+}
+
+void QDeclarativeCompiledData::clear()
+{
+ qDeleteAll(cachedPrograms);
+ qDeleteAll(cachedClosures);
+ for (int ii = 0; ii < cachedClosures.count(); ++ii)
+ cachedClosures[ii] = 0;
+ for (int ii = 0; ii < cachedPrograms.count(); ++ii)
+ cachedPrograms[ii] = 0;
+}
+
+const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const
+{
+ if (type) {
+ return type->metaObject();
+ } else {
+ Q_ASSERT(component);
+ return component->root;
+ }
+}
+
+/*!
+Returns the property cache, if one alread exists. The cache is not referenced.
+*/
+QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::propertyCache() const
+{
+ if (type)
+ return typePropertyCache;
+ else
+ return component->rootPropertyCache;
+}
+
+/*!
+Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
+*/
+QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::createPropertyCache(QDeclarativeEngine *engine)
+{
+ if (typePropertyCache) {
+ return typePropertyCache;
+ } else if (type) {
+ typePropertyCache = QDeclarativeEnginePrivate::get(engine)->cache(type->metaObject());
+ typePropertyCache->addref();
+ return typePropertyCache;
+ } else {
+ return component->rootPropertyCache;
+ }
+}
+
+
+void QDeclarativeCompiledData::dumpInstructions()
+{
+ if (!name.isEmpty())
+ qWarning() << name;
+ qWarning().nospace() << "Index\tLine\tOperation\t\tData1\tData2\tData3\tComments";
+ qWarning().nospace() << "-------------------------------------------------------------------------------";
+ for (int ii = 0; ii < bytecode.count(); ++ii) {
+ dump(&bytecode[ii], ii);
+ }
+ qWarning().nospace() << "-------------------------------------------------------------------------------";
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
new file mode 100644
index 0000000000..f57f842004
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -0,0 +1,3123 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativecompiler_p.h"
+
+#include "private/qdeclarativeparser_p.h"
+#include "private/qdeclarativescriptparser_p.h"
+#include "qdeclarativepropertyvaluesource.h"
+#include "qdeclarativecomponent.h"
+#include "private/qmetaobjectbuilder_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "qdeclarativeengine.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "private/qdeclarativecustomparser_p_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativecomponent_p.h"
+#include "parser/qdeclarativejsast_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativerewrite_p.h"
+#include "qdeclarativescriptstring.h"
+#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativescriptparser_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
+
+#include <QColor>
+#include <QDebug>
+#include <QPointF>
+#include <QSizeF>
+#include <QRectF>
+#include <QAtomicInt>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatetime.h>
+
+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;
+
+/*!
+ Instantiate a new QDeclarativeCompiler.
+*/
+QDeclarativeCompiler::QDeclarativeCompiler()
+: output(0), engine(0), unitRoot(0), unit(0)
+{
+}
+
+/*!
+ Returns true if the last call to compile() caused errors.
+
+ \sa errors()
+*/
+bool QDeclarativeCompiler::isError() const
+{
+ return !exceptions.isEmpty();
+}
+
+/*!
+ Return the list of errors from the last call to compile(), or an empty list
+ if there were no errors.
+*/
+QList<QDeclarativeError> QDeclarativeCompiler::errors() const
+{
+ return exceptions;
+}
+
+/*!
+ Returns true if \a name refers to an attached property, false otherwise.
+
+ Attached property names are those that start with a capital letter.
+*/
+bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
+{
+ return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
+}
+
+/*!
+ Returns true if \a name refers to a signal property, false otherwise.
+
+ Signal property names are those that start with "on", followed by a capital
+ letter.
+*/
+bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
+{
+ return name.length() >= 3 && name.startsWith("on") &&
+ 'A' <= name.at(2) && 'Z' >= name.at(2);
+}
+
+/*!
+ \macro COMPILE_EXCEPTION
+ \internal
+ Inserts an error into the QDeclarativeCompiler error list, and returns false
+ (failure).
+
+ \a token is used to source the error line and column, and \a desc is the
+ error itself. \a desc can be an expression that can be piped into QDebug.
+
+ For example:
+
+ \code
+ COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
+ \endcode
+*/
+#define COMPILE_EXCEPTION(token, desc) \
+ { \
+ QString exceptionDescription; \
+ QDeclarativeError error; \
+ error.setUrl(output->url); \
+ error.setLine((token)->location.start.line); \
+ error.setColumn((token)->location.start.column); \
+ error.setDescription(desc.trimmed()); \
+ exceptions << error; \
+ return false; \
+ }
+
+/*!
+ \macro COMPILE_CHECK
+ \internal
+ Returns false if \a is false, otherwise does nothing.
+*/
+#define COMPILE_CHECK(a) \
+ { \
+ if (!a) return false; \
+ }
+
+/*!
+ Returns true if literal \a v can be assigned to property \a prop, otherwise
+ false.
+
+ This test corresponds to action taken by genLiteralAssignment(). Any change
+ made here, must have a corresponding action in genLiteralAssigment().
+*/
+bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
+ QDeclarativeParser::Value *v)
+{
+ QString string = v->value.asString();
+
+ if (!prop.isWritable())
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
+
+ if (prop.isEnumType()) {
+ int value;
+ if (prop.isFlagType()) {
+ value = prop.enumerator().keysToValue(string.toUtf8().constData());
+ } else
+ value = prop.enumerator().keyToValue(string.toUtf8().constData());
+ if (value == -1)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
+ return true;
+ }
+ int type = prop.userType();
+ switch(type) {
+ case -1:
+ break;
+ case QVariant::String:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
+ break;
+ case QVariant::Url:
+ if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
+ break;
+ case QVariant::UInt:
+ {
+ bool ok = v->value.isNumber();
+ if (ok) {
+ double n = v->value.asNumber();
+ if (double(uint(n)) != n)
+ ok = false;
+ }
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
+ }
+ break;
+ case QVariant::Int:
+ {
+ bool ok = v->value.isNumber();
+ if (ok) {
+ double n = v->value.asNumber();
+ if (double(int(n)) != n)
+ ok = false;
+ }
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
+ }
+ break;
+ case QMetaType::Float:
+ if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
+ break;
+ case QVariant::Double:
+ if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
+ break;
+ case QVariant::Color:
+ {
+ bool ok;
+ QDeclarativeStringConverters::colorFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date:
+ {
+ bool ok;
+ QDeclarativeStringConverters::dateFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
+ }
+ break;
+ case QVariant::Time:
+ {
+ bool ok;
+ QDeclarativeStringConverters::timeFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
+ }
+ break;
+ case QVariant::DateTime:
+ {
+ bool ok;
+ QDeclarativeStringConverters::dateTimeFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point:
+ case QVariant::PointF:
+ {
+ bool ok;
+ QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
+ }
+ break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ {
+ bool ok;
+ QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
+ }
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ bool ok;
+ QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
+ }
+ break;
+ case QVariant::Bool:
+ {
+ if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
+ }
+ break;
+ case QVariant::Vector3D:
+ {
+ bool ok;
+ QDeclarativeStringConverters::vector3DFromString(string, &ok);
+ if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
+ }
+ break;
+ default:
+ {
+ int t = prop.userType();
+ QDeclarativeMetaType::StringConverter converter =
+ QDeclarativeMetaType::customStringConverter(t);
+ if (!converter)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
+ }
+ break;
+ }
+ return true;
+}
+
+/*!
+ Generate a store instruction for assigning literal \a v to property \a prop.
+
+ Any literal assignment that is approved in testLiteralAssignment() must have
+ a corresponding action in this method.
+*/
+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());
+
+ instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.storeInteger.propertyIndex = prop.propertyIndex();
+ instr.storeInteger.value = value;
+ output->bytecode << instr;
+ return;
+ }
+
+ int type = prop.userType();
+ switch(type) {
+ case -1:
+ {
+ if (v->value.isNumber()) {
+ double n = v->value.asNumber();
+ if (double(int(n)) == n) {
+ instr.type = QDeclarativeInstruction::StoreVariantInteger;
+ instr.storeInteger.propertyIndex = prop.propertyIndex();
+ instr.storeInteger.value = int(n);
+ } else {
+ instr.type = QDeclarativeInstruction::StoreVariantDouble;
+ instr.storeDouble.propertyIndex = prop.propertyIndex();
+ instr.storeDouble.value = n;
+ }
+ } else if(v->value.isBoolean()) {
+ instr.type = QDeclarativeInstruction::StoreVariantBool;
+ instr.storeBool.propertyIndex = prop.propertyIndex();
+ instr.storeBool.value = v->value.asBoolean();
+ } else {
+ instr.type = QDeclarativeInstruction::StoreVariant;
+ instr.storeString.propertyIndex = prop.propertyIndex();
+ instr.storeString.value = output->indexForString(string);
+ }
+ }
+ break;
+ case QVariant::String:
+ {
+ instr.type = QDeclarativeInstruction::StoreString;
+ instr.storeString.propertyIndex = prop.propertyIndex();
+ instr.storeString.value = output->indexForString(string);
+ }
+ break;
+ case QVariant::Url:
+ {
+ instr.type = QDeclarativeInstruction::StoreUrl;
+ QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
+ instr.storeUrl.propertyIndex = prop.propertyIndex();
+ instr.storeUrl.value = output->indexForUrl(u);
+ }
+ break;
+ case QVariant::UInt:
+ {
+ instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.storeInteger.propertyIndex = prop.propertyIndex();
+ instr.storeInteger.value = uint(v->value.asNumber());
+ }
+ break;
+ case QVariant::Int:
+ {
+ instr.type = QDeclarativeInstruction::StoreInteger;
+ instr.storeInteger.propertyIndex = prop.propertyIndex();
+ instr.storeInteger.value = int(v->value.asNumber());
+ }
+ break;
+ case QMetaType::Float:
+ {
+ instr.type = QDeclarativeInstruction::StoreFloat;
+ instr.storeFloat.propertyIndex = prop.propertyIndex();
+ instr.storeFloat.value = float(v->value.asNumber());
+ }
+ break;
+ case QVariant::Double:
+ {
+ instr.type = QDeclarativeInstruction::StoreDouble;
+ instr.storeDouble.propertyIndex = prop.propertyIndex();
+ instr.storeDouble.value = v->value.asNumber();
+ }
+ break;
+ case QVariant::Color:
+ {
+ QColor c = QDeclarativeStringConverters::colorFromString(string);
+ instr.type = QDeclarativeInstruction::StoreColor;
+ instr.storeColor.propertyIndex = prop.propertyIndex();
+ instr.storeColor.value = c.rgba();
+ }
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date:
+ {
+ QDate d = QDeclarativeStringConverters::dateFromString(string);
+ instr.type = QDeclarativeInstruction::StoreDate;
+ instr.storeDate.propertyIndex = prop.propertyIndex();
+ instr.storeDate.value = d.toJulianDay();
+ }
+ break;
+ case QVariant::Time:
+ {
+ QTime time = QDeclarativeStringConverters::timeFromString(string);
+ int data[] = { time.hour(), time.minute(),
+ time.second(), time.msec() };
+ int index = output->indexForInt(data, 4);
+ instr.type = QDeclarativeInstruction::StoreTime;
+ instr.storeTime.propertyIndex = prop.propertyIndex();
+ instr.storeTime.valueIndex = index;
+ }
+ break;
+ case QVariant::DateTime:
+ {
+ QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
+ int data[] = { dateTime.date().toJulianDay(),
+ dateTime.time().hour(),
+ dateTime.time().minute(),
+ dateTime.time().second(),
+ dateTime.time().msec() };
+ int index = output->indexForInt(data, 5);
+ instr.type = QDeclarativeInstruction::StoreDateTime;
+ instr.storeDateTime.propertyIndex = prop.propertyIndex();
+ instr.storeDateTime.valueIndex = index;
+ }
+ break;
+#endif // QT_NO_DATESTRING
+ case QVariant::Point:
+ case QVariant::PointF:
+ {
+ bool ok;
+ QPointF point =
+ QDeclarativeStringConverters::pointFFromString(string, &ok);
+ float data[] = { float(point.x()), float(point.y()) };
+ int index = output->indexForFloat(data, 2);
+ if (type == QVariant::PointF)
+ instr.type = QDeclarativeInstruction::StorePointF;
+ else
+ instr.type = QDeclarativeInstruction::StorePoint;
+ instr.storeRealPair.propertyIndex = prop.propertyIndex();
+ instr.storeRealPair.valueIndex = index;
+ }
+ break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ {
+ bool ok;
+ QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
+ float data[] = { float(size.width()), float(size.height()) };
+ int index = output->indexForFloat(data, 2);
+ if (type == QVariant::SizeF)
+ instr.type = QDeclarativeInstruction::StoreSizeF;
+ else
+ instr.type = QDeclarativeInstruction::StoreSize;
+ instr.storeRealPair.propertyIndex = prop.propertyIndex();
+ instr.storeRealPair.valueIndex = index;
+ }
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ bool ok;
+ QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
+ float data[] = { float(rect.x()), float(rect.y()),
+ float(rect.width()), float(rect.height()) };
+ int index = output->indexForFloat(data, 4);
+ if (type == QVariant::RectF)
+ instr.type = QDeclarativeInstruction::StoreRectF;
+ else
+ instr.type = QDeclarativeInstruction::StoreRect;
+ instr.storeRect.propertyIndex = prop.propertyIndex();
+ instr.storeRect.valueIndex = index;
+ }
+ break;
+ case QVariant::Bool:
+ {
+ bool b = v->value.asBoolean();
+ instr.type = QDeclarativeInstruction::StoreBool;
+ instr.storeBool.propertyIndex = prop.propertyIndex();
+ instr.storeBool.value = b;
+ }
+ break;
+ case QVariant::Vector3D:
+ {
+ bool ok;
+ QVector3D vector =
+ QDeclarativeStringConverters::vector3DFromString(string, &ok);
+ float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) };
+ int index = output->indexForFloat(data, 3);
+ instr.type = QDeclarativeInstruction::StoreVector3D;
+ instr.storeRealPair.propertyIndex = prop.propertyIndex();
+ instr.storeRealPair.valueIndex = index;
+ }
+ break;
+ default:
+ {
+ int t = prop.userType();
+ int index = output->customTypeData.count();
+ instr.type = QDeclarativeInstruction::AssignCustomType;
+ instr.assignCustomType.propertyIndex = prop.propertyIndex();
+ instr.assignCustomType.valueIndex = index;
+
+ QDeclarativeCompiledData::CustomTypeData data;
+ data.index = output->indexForString(string);
+ data.type = t;
+ output->customTypeData << data;
+ }
+ break;
+ }
+ output->bytecode << instr;
+}
+
+/*!
+ Resets data by clearing the lists that the QDeclarativeCompiler modifies.
+*/
+void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
+{
+ data->types.clear();
+ data->primitives.clear();
+ data->floatData.clear();
+ data->intData.clear();
+ data->customTypeData.clear();
+ data->datas.clear();
+ data->bytecode.clear();
+}
+
+/*!
+ Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
+ with which the QDeclarativeCompiledData will be associated.
+
+ Returns true on success, false on failure. On failure, the compile errors
+ are available from errors().
+
+ If the environment variant QML_COMPILER_DUMP is set
+ (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
+ on a successful compiler.
+*/
+bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
+ QDeclarativeTypeData *unit,
+ QDeclarativeCompiledData *out)
+{
+ exceptions.clear();
+
+ Q_ASSERT(out);
+ reset(out);
+
+ output = out;
+
+ // Compile types
+ const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
+
+ for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
+ QDeclarativeCompiledData::TypeReference ref;
+
+ const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
+ QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
+
+ if (tref.type) {
+ ref.type = tref.type;
+ if (!ref.type->isCreatable()) {
+ QString err = ref.type->noCreationReason();
+ if (err.isEmpty())
+ err = tr( "Element is not creatable.");
+ COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
+ }
+
+ if (ref.type->containsRevisionedAttributes()) {
+ QDeclarativeError cacheError;
+ ref.typePropertyCache =
+ QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
+
+ if (!ref.typePropertyCache) {
+ COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
+ }
+ ref.typePropertyCache->addref();
+ }
+
+ } else if (tref.typeData) {
+ ref.component = tref.typeData->compiledData();
+ }
+ ref.className = parserRef->name.toUtf8();
+ out->types << ref;
+ }
+
+ QDeclarativeParser::Object *root = unit->parser().tree();
+ Q_ASSERT(root);
+
+ this->engine = engine;
+ this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ this->unit = unit;
+ this->unitRoot = root;
+ compileTree(root);
+
+ if (!isError()) {
+ if (compilerDump())
+ out->dumpInstructions();
+ if (compilerStatDump())
+ dumpStats();
+ } else {
+ reset(out);
+ }
+
+ compileState = ComponentCompileState();
+ savedCompileStates.clear();
+ output = 0;
+ this->engine = 0;
+ this->enginePrivate = 0;
+ this->unit = 0;
+ this->unitRoot = 0;
+
+ return !isError();
+}
+
+void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
+{
+ compileState.root = tree;
+ componentStat.lineNumber = tree->location.start.line;
+
+ if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
+ return;
+
+ QDeclarativeInstruction init;
+ init.type = QDeclarativeInstruction::Init;
+ init.line = 0;
+ init.init.bindingsSize = compileState.bindings.count();
+ init.init.parserStatusSize = compileState.parserStatusCount;
+ init.init.contextCache = genContextCache();
+ if (compileState.compiledBindingData.isEmpty())
+ init.init.compiledBinding = -1;
+ else
+ 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;
+ init.line = 0;
+ 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()) {
+ output->root = tree->metatype;
+ } else {
+ static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
+ output->root = &output->rootData;
+ }
+ if (!tree->metadata.isEmpty())
+ enginePrivate->registerCompositeType(output);
+}
+
+static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
+{
+ return t1->location.start.line < t2->location.start.line ||
+ (t1->location.start.line == t2->location.start.line &&
+ t1->location.start.column < t2->location.start.column);
+}
+
+bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
+{
+ componentStat.objects++;
+
+ Q_ASSERT (obj->type != -1);
+ const QDeclarativeCompiledData::TypeReference &tr =
+ output->types.at(obj->type);
+ obj->metatype = tr.metaObject();
+
+ if (tr.component)
+ obj->url = tr.component->url;
+ if (tr.type)
+ obj->typeName = tr.type->qmlTypeName();
+ obj->className = tr.className;
+
+ // This object is a "Component" element
+ if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
+ COMPILE_CHECK(buildComponent(obj, ctxt));
+ return true;
+ }
+
+ // Object instantiations reset the binding context
+ BindingContext objCtxt(obj);
+
+ // Create the synthesized meta object, ignoring aliases
+ COMPILE_CHECK(checkDynamicMeta(obj));
+ COMPILE_CHECK(mergeDynamicMetaProperties(obj));
+ COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
+
+ // Find the native type and check for the QDeclarativeParserStatus interface
+ QDeclarativeType *type = toQmlType(obj);
+ Q_ASSERT(type);
+ obj->parserStatusCast = type->parserStatusCast();
+ if (obj->parserStatusCast != -1)
+ compileState.parserStatusCount++;
+
+ // Check if this is a custom parser type. Custom parser types allow
+ // assignments to non-existent properties. These assignments are then
+ // compiled by the type.
+ bool isCustomParser = output->types.at(obj->type).type &&
+ output->types.at(obj->type).type->customParser() != 0;
+ QList<QDeclarativeCustomParserProperty> customProps;
+
+ // Fetch the list of deferred properties
+ QStringList deferredList = deferredProperties(obj);
+
+ // Must do id property first. This is to ensure that the id given to any
+ // id reference created matches the order in which the objects are
+ // instantiated
+ foreach(Property *prop, obj->properties) {
+ if (prop->name == "id") {
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ break;
+ }
+ }
+
+ // Merge
+ Property *defaultProperty = 0;
+ Property *skipProperty = 0;
+ if (obj->defaultProperty) {
+ const QMetaObject *metaObject = obj->metaObject();
+ Q_ASSERT(metaObject);
+ QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
+ if (p.name()) {
+ Property *explicitProperty = obj->getProperty(p.name(), false);
+ if (explicitProperty && !explicitProperty->value) {
+ skipProperty = explicitProperty;
+
+ defaultProperty = new Property;
+ defaultProperty->parent = obj;
+ defaultProperty->isDefault = true;
+ defaultProperty->location = obj->defaultProperty->location;
+ defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
+ defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
+
+ defaultProperty->values = obj->defaultProperty->values;
+ defaultProperty->values += explicitProperty->values;
+ foreach(QDeclarativeParser::Value *value, defaultProperty->values)
+ value->addref();
+ qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
+
+ } else {
+ defaultProperty = obj->defaultProperty;
+ defaultProperty->addref();
+ }
+ } else {
+ defaultProperty = obj->defaultProperty;
+ defaultProperty->addref();
+ }
+ }
+
+ QDeclarativeCustomParser *cp = 0;
+ if (isCustomParser)
+ cp = output->types.at(obj->type).type->customParser();
+
+ // Build all explicit properties specified
+ foreach(Property *prop, obj->properties) {
+
+ if (prop == skipProperty)
+ continue;
+ if (prop->name == "id")
+ continue;
+
+ bool canDefer = false;
+ if (isCustomParser) {
+ if (doesPropertyExist(prop, obj) &&
+ (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
+ !isAttachedPropertyName(prop->name))) {
+ int ids = compileState.ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState.ids.count();
+ } else {
+ customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
+ }
+ } else {
+ if (isSignalPropertyName(prop->name)) {
+ COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
+ } else {
+ int ids = compileState.ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState.ids.count();
+ }
+ }
+
+ if (canDefer && !deferredList.isEmpty() &&
+ deferredList.contains(QString::fromUtf8(prop->name)))
+ prop->isDeferred = true;
+
+ }
+
+ // Build the default property
+ if (defaultProperty) {
+ Property *prop = defaultProperty;
+
+ bool canDefer = false;
+ if (isCustomParser) {
+ if (doesPropertyExist(prop, obj)) {
+ int ids = compileState.ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState.ids.count();
+ } else {
+ customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
+ }
+ } else {
+ int ids = compileState.ids.count();
+ COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
+ canDefer = ids == compileState.ids.count();
+ }
+
+ if (canDefer && !deferredList.isEmpty() &&
+ deferredList.contains(QString::fromUtf8(prop->name)))
+ prop->isDeferred = true;
+ }
+
+ if (defaultProperty)
+ defaultProperty->release();
+
+ // Compile custom parser parts
+ if (isCustomParser && !customProps.isEmpty()) {
+ cp->clearErrors();
+ cp->compiler = this;
+ cp->object = obj;
+ obj->custom = cp->compile(customProps);
+ cp->compiler = 0;
+ cp->object = 0;
+ foreach (QDeclarativeError err, cp->errors()) {
+ err.setUrl(output->url);
+ exceptions << err;
+ }
+ }
+
+ return true;
+}
+
+void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
+{
+ QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
+ if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
+ genComponent(obj);
+ return;
+ }
+
+ // Create the object
+ if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
+ !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
+
+ QDeclarativeInstruction create;
+ create.type = QDeclarativeInstruction::CreateSimpleObject;
+ create.line = obj->location.start.line;
+ create.createSimple.create = output->types.at(obj->type).type->createFunction();
+ create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
+ create.createSimple.type = obj->type;
+ create.createSimple.column = obj->location.start.column;
+ output->bytecode << create;
+
+ } else {
+
+ QDeclarativeInstruction create;
+ create.type = QDeclarativeInstruction::CreateObject;
+ create.line = obj->location.start.line;
+ create.create.column = obj->location.start.column;
+ create.create.data = -1;
+ if (!obj->custom.isEmpty())
+ create.create.data = output->indexForByteArray(obj->custom);
+ create.create.type = obj->type;
+ if (!output->types.at(create.create.type).type &&
+ !obj->bindingBitmask.isEmpty()) {
+ Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
+ create.create.bindingBits =
+ output->indexForByteArray(obj->bindingBitmask);
+ } else {
+ create.create.bindingBits = -1;
+ }
+ output->bytecode << create;
+
+ }
+
+ // Setup the synthesized meta object if necessary
+ if (!obj->metadata.isEmpty()) {
+ QDeclarativeInstruction meta;
+ meta.type = QDeclarativeInstruction::StoreMetaObject;
+ meta.line = 0;
+ meta.storeMeta.data = output->indexForByteArray(obj->metadata);
+ meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
+ meta.storeMeta.propertyCache = output->propertyCaches.count();
+
+ QDeclarativePropertyCache *propertyCache = obj->synthCache;
+ Q_ASSERT(propertyCache);
+ propertyCache->addref();
+
+ // Add flag for alias properties
+ if (!obj->synthdata.isEmpty()) {
+ const QDeclarativeVMEMetaData *vmeMetaData =
+ reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
+ for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
+ int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
+ propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
+ }
+ }
+
+ if (obj == unitRoot) {
+ propertyCache->addref();
+ output->rootPropertyCache = propertyCache;
+ }
+
+ output->propertyCaches << propertyCache;
+ output->bytecode << meta;
+ } else if (obj == unitRoot) {
+ output->rootPropertyCache = tr.createPropertyCache(engine);
+ output->rootPropertyCache->addref();
+ }
+
+ // Set the object id
+ if (!obj->id.isEmpty()) {
+ QDeclarativeInstruction id;
+ id.type = QDeclarativeInstruction::SetId;
+ id.line = 0;
+ id.setId.value = output->indexForString(obj->id);
+ id.setId.index = obj->idIndex;
+ output->bytecode << id;
+ }
+
+ // Begin the class
+ if (tr.type && obj->parserStatusCast != -1) {
+ QDeclarativeInstruction begin;
+ begin.type = QDeclarativeInstruction::BeginObject;
+ begin.begin.castValue = obj->parserStatusCast;
+ begin.line = obj->location.start.line;
+ output->bytecode << begin;
+ }
+
+ genObjectBody(obj);
+}
+
+void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
+{
+ typedef QPair<Property *, int> PropPair;
+ foreach(const PropPair &prop, obj->scriptStringProperties) {
+ QDeclarativeInstruction ss;
+ ss.type = QDeclarativeInstruction::StoreScriptString;
+ ss.storeScriptString.propertyIndex = prop.first->index;
+ ss.storeScriptString.value =
+ output->indexForString(prop.first->values.at(0)->value.asScript());
+ ss.storeScriptString.scope = prop.second;
+ output->bytecode << ss;
+ }
+
+ bool seenDefer = false;
+ foreach(Property *prop, obj->valueProperties) {
+ if (prop->isDeferred) {
+ seenDefer = true;
+ continue;
+ }
+ if (!prop->isAlias)
+ genValueProperty(prop, obj);
+ }
+ if (seenDefer) {
+ QDeclarativeInstruction defer;
+ defer.type = QDeclarativeInstruction::Defer;
+ defer.line = 0;
+ defer.defer.deferCount = 0;
+ int deferIdx = output->bytecode.count();
+ output->bytecode << defer;
+
+ QDeclarativeInstruction init;
+ init.type = QDeclarativeInstruction::Init;
+ init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
+ init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
+ init.init.contextCache = -1;
+ init.init.compiledBinding = -1;
+ output->bytecode << init;
+
+ foreach(Property *prop, obj->valueProperties) {
+ if (!prop->isDeferred)
+ continue;
+ genValueProperty(prop, obj);
+ }
+
+ output->bytecode[deferIdx].defer.deferCount =
+ output->bytecode.count() - deferIdx - 1;
+ }
+
+ foreach(Property *prop, obj->signalProperties) {
+
+ QDeclarativeParser::Value *v = prop->values.at(0);
+
+ if (v->type == Value::SignalObject) {
+
+ genObject(v->object);
+
+ QDeclarativeInstruction assign;
+ assign.type = QDeclarativeInstruction::AssignSignalObject;
+ assign.line = v->location.start.line;
+ assign.assignSignalObject.signal =
+ output->indexForByteArray(prop->name);
+ output->bytecode << assign;
+
+ } else if (v->type == Value::SignalExpression) {
+
+ BindingContext ctxt = compileState.signalExpressions.value(v);
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreSignal;
+ store.line = v->location.start.line;
+ store.storeSignal.signalIndex = prop->index;
+ store.storeSignal.value =
+ output->indexForString(v->value.asScript().trimmed());
+ store.storeSignal.context = ctxt.stack;
+ store.storeSignal.name = output->indexForByteArray(prop->name);
+ output->bytecode << store;
+
+ }
+
+ }
+
+ foreach(Property *prop, obj->attachedProperties) {
+ QDeclarativeInstruction fetch;
+ fetch.type = QDeclarativeInstruction::FetchAttached;
+ fetch.line = prop->location.start.line;
+ fetch.fetchAttached.id = prop->index;
+ output->bytecode << fetch;
+
+ genObjectBody(prop->value);
+
+ QDeclarativeInstruction pop;
+ pop.type = QDeclarativeInstruction::PopFetchedObject;
+ pop.line = prop->location.start.line;
+ output->bytecode << pop;
+ }
+
+ foreach(Property *prop, obj->groupedProperties) {
+ QDeclarativeInstruction fetch;
+ fetch.type = QDeclarativeInstruction::FetchObject;
+ fetch.fetch.property = prop->index;
+ fetch.line = prop->location.start.line;
+ output->bytecode << fetch;
+
+ if (!prop->value->metadata.isEmpty()) {
+ QDeclarativeInstruction meta;
+ meta.type = QDeclarativeInstruction::StoreMetaObject;
+ meta.line = 0;
+ meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
+ meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
+ meta.storeMeta.propertyCache = -1;
+ output->bytecode << meta;
+ }
+
+ genObjectBody(prop->value);
+
+ QDeclarativeInstruction pop;
+ pop.type = QDeclarativeInstruction::PopFetchedObject;
+ pop.line = prop->location.start.line;
+ output->bytecode << pop;
+ }
+
+ foreach(Property *prop, obj->valueTypeProperties) {
+ if (!prop->isAlias)
+ genValueTypeProperty(obj, prop);
+ }
+
+ foreach(Property *prop, obj->valueProperties) {
+ if (prop->isDeferred)
+ continue;
+ if (prop->isAlias)
+ genValueProperty(prop, obj);
+ }
+
+ foreach(Property *prop, obj->valueTypeProperties) {
+ if (prop->isAlias)
+ genValueTypeProperty(obj, prop);
+ }
+}
+
+void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
+{
+ QDeclarativeInstruction fetch;
+ fetch.type = QDeclarativeInstruction::FetchValueType;
+ fetch.fetchValue.property = prop->index;
+ fetch.fetchValue.type = prop->type;
+ fetch.fetchValue.bindingSkipList = 0;
+ fetch.line = prop->location.start.line;
+
+ if (obj->type == -1 || output->types.at(obj->type).component) {
+ // We only have to do this if this is a composite type. If it is a builtin
+ // type it can't possibly already have bindings that need to be cleared.
+ foreach(Property *vprop, prop->value->valueProperties) {
+ if (!vprop->values.isEmpty()) {
+ Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
+ fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
+ }
+ }
+ }
+
+ output->bytecode << fetch;
+
+ foreach(Property *vprop, prop->value->valueProperties) {
+ genPropertyAssignment(vprop, prop->value, prop);
+ }
+
+ QDeclarativeInstruction pop;
+ pop.type = QDeclarativeInstruction::PopValueType;
+ pop.fetchValue.property = prop->index;
+ pop.fetchValue.type = prop->type;
+ pop.fetchValue.bindingSkipList = 0;
+ pop.line = prop->location.start.line;
+ output->bytecode << pop;
+}
+
+void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
+{
+ QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
+ Q_ASSERT(root);
+
+ QDeclarativeInstruction create;
+ create.type = QDeclarativeInstruction::CreateComponent;
+ create.line = root->location.start.line;
+ create.createComponent.column = root->location.start.column;
+ create.createComponent.endLine = root->location.end.line;
+ output->bytecode << create;
+ int count = output->bytecode.count();
+
+ ComponentCompileState oldCompileState = compileState;
+ compileState = componentState(root);
+
+ QDeclarativeInstruction init;
+ init.type = QDeclarativeInstruction::Init;
+ init.init.bindingsSize = compileState.bindings.count();
+ init.init.parserStatusSize = compileState.parserStatusCount;
+ init.init.contextCache = genContextCache();
+ if (compileState.compiledBindingData.isEmpty())
+ init.init.compiledBinding = -1;
+ else
+ init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
+ init.line = obj->location.start.line;
+ output->bytecode << init;
+
+ genObject(root);
+
+ QDeclarativeInstruction def;
+ init.line = 0;
+ def.type = QDeclarativeInstruction::SetDefault;
+ output->bytecode << def;
+
+ output->bytecode[count - 1].createComponent.count =
+ output->bytecode.count() - count;
+
+ compileState = oldCompileState;
+
+ if (!obj->id.isEmpty()) {
+ QDeclarativeInstruction id;
+ id.type = QDeclarativeInstruction::SetId;
+ id.line = 0;
+ id.setId.value = output->indexForString(obj->id);
+ id.setId.index = obj->idIndex;
+ output->bytecode << id;
+ }
+}
+
+bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ // The special "Component" element can only have the id property and a
+ // default property, that actually defines the component's tree
+
+ // Find, check and set the "id" property (if any)
+ Property *idProp = 0;
+ if (obj->properties.count() > 1 ||
+ (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
+ COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
+
+ if (obj->properties.count())
+ idProp = *obj->properties.begin();
+
+ if (idProp) {
+ if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
+ COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
+ COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
+
+ QString idVal = idProp->values.first()->primitive();
+
+ if (compileState.ids.contains(idVal))
+ COMPILE_EXCEPTION(idProp, tr("id is not unique"));
+
+ obj->id = idVal;
+ addId(idVal, obj);
+ }
+
+ // Check the Component tree is well formed
+ if (obj->defaultProperty &&
+ (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
+ (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
+ COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
+
+ if (!obj->dynamicProperties.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
+ if (!obj->dynamicSignals.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
+ if (!obj->dynamicSlots.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
+
+ QDeclarativeParser::Object *root = 0;
+ if (obj->defaultProperty && obj->defaultProperty->values.count())
+ root = obj->defaultProperty->values.first()->object;
+
+ if (!root)
+ COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
+
+ // Build the component tree
+ COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
+
+ return true;
+}
+
+bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ ComponentCompileState oldComponentCompileState = compileState;
+ ComponentStat oldComponentStat = componentStat;
+
+ compileState = ComponentCompileState();
+ compileState.root = obj;
+
+ componentStat = ComponentStat();
+ componentStat.lineNumber = obj->location.start.line;
+
+ if (obj)
+ COMPILE_CHECK(buildObject(obj, ctxt));
+
+ COMPILE_CHECK(completeComponentBuild());
+
+ compileState = oldComponentCompileState;
+ componentStat = oldComponentStat;
+
+ return true;
+}
+
+
+// Build a sub-object. A sub-object is one that was not created directly by
+// QML - such as a grouped property object, or an attached object. Sub-object's
+// can't have an id, involve a custom parser, have attached properties etc.
+bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
+{
+ Q_ASSERT(obj->metatype);
+ Q_ASSERT(!obj->defaultProperty);
+ Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
+ // sub-context
+
+ foreach(Property *prop, obj->properties) {
+ if (isSignalPropertyName(prop->name)) {
+ COMPILE_CHECK(buildSignal(prop, obj, ctxt));
+ } else {
+ COMPILE_CHECK(buildProperty(prop, obj, ctxt));
+ }
+ }
+
+ return true;
+}
+
+int QDeclarativeCompiler::componentTypeRef()
+{
+ QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
+ for (int ii = output->types.count() - 1; ii >= 0; --ii) {
+ if (output->types.at(ii).type == t)
+ return ii;
+ }
+ QDeclarativeCompiledData::TypeReference ref;
+ ref.className = "Component";
+ ref.type = t;
+ output->types << ref;
+ return output->types.count() - 1;
+}
+
+bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(obj->metaObject());
+
+ QByteArray name = prop->name;
+ Q_ASSERT(name.startsWith("on"));
+ name = name.mid(2);
+ if(name[0] >= 'A' && name[0] <= 'Z')
+ name[0] = name[0] - 'A' + 'a';
+
+ bool notInRevision = false;
+ int sigIdx = indexOfSignal(obj, name, &notInRevision);
+
+ if (sigIdx == -1) {
+
+ if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
+ Q_ASSERT(obj->type != -1);
+ const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
+ if (type.type) {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
+ }
+ }
+
+ // If the "on<Signal>" name doesn't resolve into a signal, try it as a
+ // property.
+ COMPILE_CHECK(buildProperty(prop, obj, ctxt));
+
+ } else {
+
+ if (prop->value || prop->values.count() != 1)
+ COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
+
+ prop->index = sigIdx;
+ obj->addSignalProperty(prop);
+
+ if (prop->values.at(0)->object) {
+ COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
+ prop->values.at(0)->type = Value::SignalObject;
+ } else {
+ prop->values.at(0)->type = Value::SignalExpression;
+
+ if (!prop->values.at(0)->value.isScript())
+ COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
+
+ QString script = prop->values.at(0)->value.asScript().trimmed();
+ if (script.isEmpty())
+ COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
+
+ compileState.signalExpressions.insert(prop->values.at(0), ctxt);
+ }
+ }
+
+ return true;
+}
+
+
+/*!
+ Returns true if (value) property \a prop exists on obj, false otherwise.
+*/
+bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj)
+{
+ if(isAttachedPropertyName(prop->name) || prop->name == "id")
+ return true;
+
+ const QMetaObject *mo = obj->metaObject();
+ if (mo) {
+ if (prop->isDefault) {
+ QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
+ return p.name() != 0;
+ } else {
+ int idx = indexOfProperty(obj, prop->name);
+ return idx != -1 && mo->property(idx).isScriptable();
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (prop->isEmpty())
+ COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
+
+ const QMetaObject *metaObject = obj->metaObject();
+ Q_ASSERT(metaObject);
+
+ if (isAttachedPropertyName(prop->name)) {
+ // Setup attached property data
+
+ if (ctxt.isSubContext()) {
+ // Attached properties cannot be used on sub-objects. Sub-objects
+ // always exist in a binding sub-context, which is what we test
+ // for here.
+ COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
+ }
+
+ QDeclarativeType *type = 0;
+ QDeclarativeImportedNamespace *typeNamespace = 0;
+ 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;
+ } else if (!type || !type->attachedPropertiesType()) {
+ COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
+ }
+
+ if (!prop->value)
+ COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
+
+ Q_ASSERT(type->attachedPropertiesFunction());
+ prop->index = type->attachedPropertiesId();
+ prop->value->metatype = type->attachedPropertiesType();
+ } else {
+ // Setup regular property data
+ QMetaProperty p;
+
+ if (prop->isDefault) {
+ p = QDeclarativeMetaType::defaultProperty(metaObject);
+
+ if (p.name()) {
+ prop->index = p.propertyIndex();
+ prop->name = p.name();
+ }
+
+ } else {
+ bool notInRevision = false;
+ prop->index = indexOfProperty(obj, prop->name, &notInRevision);
+ if (prop->index == -1 && notInRevision) {
+ const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
+ const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
+ if (type.type) {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
+ }
+ }
+
+ if (prop->index != -1) {
+ p = metaObject->property(prop->index);
+ Q_ASSERT(p.name());
+
+ if (!p.isScriptable()) {
+ prop->index = -1;
+ p = QMetaProperty();
+ }
+ }
+ }
+
+ // We can't error here as the "id" property does not require a
+ // successful index resolution
+ if (p.name())
+ prop->type = p.userType();
+
+ // Check if this is an alias
+ if (prop->index != -1 &&
+ prop->parent &&
+ prop->parent->type != -1 &&
+ output->types.at(prop->parent->type).component) {
+
+ QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
+ if (cache && cache->property(prop->index) &&
+ cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
+ prop->isAlias = true;
+ }
+
+ if (prop->index != -1 && !prop->values.isEmpty())
+ prop->parent->setBindingBit(prop->index);
+ }
+
+ if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
+
+ // The magic "id" behavior doesn't apply when "id" is resolved as a
+ // default property or to sub-objects (which are always in binding
+ // sub-contexts)
+ COMPILE_CHECK(buildIdProperty(prop, obj));
+ if (prop->type == QVariant::String &&
+ prop->values.at(0)->value.isString())
+ COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
+
+ } else if (isAttachedPropertyName(prop->name)) {
+
+ COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
+
+ } else if (prop->index == -1) {
+
+ if (prop->isDefault) {
+ COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
+ } else {
+ COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
+ }
+
+ } else if (prop->value) {
+
+ COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
+
+ } else if (enginePrivate->isList(prop->type)) {
+
+ COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
+
+ } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
+
+ COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
+
+ } else {
+
+ COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
+
+ }
+
+ return true;
+}
+
+bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
+ QDeclarativeParser::Property *nsProp,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (!nsProp->value)
+ COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
+
+ foreach (Property *prop, nsProp->value->properties) {
+
+ if (!isAttachedPropertyName(prop->name))
+ COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
+
+ // Setup attached property data
+
+ QDeclarativeType *type = 0;
+ unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
+
+ if (!type || !type->attachedPropertiesType())
+ COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
+
+ if (!prop->value)
+ COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
+
+ Q_ASSERT(type->attachedPropertiesFunction());
+ prop->index = type->index();
+ prop->value->metatype = type->attachedPropertiesType();
+
+ COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
+ }
+
+ return true;
+}
+
+void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj)
+{
+ if (enginePrivate->isList(prop->type)) {
+ genListProperty(prop, obj);
+ } else {
+ genPropertyAssignment(prop, obj);
+ }
+}
+
+void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj)
+{
+ int listType = enginePrivate->listType(prop->type);
+
+ QDeclarativeInstruction fetch;
+ fetch.type = QDeclarativeInstruction::FetchQList;
+ fetch.line = prop->location.start.line;
+ fetch.fetchQmlList.property = prop->index;
+ bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
+ fetch.fetchQmlList.type = listType;
+ output->bytecode << fetch;
+
+ for (int ii = 0; ii < prop->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->values.at(ii);
+
+ if (v->type == Value::CreatedObject) {
+
+ genObject(v->object);
+ if (listTypeIsInterface) {
+ QDeclarativeInstruction assign;
+ assign.type = QDeclarativeInstruction::AssignObjectList;
+ assign.line = prop->location.start.line;
+ output->bytecode << assign;
+ } else {
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreObjectQList;
+ store.line = prop->location.start.line;
+ output->bytecode << store;
+ }
+
+ } else if (v->type == Value::PropertyBinding) {
+
+ genBindingAssignment(v, prop, obj);
+
+ }
+
+ }
+
+ QDeclarativeInstruction pop;
+ pop.type = QDeclarativeInstruction::PopQList;
+ pop.line = prop->location.start.line;
+ output->bytecode << pop;
+}
+
+void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Property *valueTypeProperty)
+{
+ for (int ii = 0; ii < prop->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->values.at(ii);
+
+ Q_ASSERT(v->type == Value::CreatedObject ||
+ v->type == Value::PropertyBinding ||
+ v->type == Value::Literal);
+
+ if (v->type == Value::CreatedObject) {
+
+ genObject(v->object);
+
+ if (QDeclarativeMetaType::isInterface(prop->type)) {
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreInterface;
+ store.line = v->object->location.start.line;
+ store.storeObject.propertyIndex = prop->index;
+ output->bytecode << store;
+
+ } else if (prop->type == -1) {
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreVariantObject;
+ store.line = v->object->location.start.line;
+ store.storeObject.propertyIndex = prop->index;
+ output->bytecode << store;
+
+ } else {
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreObject;
+ store.line = v->object->location.start.line;
+ store.storeObject.propertyIndex = prop->index;
+ output->bytecode << store;
+
+ }
+ } else if (v->type == Value::PropertyBinding) {
+
+ genBindingAssignment(v, prop, obj, valueTypeProperty);
+
+ } else if (v->type == Value::Literal) {
+
+ QMetaProperty mp = obj->metaObject()->property(prop->index);
+ genLiteralAssignment(mp, v);
+
+ }
+
+ }
+
+ for (int ii = 0; ii < prop->onValues.count(); ++ii) {
+
+ QDeclarativeParser::Value *v = prop->onValues.at(ii);
+
+ Q_ASSERT(v->type == Value::ValueSource ||
+ v->type == Value::ValueInterceptor);
+
+ if (v->type == Value::ValueSource) {
+ genObject(v->object);
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreValueSource;
+ store.line = v->object->location.start.line;
+ if (valueTypeProperty) {
+ store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
+ store.assignValueSource.owner = 1;
+ } else {
+ store.assignValueSource.property = genPropertyData(prop);
+ store.assignValueSource.owner = 0;
+ }
+ QDeclarativeType *valueType = toQmlType(v->object);
+ store.assignValueSource.castValue = valueType->propertyValueSourceCast();
+ output->bytecode << store;
+
+ } else if (v->type == Value::ValueInterceptor) {
+ genObject(v->object);
+
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreValueInterceptor;
+ store.line = v->object->location.start.line;
+ if (valueTypeProperty) {
+ store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
+ store.assignValueInterceptor.owner = 1;
+ } else {
+ store.assignValueInterceptor.property = genPropertyData(prop);
+ store.assignValueInterceptor.owner = 0;
+ }
+ QDeclarativeType *valueType = toQmlType(v->object);
+ store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
+ output->bytecode << store;
+ }
+
+ }
+}
+
+bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj)
+{
+ if (prop->value ||
+ prop->values.count() > 1 ||
+ prop->values.at(0)->object)
+ COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
+
+ QDeclarativeParser::Value *idValue = prop->values.at(0);
+ QString val = idValue->primitive();
+
+ COMPILE_CHECK(checkValidId(idValue, val));
+
+ if (compileState.ids.contains(val))
+ COMPILE_EXCEPTION(prop, tr("id is not unique"));
+
+ prop->values.at(0)->type = Value::Id;
+
+ obj->id = val;
+ addId(val, obj);
+
+ return true;
+}
+
+void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
+{
+ Q_ASSERT(!compileState.ids.contains(id));
+ Q_ASSERT(obj->id == id);
+ obj->idIndex = compileState.ids.count();
+ compileState.ids.insert(id, obj);
+ compileState.idIndexes.insert(obj->idIndex, obj);
+}
+
+void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
+{
+ Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
+ compileState.bindings.insert(ref.value, ref);
+}
+
+void QDeclarativeCompiler::saveComponentState()
+{
+ Q_ASSERT(compileState.root);
+ Q_ASSERT(!savedCompileStates.contains(compileState.root));
+
+ savedCompileStates.insert(compileState.root, compileState);
+ savedComponentStats.append(componentStat);
+}
+
+QDeclarativeCompiler::ComponentCompileState
+QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
+{
+ Q_ASSERT(savedCompileStates.contains(obj));
+ return savedCompileStates.value(obj);
+}
+
+// Build attached property object. In this example,
+// Text {
+// GridView.row: 10
+// }
+// GridView is an attached property object.
+bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->value);
+ Q_ASSERT(prop->index != -1); // This is set in buildProperty()
+
+ obj->addAttachedProperty(prop);
+
+ COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+
+ return true;
+}
+
+
+// Build "grouped" properties. In this example:
+// Text {
+// font.pointSize: 12
+// font.family: "Helvetica"
+// }
+// font is a nested property. pointSize and family are not.
+bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->type != 0);
+ Q_ASSERT(prop->index != -1);
+
+ if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
+ if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
+
+ if (prop->values.count()) {
+ if (prop->values.at(0)->location < prop->value->location) {
+ COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
+ } else {
+ COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
+ }
+ }
+
+ if (!obj->metaObject()->property(prop->index).isWritable()) {
+ COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
+ }
+
+
+ if (prop->isAlias) {
+ foreach (Property *vtProp, prop->value->properties)
+ vtProp->isAlias = true;
+ }
+
+ COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
+ prop->value, obj, ctxt.incr()));
+ obj->addValueTypeProperty(prop);
+ } else {
+ COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
+ }
+
+ } else {
+ // Load the nested property's meta type
+ prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
+ if (!prop->value->metatype)
+ COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
+
+ if (prop->values.count())
+ COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
+
+ obj->addGroupedProperty(prop);
+
+ COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
+ }
+
+ return true;
+}
+
+bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Object *baseObj,
+ const BindingContext &ctxt)
+{
+ if (obj->defaultProperty)
+ COMPILE_EXCEPTION(obj, tr("Invalid property use"));
+ obj->metatype = type->metaObject();
+
+ foreach (Property *prop, obj->properties) {
+ int idx = type->metaObject()->indexOfProperty(prop->name.constData());
+ if (idx == -1)
+ COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
+ QMetaProperty p = type->metaObject()->property(idx);
+ if (!p.isScriptable())
+ COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
+ prop->index = idx;
+ prop->type = p.userType();
+ prop->isValueTypeSubProperty = true;
+
+ if (prop->value)
+ COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
+
+ if (prop->values.count() > 1) {
+ COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
+ } else if (prop->values.count()) {
+ QDeclarativeParser::Value *value = prop->values.at(0);
+
+ if (value->object) {
+ COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
+ } else if (value->value.isScript()) {
+ // ### Check for writability
+
+ //optimization for <Type>.<EnumValue> enum assignments
+ bool isEnumAssignment = false;
+ COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
+ if (isEnumAssignment) {
+ value->type = Value::Literal;
+ } else {
+ BindingReference reference;
+ reference.expression = value->value;
+ reference.property = prop;
+ reference.value = value;
+ reference.bindingContext = ctxt;
+ reference.bindingContext.owner++;
+ addBindingReference(reference);
+ value->type = Value::PropertyBinding;
+ }
+ } else {
+ COMPILE_CHECK(testLiteralAssignment(p, value));
+ value->type = Value::Literal;
+ }
+ }
+
+ for (int ii = 0; ii < prop->onValues.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->onValues.at(ii);
+ Q_ASSERT(v->object);
+
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
+ }
+
+ obj->addValueProperty(prop);
+ }
+
+ return true;
+}
+
+// Build assignments to QML lists. QML lists are properties of type
+// QDeclarativeListProperty<T>. List properties can accept a list of
+// objects, or a single binding.
+bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(enginePrivate->isList(prop->type));
+
+ int t = prop->type;
+
+ obj->addValueProperty(prop);
+
+ int listType = enginePrivate->listType(t);
+ bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
+
+ bool assignedBinding = false;
+ for (int ii = 0; ii < prop->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->values.at(ii);
+ if (v->object) {
+ v->type = Value::CreatedObject;
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ // We check object coercian here. We check interface assignment
+ // at runtime.
+ if (!listTypeIsInterface) {
+ if (!canCoerce(listType, v->object)) {
+ COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
+ }
+ }
+
+ } else if (v->value.isScript()) {
+ if (assignedBinding)
+ COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
+
+ assignedBinding = true;
+ COMPILE_CHECK(buildBinding(v, prop, ctxt));
+ v->type = Value::PropertyBinding;
+ } else {
+ COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
+ }
+ }
+
+ return true;
+}
+
+// Compiles an assignment to a QDeclarativeScriptString property
+bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ if (prop->values.count() > 1)
+ COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
+
+ if (prop->values.at(0)->object)
+ COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
+
+ obj->addScriptStringProperty(prop, ctxt.stack);
+
+ return true;
+}
+
+// Compile regular property assignments of the form "property: <value>"
+bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt)
+{
+ obj->addValueProperty(prop);
+
+ if (prop->values.count() > 1)
+ COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
+
+ for (int ii = 0; ii < prop->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->values.at(ii);
+ if (v->object) {
+
+ COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
+
+ } else {
+
+ COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
+
+ }
+ }
+
+ for (int ii = 0; ii < prop->onValues.count(); ++ii) {
+ QDeclarativeParser::Value *v = prop->onValues.at(ii);
+
+ Q_ASSERT(v->object);
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
+ }
+
+ return true;
+}
+
+// Compile assigning a single object instance to a regular property
+bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(v->object->type != -1);
+
+ if (!obj->metaObject()->property(prop->index).isWritable())
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
+
+ if (QDeclarativeMetaType::isInterface(prop->type)) {
+
+ // Assigning an object to an interface ptr property
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+
+ } else if (prop->type == -1) {
+
+ // Assigning an object to a QVariant
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+ } else {
+ // Normally buildObject() will set this up, but we need the static
+ // meta object earlier to test for assignability. It doesn't matter
+ // that there may still be outstanding synthesized meta object changes
+ // on this type, as they are not relevant for assignability testing
+ v->object->metatype = output->types.at(v->object->type).metaObject();
+ Q_ASSERT(v->object->metaObject());
+
+ // We want to raw metaObject here as the raw metaobject is the
+ // actual property type before we applied any extensions that might
+ // effect the properties on the type, but don't effect assignability
+ const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
+
+ // Will be true if the assgned type inherits propertyMetaObject
+ bool isAssignable = false;
+ // Determine isAssignable value
+ if (propertyMetaObject) {
+ const QMetaObject *c = v->object->metatype;
+ while(c) {
+ isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
+ c = c->superClass();
+ }
+ }
+
+ if (isAssignable) {
+ // Simple assignment
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ v->type = Value::CreatedObject;
+ } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
+ // Automatic "Component" insertion
+ QDeclarativeParser::Object *root = v->object;
+ QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
+ component->type = componentTypeRef();
+ component->typeName = "Qt/Component";
+ component->metatype = &QDeclarativeComponent::staticMetaObject;
+ component->location = root->location;
+ QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
+ componentValue->object = root;
+ component->getDefaultProperty()->addValue(componentValue);
+ v->object = component;
+ COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
+ } else {
+ COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
+ }
+ }
+
+ return true;
+}
+
+// Compile assigning a single object instance to a regular property using the "on" syntax.
+//
+// For example:
+// Item {
+// NumberAnimation on x { }
+// }
+bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Object *baseObj,
+ QDeclarativeParser::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(v->object->type != -1);
+
+ if (!obj->metaObject()->property(prop->index).isWritable())
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
+
+
+ // Normally buildObject() will set this up, but we need the static
+ // meta object earlier to test for assignability. It doesn't matter
+ // that there may still be outstanding synthesized meta object changes
+ // on this type, as they are not relevant for assignability testing
+ v->object->metatype = output->types.at(v->object->type).metaObject();
+ Q_ASSERT(v->object->metaObject());
+
+ // Will be true if the assigned type inherits QDeclarativePropertyValueSource
+ bool isPropertyValue = false;
+ // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
+ bool isPropertyInterceptor = false;
+ if (QDeclarativeType *valueType = toQmlType(v->object)) {
+ isPropertyValue = valueType->propertyValueSourceCast() != -1;
+ isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
+ }
+
+ if (isPropertyValue || isPropertyInterceptor) {
+ // Assign as a property value source
+ COMPILE_CHECK(buildObject(v->object, ctxt));
+
+ if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
+ buildDynamicMeta(baseObj, ForceCreation);
+ v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
+ } else {
+ COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
+ }
+
+ return true;
+}
+
+// Compile assigning a literal or binding to a regular property
+bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *v,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+
+ if (v->value.isScript()) {
+
+ //optimization for <Type>.<EnumValue> enum assignments
+ bool isEnumAssignment = false;
+ COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
+ if (isEnumAssignment) {
+ v->type = Value::Literal;
+ return true;
+ }
+
+ COMPILE_CHECK(buildBinding(v, prop, ctxt));
+
+ v->type = Value::PropertyBinding;
+
+ } else {
+
+ COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
+
+ v->type = Value::Literal;
+ }
+
+ return true;
+}
+
+bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *v,
+ bool *isAssignment)
+{
+ *isAssignment = false;
+ if (!prop.isEnumType())
+ return true;
+
+ if (!prop.isWritable())
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
+
+ QString string = v->value.asString();
+ if (!string.at(0).isUpper())
+ return true;
+
+ QStringList parts = string.split(QLatin1Char('.'));
+ if (parts.count() != 2)
+ return true;
+
+ QString typeName = parts.at(0);
+ QDeclarativeType *type = 0;
+ unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
+
+ //handle enums on value types (where obj->typeName is empty)
+ QByteArray objTypeName = obj->typeName;
+ if (objTypeName.isEmpty()) {
+ QDeclarativeType *objType = toQmlType(obj);
+ if (objType)
+ objTypeName = objType->qmlTypeName();
+ }
+
+ if (!type || objTypeName != type->qmlTypeName())
+ 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());
+ if (value == -1)
+ return true;
+
+ v->type = Value::Literal;
+ v->value = QDeclarativeParser::Variant(enumValue);
+ *isAssignment = true;
+
+ return true;
+}
+
+// Similar logic to above, but not knowing target property.
+int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
+{
+ int dot = script.indexOf('.');
+ if (dot > 0) {
+ QDeclarativeType *type = 0;
+ unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
+ if (!type)
+ return -1;
+ const QMetaObject *mo = type->metaObject();
+ const char *key = script.constData() + dot+1;
+ int i = mo->enumeratorCount();
+ while (i--) {
+ int v = mo->enumerator(i).keyToValue(key);
+ if (v >= 0)
+ return v;
+ }
+ }
+ return -1;
+}
+
+const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
+{
+ QDeclarativeType *qmltype = 0;
+ if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
+ return 0;
+ if (!qmltype)
+ return 0;
+ return qmltype->metaObject();
+}
+
+// similar to logic of completeComponentBuild, but also sticks data
+// into datas at the end
+int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
+{
+ QDeclarativeRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
+ bool isSharable = false;
+ QString rewrite = rewriteBinding(expression, 0, &isSharable);
+
+ quint32 length = rewrite.length();
+ quint32 pc;
+
+ if (isSharable) {
+ pc = output->cachedClosures.count();
+ pc |= 0x80000000;
+ output->cachedClosures.append(0);
+ } else {
+ pc = output->cachedPrograms.length();
+ output->cachedPrograms.append(0);
+ }
+
+ QByteArray compiledData =
+ QByteArray((const char *)&pc, sizeof(quint32)) +
+ QByteArray((const char *)&length, sizeof(quint32)) +
+ QByteArray((const char *)rewrite.constData(),
+ rewrite.length() * sizeof(QChar));
+
+ return output->indexForByteArray(compiledData);
+}
+
+// Ensures that the dynamic meta specification on obj is valid
+bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
+{
+ QSet<QByteArray> propNames;
+ QSet<QByteArray> methodNames;
+ bool seenDefaultProperty = false;
+
+ // Check properties
+ for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
+ const QDeclarativeParser::Object::DynamicProperty &prop =
+ obj->dynamicProperties.at(ii);
+
+ if (prop.isDefaultProperty) {
+ if (seenDefaultProperty)
+ COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
+ seenDefaultProperty = true;
+ }
+
+ if (propNames.contains(prop.name))
+ COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
+
+ QString propName = QString::fromUtf8(prop.name);
+ if (propName.at(0).isUpper())
+ COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
+
+ if (enginePrivate->globalClass->illegalNames().contains(propName))
+ COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
+
+ propNames.insert(prop.name);
+ }
+
+ for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
+ QByteArray name = obj->dynamicSignals.at(ii).name;
+ if (methodNames.contains(name))
+ COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
+ QString nameStr = QString::fromUtf8(name);
+ if (nameStr.at(0).isUpper())
+ COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
+ if (enginePrivate->globalClass->illegalNames().contains(nameStr))
+ COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
+ methodNames.insert(name);
+ }
+ for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
+ QByteArray name = obj->dynamicSlots.at(ii).name;
+ if (methodNames.contains(name))
+ COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
+ QString nameStr = QString::fromUtf8(name);
+ if (nameStr.at(0).isUpper())
+ COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
+ if (enginePrivate->globalClass->illegalNames().contains(nameStr))
+ COMPILE_EXCEPTION(obj, tr("Illegal method name"));
+ methodNames.insert(name);
+ }
+
+ return true;
+}
+
+bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
+{
+ for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
+ const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+
+ if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
+ continue;
+
+ Property *property = 0;
+ if (p.isDefaultProperty) {
+ property = obj->getDefaultProperty();
+ } else {
+ property = obj->getProperty(p.name);
+ if (!property->values.isEmpty())
+ COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
+ }
+
+ if (property->value)
+ COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
+
+ for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
+ v->addref();
+ property->values.append(v);
+ }
+ }
+ return true;
+}
+
+Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
+
+bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
+{
+ Q_ASSERT(obj);
+ Q_ASSERT(obj->metatype);
+
+ if (mode != ForceCreation &&
+ obj->dynamicProperties.isEmpty() &&
+ obj->dynamicSignals.isEmpty() &&
+ obj->dynamicSlots.isEmpty())
+ return true;
+
+ QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
+
+ QByteArray newClassName = obj->metatype->className();
+ newClassName.append("_QML_");
+ int idx = classIndexCounter()->fetchAndAddRelaxed(1);
+ newClassName.append(QByteArray::number(idx));
+ if (compileState.root == obj) {
+ QString path = output->url.path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash > -1) {
+ QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
+ if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
+ newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
+ }
+ }
+
+ QMetaObjectBuilder builder;
+ builder.setClassName(newClassName);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ bool hasAlias = false;
+ for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
+ const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+
+ int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
+ if (-1 != propIdx) {
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+ if (prop.isFinal())
+ COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
+ }
+
+ if (p.isDefaultProperty &&
+ (p.type != Object::DynamicProperty::Alias ||
+ mode == ResolveAliases))
+ builder.addClassInfo("DefaultProperty", p.name);
+
+ QByteArray type;
+ int propertyType = 0;
+ bool readonly = false;
+ switch(p.type) {
+ case Object::DynamicProperty::Alias:
+ hasAlias = true;
+ continue;
+ break;
+ case Object::DynamicProperty::CustomList:
+ case Object::DynamicProperty::Custom:
+ {
+ QByteArray customTypeName;
+ QDeclarativeType *qmltype = 0;
+ QUrl url;
+ if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
+ COMPILE_EXCEPTION(&p, tr("Invalid property type"));
+
+ if (!qmltype) {
+ QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ QDeclarativeCompiledData *data = tdata->compiledData();
+ customTypeName = data->root->className();
+ data->release();
+ tdata->release();
+ } else {
+ customTypeName = qmltype->typeName();
+ }
+
+ if (p.type == Object::DynamicProperty::Custom) {
+ type = customTypeName + '*';
+ propertyType = QMetaType::QObjectStar;
+ } else {
+ readonly = true;
+ type = "QDeclarativeListProperty<";
+ type.append(customTypeName);
+ type.append(">");
+ propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
+ }
+ }
+ break;
+ case Object::DynamicProperty::Variant:
+ propertyType = -1;
+ type = "QVariant";
+ break;
+ case Object::DynamicProperty::Int:
+ propertyType = QVariant::Int;
+ type = "int";
+ break;
+ case Object::DynamicProperty::Bool:
+ propertyType = QVariant::Bool;
+ type = "bool";
+ break;
+ case Object::DynamicProperty::Real:
+ propertyType = QVariant::Double;
+ type = "double";
+ break;
+ case Object::DynamicProperty::String:
+ propertyType = QVariant::String;
+ type = "QString";
+ break;
+ case Object::DynamicProperty::Url:
+ propertyType = QVariant::Url;
+ type = "QUrl";
+ break;
+ case Object::DynamicProperty::Color:
+ propertyType = QVariant::Color;
+ type = "QColor";
+ break;
+ case Object::DynamicProperty::Time:
+ propertyType = QVariant::Time;
+ type = "QTime";
+ break;
+ case Object::DynamicProperty::Date:
+ propertyType = QVariant::Date;
+ type = "QDate";
+ break;
+ case Object::DynamicProperty::DateTime:
+ propertyType = QVariant::DateTime;
+ type = "QDateTime";
+ break;
+ }
+
+ ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
+ QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
+ dynamicData.append((char *)&propertyData, sizeof(propertyData));
+
+ builder.addSignal(p.name + "Changed()");
+ QMetaPropertyBuilder propBuilder =
+ builder.addProperty(p.name, type, builder.methodCount() - 1);
+ propBuilder.setWritable(!readonly);
+ }
+
+ for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
+ const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
+
+ if (p.type == Object::DynamicProperty::Alias) {
+ if (mode == ResolveAliases) {
+ ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
+ COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
+ } else {
+ // Need a fake signal so that the metaobject remains consistent across
+ // the resolve and non-resolve alias runs
+ builder.addSignal(p.name + "Changed()");
+ }
+ }
+ }
+
+ for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
+ const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
+ QByteArray sig(s.name + '(');
+ for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
+ if (jj) sig.append(',');
+ sig.append(s.parameterTypes.at(jj));
+ }
+ sig.append(')');
+ QMetaMethodBuilder b = builder.addSignal(sig);
+ b.setParameterNames(s.parameterNames);
+ ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
+ }
+
+ QStringList funcScripts;
+
+ for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
+ Object::DynamicSlot &s = obj->dynamicSlots[ii];
+ QByteArray sig(s.name + '(');
+ QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
+
+ for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
+ if (jj) {
+ sig.append(',');
+ funcScript.append(QLatin1Char(','));
+ }
+ funcScript.append(QLatin1String(s.parameterNames.at(jj)));
+ sig.append("QVariant");
+ }
+ sig.append(')');
+ funcScript.append(QLatin1Char(')'));
+ funcScript.append(s.body);
+ funcScript.append(QLatin1Char(')'));
+ funcScripts << funcScript;
+
+ QMetaMethodBuilder b = builder.addSlot(sig);
+ b.setReturnType("QVariant");
+ b.setParameterNames(s.parameterNames);
+
+ ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
+ QDeclarativeVMEMetaData::MethodData methodData =
+ { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
+
+ dynamicData.append((char *)&methodData, sizeof(methodData));
+ }
+
+ for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
+ const QString &funcScript = funcScripts.at(ii);
+ QDeclarativeVMEMetaData::MethodData *data =
+ ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
+
+ data->bodyOffset = dynamicData.size();
+
+ dynamicData.append((const char *)funcScript.constData(),
+ (funcScript.length() * sizeof(QChar)));
+ }
+
+ obj->metadata = builder.toRelocatableData();
+ builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
+
+ if (mode == IgnoreAliases && hasAlias)
+ compileState.aliasingObjects << obj;
+
+ obj->synthdata = dynamicData;
+
+ if (obj->synthCache) {
+ obj->synthCache->release();
+ obj->synthCache = 0;
+ }
+
+ if (obj->type != -1) {
+ QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
+ cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
+ QDeclarativePropertyCache::Data::IsVMEFunction,
+ QDeclarativePropertyCache::Data::IsVMESignal);
+ obj->synthCache = cache;
+ }
+
+ return true;
+}
+
+bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
+{
+ if (val.isEmpty())
+ COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
+
+ if (val.at(0).isLetter() && !val.at(0).isLower())
+ COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
+
+ QChar u(QLatin1Char('_'));
+ for (int ii = 0; ii < val.count(); ++ii) {
+
+ if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
+ COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
+ } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
+ COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
+ }
+
+ }
+
+ if (enginePrivate->globalClass->illegalNames().contains(val))
+ COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
+
+ return true;
+}
+
+#include <qdeclarativejsparser_p.h>
+
+static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
+{
+ if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
+ QString name =
+ static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
+ return QStringList() << name;
+ } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
+ QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
+
+ QStringList rv = astNodeToStringList(expr->base);
+ if (rv.isEmpty())
+ return rv;
+ rv.append(expr->name->asString());
+ return rv;
+ }
+ return QStringList();
+}
+
+bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
+ QByteArray &data,
+ QDeclarativeParser::Object *obj,
+ const Object::DynamicProperty &prop)
+{
+ if (!prop.defaultValue)
+ COMPILE_EXCEPTION(obj, tr("No property alias location"));
+
+ if (prop.defaultValue->values.count() != 1 ||
+ prop.defaultValue->values.at(0)->object ||
+ !prop.defaultValue->values.at(0)->value.isScript())
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
+ if (!node)
+ COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
+
+ QStringList alias = astNodeToStringList(node);
+
+ if (alias.count() < 1 || alias.count() > 3)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+
+ if (!compileState.ids.contains(alias.at(0)))
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
+
+ QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
+
+ QByteArray typeName;
+
+ int propIdx = -1;
+ int flags = 0;
+ bool writable = false;
+ if (alias.count() == 2 || alias.count() == 3) {
+ propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
+
+ if (-1 == propIdx) {
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+ } else if (propIdx > 0xFFFF) {
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
+ }
+
+ QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
+ if (!aliasProperty.isScriptable())
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ writable = aliasProperty.isWritable();
+
+ if (alias.count() == 3) {
+ QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
+ if (!valueType)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+
+ propIdx |= ((unsigned int)aliasProperty.type()) << 24;
+
+ int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
+ if (valueTypeIndex == -1)
+ COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
+ Q_ASSERT(valueTypeIndex <= 0xFF);
+
+ aliasProperty = valueType->metaObject()->property(valueTypeIndex);
+ propIdx |= (valueTypeIndex << 16);
+ }
+
+ if (aliasProperty.isEnumType())
+ typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
+ else
+ typeName = aliasProperty.typeName();
+ } else {
+ typeName = idObject->metaObject()->className();
+
+ //use the base type since it has been registered with metatype system
+ int index = typeName.indexOf("_QML_");
+ if (index != -1) {
+ typeName = typeName.left(index);
+ } else {
+ index = typeName.indexOf("_QMLTYPE_");
+ const QMetaObject *mo = idObject->metaObject();
+ while (index != -1 && mo) {
+ typeName = mo->superClass()->className();
+ index = typeName.indexOf("_QMLTYPE_");
+ mo = mo->superClass();
+ }
+ }
+
+ typeName += '*';
+ }
+
+ if (typeName.endsWith('*'))
+ flags |= QML_ALIAS_FLAG_PTR;
+
+ data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
+ data.append((const char *)&propIdx, sizeof(propIdx));
+ data.append((const char *)&flags, sizeof(flags));
+
+ builder.addSignal(prop.name + "Changed()");
+ QMetaPropertyBuilder propBuilder =
+ builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
+ propBuilder.setWritable(writable);
+ return true;
+}
+
+bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
+ QDeclarativeParser::Property *prop,
+ const BindingContext &ctxt)
+{
+ Q_ASSERT(prop->index != -1);
+ Q_ASSERT(prop->parent);
+ Q_ASSERT(prop->parent->metaObject());
+
+ QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
+ if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
+ COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
+
+ BindingReference reference;
+ reference.expression = value->value;
+ reference.property = prop;
+ reference.value = value;
+ reference.bindingContext = ctxt;
+ addBindingReference(reference);
+
+ return true;
+}
+
+void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
+ QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Property *valueTypeProperty)
+{
+ Q_UNUSED(obj);
+ Q_ASSERT(compileState.bindings.contains(binding));
+
+ const BindingReference &ref = compileState.bindings.value(binding);
+ if (ref.dataType == BindingReference::Experimental) {
+ QDeclarativeInstruction store;
+ store.type = QDeclarativeInstruction::StoreCompiledBinding;
+ store.assignBinding.value = ref.compiledIndex;
+ store.assignBinding.context = ref.bindingContext.stack;
+ store.assignBinding.owner = ref.bindingContext.owner;
+ if (valueTypeProperty)
+ store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
+ ((valueTypeProperty->type & 0xFF)) << 16 |
+ ((prop->index & 0xFF) << 24);
+ else
+ store.assignBinding.property = prop->index;
+ store.line = binding->location.start.line;
+ output->bytecode << store;
+ return;
+ }
+
+ QDeclarativeInstruction store;
+ if (!prop->isAlias)
+ store.type = QDeclarativeInstruction::StoreBinding;
+ else
+ store.type = QDeclarativeInstruction::StoreBindingOnAlias;
+ store.assignBinding.value = output->indexForByteArray(ref.compiledData);
+ store.assignBinding.context = ref.bindingContext.stack;
+ store.assignBinding.owner = ref.bindingContext.owner;
+ store.line = binding->location.start.line;
+
+ Q_ASSERT(ref.bindingContext.owner == 0 ||
+ (ref.bindingContext.owner != 0 && valueTypeProperty));
+ if (ref.bindingContext.owner) {
+ store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
+ } else {
+ store.assignBinding.property = genPropertyData(prop);
+ }
+
+ output->bytecode << store;
+}
+
+int QDeclarativeCompiler::genContextCache()
+{
+ if (compileState.ids.count() == 0)
+ return -1;
+
+ QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
+
+ for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
+ iter != compileState.ids.end();
+ ++iter)
+ cache->add(iter.key(), (*iter)->idIndex);
+
+ output->contextCaches.append(cache);
+ return output->contextCaches.count() - 1;
+}
+
+int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
+ QDeclarativeParser::Property *prop)
+{
+ QByteArray data =
+ QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
+ enginePrivate->valueTypes[prop->type]->metaObject(),
+ valueTypeProp->index);
+// valueTypeProp->index, valueTypeProp->type);
+
+ return output->indexForByteArray(data);
+}
+
+int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
+{
+ return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
+}
+
+bool QDeclarativeCompiler::completeComponentBuild()
+{
+ componentStat.ids = compileState.ids.count();
+
+ for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
+ QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
+ COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
+ }
+
+ QDeclarativeBindingCompiler::Expression expr;
+ expr.component = compileState.root;
+ expr.ids = compileState.ids;
+
+ QDeclarativeBindingCompiler 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) {
+ int index = bindingCompiler.compile(expr, enginePrivate);
+ if (index != -1) {
+ binding.dataType = BindingReference::Experimental;
+ binding.compiledIndex = index;
+ componentStat.optimizedBindings.append(iter.key()->location);
+ continue;
+ }
+ }
+
+ binding.dataType = BindingReference::QtScript;
+
+ // Pre-rewrite the expression
+ QString expression = binding.expression.asScript();
+
+ QDeclarativeRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName('$'+binding.property->name);
+ bool isSharable = false;
+ expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
+
+ quint32 length = expression.length();
+ quint32 pc;
+
+ if (isSharable) {
+ pc = output->cachedClosures.count();
+ pc |= 0x80000000;
+ output->cachedClosures.append(0);
+ } else {
+ pc = output->cachedPrograms.length();
+ output->cachedPrograms.append(0);
+ }
+
+ binding.compiledData =
+ QByteArray((const char *)&pc, sizeof(quint32)) +
+ QByteArray((const char *)&length, sizeof(quint32)) +
+ QByteArray((const char *)expression.constData(),
+ expression.length() * sizeof(QChar));
+
+ componentStat.scriptBindings.append(iter.key()->location);
+ }
+
+ if (bindingCompiler.isValid()) {
+ compileState.compiledBindingData = bindingCompiler.program();
+ if (bindingsDump())
+ QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
+ }
+
+ saveComponentState();
+
+ return true;
+}
+
+void QDeclarativeCompiler::dumpStats()
+{
+ qWarning().nospace() << "QML Document: " << output->url.toString();
+ for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
+ const ComponentStat &stat = savedComponentStats.at(ii);
+ qWarning().nospace() << " Component Line " << stat.lineNumber;
+ qWarning().nospace() << " Total Objects: " << stat.objects;
+ qWarning().nospace() << " IDs Used: " << stat.ids;
+ qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
+
+ {
+ QByteArray output;
+ for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
+ if (0 == (ii % 10)) {
+ if (ii) output.append("\n");
+ output.append(" ");
+ }
+
+ output.append("(");
+ output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
+ output.append(":");
+ output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
+ output.append(") ");
+ }
+ if (!output.isEmpty())
+ qWarning().nospace() << output.constData();
+ }
+
+ qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
+ {
+ QByteArray output;
+ for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
+ if (0 == (ii % 10)) {
+ if (ii) output.append("\n");
+ output.append(" ");
+ }
+
+ output.append("(");
+ output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
+ output.append(":");
+ output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
+ output.append(") ");
+ }
+ if (!output.isEmpty())
+ qWarning().nospace() << output.constData();
+ }
+ }
+}
+
+/*!
+ Returns true if from can be assigned to a (QObject) property of type
+ to.
+*/
+bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
+{
+ const QMetaObject *toMo =
+ enginePrivate->rawMetaObjectForType(to);
+ const QMetaObject *fromMo = from->metaObject();
+
+ while (fromMo) {
+ if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
+ return true;
+ fromMo = fromMo->superClass();
+ }
+ return false;
+}
+
+QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
+{
+ // ### Optimize
+ const QMetaObject *mo = from->metatype;
+ QDeclarativeType *type = 0;
+ while (!type && mo) {
+ type = QDeclarativeMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ return type;
+}
+
+QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
+{
+ const QMetaObject *mo = obj->metatype;
+
+ int idx = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (idx == -1)
+ return QStringList();
+
+ QMetaClassInfo classInfo = mo->classInfo(idx);
+ QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ return rv;
+}
+
+// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
+int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
+ bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
+ // XXX fromUtf8
+ QString strName(QString::fromUtf8(name));
+ QDeclarativePropertyCache *cache =
+ object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
+
+ QDeclarativePropertyCache::Data *d = cache->property(strName);
+ if (notInRevision) *notInRevision = false;
+
+ while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return -1;
+ } else if (d) {
+ return d->coreIndex;
+ }
+
+ if (name.endsWith("Changed")) {
+ QByteArray propName = name.mid(0, name.length() - 7);
+
+ int propIndex = indexOfProperty(object, propName, notInRevision);
+ if (propIndex != -1) {
+ d = cache->property(propIndex);
+ return d->notifyIndex;
+ }
+ }
+
+ return -1;
+ } else {
+ return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
+ }
+
+}
+
+int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
+ bool *notInRevision)
+{
+ if (notInRevision) *notInRevision = false;
+
+ if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
+ // XXX fromUtf8
+ QString strName(QString::fromUtf8(name));
+ QDeclarativePropertyCache *cache =
+ object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
+
+ QDeclarativePropertyCache::Data *d = cache->property(strName);
+ // Find the first property
+ while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return -1;
+ } else {
+ return d?d->coreIndex:-1;
+ }
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ return mo->indexOfProperty(name.constData());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
new file mode 100644
index 0000000000..93b6a0961e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVECOMPILER_P_H
+#define QDECLARATIVECOMPILER_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 "qdeclarativeerror.h"
+#include "private/qdeclarativeinstruction_p.h"
+#include "private/qdeclarativeparser_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qbitfield_p.h"
+#include "private/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativeintegercache_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+#include "private/qdeclarativetypeloader_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qset.h>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeComponent;
+class QDeclarativeContext;
+class QDeclarativeContextData;
+
+class QScriptProgram;
+class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount, public QDeclarativeCleanup
+{
+public:
+ QDeclarativeCompiledData(QDeclarativeEngine *engine);
+ virtual ~QDeclarativeCompiledData();
+
+ QString name;
+ QUrl url;
+ QDeclarativeTypeNameCache *importCache;
+
+ struct TypeReference
+ {
+ TypeReference()
+ : type(0), typePropertyCache(0), component(0) {}
+
+ QByteArray className;
+ QDeclarativeType *type;
+ QDeclarativePropertyCache *typePropertyCache;
+ QDeclarativeCompiledData *component;
+
+ QObject *createInstance(QDeclarativeContextData *, const QBitField &, QList<QDeclarativeError> *) const;
+ const QMetaObject *metaObject() const;
+ QDeclarativePropertyCache *propertyCache() const;
+ QDeclarativePropertyCache *createPropertyCache(QDeclarativeEngine *);
+ };
+ QList<TypeReference> types;
+ struct CustomTypeData
+ {
+ int index;
+ int type;
+ };
+
+ const QMetaObject *root;
+ QAbstractDynamicMetaObject rootData;
+ QDeclarativePropertyCache *rootPropertyCache;
+ QList<QString> primitives;
+ QList<float> floatData;
+ QList<int> intData;
+ QList<CustomTypeData> customTypeData;
+ QList<QByteArray> datas;
+ QList<QDeclarativeParser::Location> locations;
+ QList<QDeclarativeInstruction> bytecode;
+ QList<QScriptProgram *> cachedPrograms;
+ QList<QScriptValue *> cachedClosures;
+ QList<QDeclarativePropertyCache *> propertyCaches;
+ QList<QDeclarativeIntegerCache *> contextCaches;
+ QList<QDeclarativeParser::Object::ScriptBlock> scripts;
+ QList<QUrl> urls;
+
+ void dumpInstructions();
+
+protected:
+ virtual void clear(); // From QDeclarativeCleanup
+
+private:
+ void dump(QDeclarativeInstruction *, int idx = -1);
+ QDeclarativeCompiledData(const QDeclarativeCompiledData &other);
+ QDeclarativeCompiledData &operator=(const QDeclarativeCompiledData &other);
+ QByteArray packData;
+ friend class QDeclarativeCompiler;
+ int pack(const char *, size_t);
+
+ int indexForString(const QString &);
+ int indexForByteArray(const QByteArray &);
+ int indexForFloat(float *, int);
+ int indexForInt(int *, int);
+ int indexForLocation(const QDeclarativeParser::Location &);
+ int indexForLocation(const QDeclarativeParser::LocationSpan &);
+ int indexForUrl(const QUrl &);
+};
+
+class QMetaObjectBuilder;
+class Q_AUTOTEST_EXPORT QDeclarativeCompiler
+{
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativeCompiler)
+public:
+ QDeclarativeCompiler();
+
+ bool compile(QDeclarativeEngine *, QDeclarativeTypeData *, QDeclarativeCompiledData *);
+
+ bool isError() const;
+ QList<QDeclarativeError> errors() const;
+
+ static bool isAttachedPropertyName(const QByteArray &);
+ static bool isSignalPropertyName(const QByteArray &);
+
+ int evaluateEnum(const QByteArray& script) const; // for QDeclarativeCustomParser::evaluateEnum
+ const QMetaObject *resolveType(const QByteArray& name) const; // for QDeclarativeCustomParser::resolveType
+ int rewriteBinding(const QString& expression, const QByteArray& name); // for QDeclarativeCustomParser::rewriteBinding
+
+private:
+ static void reset(QDeclarativeCompiledData *);
+
+ struct BindingContext {
+ BindingContext()
+ : stack(0), owner(0), object(0) {}
+ BindingContext(QDeclarativeParser::Object *o)
+ : stack(0), owner(0), object(o) {}
+ BindingContext incr() const {
+ BindingContext rv(object);
+ rv.stack = stack + 1;
+ return rv;
+ }
+ bool isSubContext() const { return stack != 0; }
+ int stack;
+ int owner;
+ QDeclarativeParser::Object *object;
+ };
+
+ void compileTree(QDeclarativeParser::Object *tree);
+
+
+ bool buildObject(QDeclarativeParser::Object *obj, const BindingContext &);
+ bool buildComponent(QDeclarativeParser::Object *obj, const BindingContext &);
+ bool buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &);
+ bool buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
+ const BindingContext &);
+ bool buildProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
+ const BindingContext &);
+ bool buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
+ QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &);
+ bool buildIdProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj);
+ bool buildAttachedProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt);
+ bool buildGroupedProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt);
+ bool buildValueTypeProperty(QObject *type,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Object *baseObj,
+ const BindingContext &ctxt);
+ bool buildListProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt);
+ bool buildScriptStringProperty(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt);
+ bool buildPropertyAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ const BindingContext &ctxt);
+ bool buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *value,
+ const BindingContext &ctxt);
+ bool buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Object *baseObj,
+ QDeclarativeParser::Value *value,
+ const BindingContext &ctxt);
+ bool buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *value,
+ const BindingContext &ctxt);
+ bool doesPropertyExist(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj);
+ bool testLiteralAssignment(const QMetaProperty &prop,
+ QDeclarativeParser::Value *value);
+ bool testQualifiedEnumAssignment(const QMetaProperty &prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Value *value,
+ bool *isAssignment);
+ enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation };
+ bool mergeDynamicMetaProperties(QDeclarativeParser::Object *obj);
+ bool buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode);
+ bool checkDynamicMeta(QDeclarativeParser::Object *obj);
+ bool buildBinding(QDeclarativeParser::Value *, QDeclarativeParser::Property *prop,
+ const BindingContext &ctxt);
+ bool buildComponentFromRoot(QDeclarativeParser::Object *obj, const BindingContext &);
+ bool compileAlias(QMetaObjectBuilder &,
+ QByteArray &data,
+ QDeclarativeParser::Object *obj,
+ const QDeclarativeParser::Object::DynamicProperty &);
+ bool completeComponentBuild();
+ bool checkValidId(QDeclarativeParser::Value *, const QString &);
+
+
+ void genObject(QDeclarativeParser::Object *obj);
+ void genObjectBody(QDeclarativeParser::Object *obj);
+ void genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *);
+ void genComponent(QDeclarativeParser::Object *obj);
+ void genValueProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj);
+ void genListProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj);
+ void genPropertyAssignment(QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Property *valueTypeProperty = 0);
+ void genLiteralAssignment(const QMetaProperty &prop,
+ QDeclarativeParser::Value *value);
+ void genBindingAssignment(QDeclarativeParser::Value *binding,
+ QDeclarativeParser::Property *prop,
+ QDeclarativeParser::Object *obj,
+ QDeclarativeParser::Property *valueTypeProperty = 0);
+ int genContextCache();
+
+ int genValueTypeData(QDeclarativeParser::Property *prop, QDeclarativeParser::Property *valueTypeProp);
+ int genPropertyData(QDeclarativeParser::Property *prop);
+
+ int componentTypeRef();
+
+ static QDeclarativeType *toQmlType(QDeclarativeParser::Object *from);
+ bool canCoerce(int to, QDeclarativeParser::Object *from);
+
+ QStringList deferredProperties(QDeclarativeParser::Object *);
+ int indexOfProperty(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0);
+ int indexOfSignal(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0);
+
+ void addId(const QString &, QDeclarativeParser::Object *);
+
+ void dumpStats();
+
+ struct BindingReference {
+ QDeclarativeParser::Variant expression;
+ QDeclarativeParser::Property *property;
+ QDeclarativeParser::Value *value;
+
+ enum DataType { QtScript, Experimental };
+ DataType dataType;
+
+ int compiledIndex;
+
+ QByteArray compiledData;
+ BindingContext bindingContext;
+ };
+ void addBindingReference(const BindingReference &);
+
+ struct ComponentCompileState
+ {
+ ComponentCompileState()
+ : parserStatusCount(0), pushedProperties(0), root(0) {}
+ QHash<QString, QDeclarativeParser::Object *> ids;
+ QHash<int, QDeclarativeParser::Object *> idIndexes;
+ int parserStatusCount;
+ int pushedProperties;
+
+ QByteArray compiledBindingData;
+
+ QHash<QDeclarativeParser::Value *, BindingReference> bindings;
+ QHash<QDeclarativeParser::Value *, BindingContext> signalExpressions;
+ QList<QDeclarativeParser::Object *> aliasingObjects;
+ QDeclarativeParser::Object *root;
+ };
+ ComponentCompileState compileState;
+
+ struct ComponentStat
+ {
+ ComponentStat() : ids(0), objects(0) {}
+
+ int lineNumber;
+
+ int ids;
+ QList<QDeclarativeParser::LocationSpan> scriptBindings;
+ QList<QDeclarativeParser::LocationSpan> optimizedBindings;
+ int objects;
+ };
+ ComponentStat componentStat;
+
+ void saveComponentState();
+
+ ComponentCompileState componentState(QDeclarativeParser::Object *);
+ QHash<QDeclarativeParser::Object *, ComponentCompileState> savedCompileStates;
+ QList<ComponentStat> savedComponentStats;
+
+ QList<QDeclarativeError> exceptions;
+ QDeclarativeCompiledData *output;
+ QDeclarativeEngine *engine;
+ QDeclarativeEnginePrivate *enginePrivate;
+ QDeclarativeParser::Object *unitRoot;
+ QDeclarativeTypeData *unit;
+};
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECOMPILER_P_H
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
new file mode 100644
index 0000000000..8238252db2
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -0,0 +1,1078 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativecomponent.h"
+#include "private/qdeclarativecomponent_p.h"
+
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativevme_p.h"
+#include "qdeclarative.h"
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativebinding_p_p.h"
+#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativescriptparser_p.h"
+#include "private/qdeclarativedebugtrace_p.h"
+#include "private/qdeclarativeenginedebug_p.h"
+#include <QtScript/qscriptvalueiterator.h>
+
+#include <QStack>
+#include <QStringList>
+#include <QtCore/qdebug.h>
+#include <QApplication>
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+
+/*!
+ \class QDeclarativeComponent
+ \since 4.7
+ \brief The QDeclarativeComponent class encapsulates a QML component definition.
+ \mainclass
+
+ Components are reusable, encapsulated QML elements with well-defined interfaces.
+ They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
+
+ A QDeclarativeComponent instance can be created from a QML file.
+ For example, if there is a \c main.qml file like this:
+
+ \qml
+ import QtQuick 1.0
+
+ Item {
+ width: 200
+ height: 200
+ }
+ \endqml
+
+ The following code loads this QML file as a component, creates an instance of
+ this component using create(), and then queries the \l Item's \l {Item::}{width}
+ value:
+
+ \code
+ QDeclarativeEngine *engine = new QDeclarativeEngine;
+ QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
+
+ QObject *myObject = component.create();
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject);
+ int width = item->width(); // width = 200
+ \endcode
+
+
+ \section2 Network Components
+
+ If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a
+ network resource, the QDeclarativeComponent has to fetch the network data before it is able to create
+ objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading}
+ \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component
+ is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}.
+
+ The following example shows how to load a QML file from a network resource. After creating
+ the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the
+ QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
+ directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the
+ component has been cached and is ready immediately.
+
+ \code
+ MyApplication::MyApplication()
+ {
+ // ...
+ component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
+ if (component->isLoading())
+ QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
+ this, SLOT(continueLoading()));
+ else
+ continueLoading();
+ }
+
+ void MyApplication::continueLoading()
+ {
+ if (component->isError()) {
+ qWarning() << component->errors();
+ } else {
+ QObject *myObject = component->create();
+ }
+ }
+ \endcode
+
+ \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
+*/
+
+/*!
+ \qmlclass Component QDeclarativeComponent
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The Component element encapsulates a QML component definition.
+
+ Components are reusable, encapsulated QML elements with well-defined interfaces.
+
+ Components are often defined by \l {qdeclarativedocuments.html}{component files} -
+ that is, \c .qml files. The \e Component element essentially allows QML components
+ to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
+ This may be useful for reusing a small component within a QML file, or for defining
+ a component that logically belongs with other QML components within a file.
+
+ For example, here is a component that is used by multiple \l Loader objects.
+ It contains a single item, a \l Rectangle:
+
+ \snippet doc/src/snippets/declarative/component.qml 0
+
+ Notice that while a \l Rectangle by itself would be automatically
+ rendered and displayed, this is not the case for the above rectangle
+ because it is defined inside a \c Component. The component encapsulates the
+ QML elements within, as if they were defined in a separate QML
+ file, and is not loaded until requested (in this case, by the
+ two \l Loader objects).
+
+ Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
+ A QML document has a single top-level item that defines the behaviors and
+ properties of that component, and cannot define properties or behaviors outside
+ of that top-level item. In the same way, a \c Component definition contains a single
+ top level item (which in the above example is a \l Rectangle) and cannot define any
+ data outside of this item, with the exception of an \e id (which in the above example
+ is \e redSquare).
+
+ The \c Component element is commonly used to provide graphical components
+ for views. For example, the ListView::delegate property requires a \c Component
+ to specify how each list item is to be displayed.
+
+ \c Component objects can also be created dynamically using
+ \l{QML:Qt::createComponent()}{Qt.createComponent()}.
+*/
+
+/*!
+ \qmlattachedsignal Component::onCompleted()
+
+ Emitted after component "startup" has completed. This can be used to
+ execute script code at startup, once the full QML environment has been
+ established.
+
+ The \c {Component::onCompleted} attached property can be applied to
+ any element. The order of running the \c onCompleted scripts is
+ undefined.
+
+ \qml
+ Rectangle {
+ Component.onCompleted: console.log("Completed Running!")
+ Rectangle {
+ Component.onCompleted: console.log("Nested Completed Running!")
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlattachedsignal Component::onDestruction()
+
+ Emitted as the component begins destruction. This can be used to undo
+ work done in the onCompleted signal, or other imperative code in your
+ application.
+
+ The \c {Component::onDestruction} attached property can be applied to
+ any element. However, it applies to the destruction of the component as
+ a whole, and not the destruction of the specific object. The order of
+ running the \c onDestruction scripts is undefined.
+
+ \qml
+ Rectangle {
+ Component.onDestruction: console.log("Destruction Beginning!")
+ Rectangle {
+ Component.onDestruction: console.log("Nested Destruction Beginning!")
+ }
+ }
+ \endqml
+
+ \sa QtDeclarative
+*/
+
+/*!
+ \enum QDeclarativeComponent::Status
+
+ Specifies the loading status of the QDeclarativeComponent.
+
+ \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content.
+ \value Ready This QDeclarativeComponent is ready and create() may be called.
+ \value Loading This QDeclarativeComponent is loading network data.
+ \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}.
+*/
+
+void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *)
+{
+ Q_Q(QDeclarativeComponent);
+
+ Q_ASSERT(typeData);
+
+ fromTypeData(typeData);
+ typeData = 0;
+
+ emit q->statusChanged(q->status());
+}
+
+void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p)
+{
+ Q_Q(QDeclarativeComponent);
+
+ progress = p;
+
+ emit q->progressChanged(p);
+}
+
+void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data)
+{
+ url = data->finalUrl();
+ QDeclarativeCompiledData *c = data->compiledData();
+
+ if (!c) {
+ Q_ASSERT(data->isError());
+ state.errors = data->errors();
+ } else {
+ cc = c;
+ }
+
+ data->release();
+}
+
+void QDeclarativeComponentPrivate::clear()
+{
+ if (typeData) {
+ typeData->unregisterCallback(this);
+ typeData->release();
+ typeData = 0;
+ }
+
+ if (cc) {
+ cc->release();
+ cc = 0;
+ }
+}
+
+/*!
+ \internal
+*/
+QDeclarativeComponent::QDeclarativeComponent(QObject *parent)
+ : QObject(*(new QDeclarativeComponentPrivate), parent)
+{
+}
+
+/*!
+ Destruct the QDeclarativeComponent.
+*/
+QDeclarativeComponent::~QDeclarativeComponent()
+{
+ Q_D(QDeclarativeComponent);
+
+ if (d->state.completePending) {
+ qWarning("QDeclarativeComponent: Component destroyed while completion pending");
+ d->completeCreate();
+ }
+
+ if (d->typeData) {
+ d->typeData->unregisterCallback(d);
+ d->typeData->release();
+ }
+ if (d->cc)
+ d->cc->release();
+}
+
+/*!
+ \qmlproperty enumeration Component::status
+ This property holds the status of component loading. It can be one of:
+ \list
+ \o Component.Null - no data is available for the component
+ \o Component.Ready - the component has been loaded, and can be used to create instances.
+ \o Component.Loading - the component is currently being loaded
+ \o Component.Error - an error occurred while loading the component.
+ Calling errorString() will provide a human-readable description of any errors.
+ \endlist
+ */
+
+/*!
+ \property QDeclarativeComponent::status
+ The component's current \l{QDeclarativeComponent::Status} {status}.
+ */
+QDeclarativeComponent::Status QDeclarativeComponent::status() const
+{
+ Q_D(const QDeclarativeComponent);
+
+ if (d->typeData)
+ return Loading;
+ else if (!d->state.errors.isEmpty())
+ return Error;
+ else if (d->engine && d->cc)
+ return Ready;
+ else
+ return Null;
+}
+
+/*!
+ Returns true if status() == QDeclarativeComponent::Null.
+*/
+bool QDeclarativeComponent::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+ Returns true if status() == QDeclarativeComponent::Ready.
+*/
+bool QDeclarativeComponent::isReady() const
+{
+ return status() == Ready;
+}
+
+/*!
+ Returns true if status() == QDeclarativeComponent::Error.
+*/
+bool QDeclarativeComponent::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+ Returns true if status() == QDeclarativeComponent::Loading.
+*/
+bool QDeclarativeComponent::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+ \qmlproperty real Component::progress
+ The progress of loading the component, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+*/
+
+/*!
+ \property QDeclarativeComponent::progress
+ The progress of loading the component, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+*/
+qreal QDeclarativeComponent::progress() const
+{
+ Q_D(const QDeclarativeComponent);
+ return d->progress;
+}
+
+/*!
+ \fn void QDeclarativeComponent::progressChanged(qreal progress)
+
+ Emitted whenever the component's loading progress changes. \a progress will be the
+ current progress between 0.0 (nothing loaded) and 1.0 (finished).
+*/
+
+/*!
+ \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status)
+
+ Emitted whenever the component's status changes. \a status will be the
+ new status.
+*/
+
+/*!
+ Create a QDeclarativeComponent with no data and give it the specified
+ \a engine and \a parent. Set the data with setData().
+*/
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent)
+ : QObject(*(new QDeclarativeComponentPrivate), parent)
+{
+ Q_D(QDeclarativeComponent);
+ d->engine = engine;
+}
+
+/*!
+ Create a QDeclarativeComponent from the given \a url and give it the
+ specified \a parent and \a engine.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+ \sa loadUrl()
+*/
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent)
+: QObject(*(new QDeclarativeComponentPrivate), parent)
+{
+ Q_D(QDeclarativeComponent);
+ d->engine = engine;
+ loadUrl(url);
+}
+
+/*!
+ Create a QDeclarativeComponent from the given \a fileName and give it the specified
+ \a parent and \a engine.
+
+ \sa loadUrl()
+*/
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName,
+ QObject *parent)
+: QObject(*(new QDeclarativeComponentPrivate), parent)
+{
+ Q_D(QDeclarativeComponent);
+ d->engine = engine;
+ loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
+}
+
+/*!
+ \internal
+*/
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, int count, QObject *parent)
+ : QObject(*(new QDeclarativeComponentPrivate), parent)
+{
+ Q_D(QDeclarativeComponent);
+ d->engine = engine;
+ d->cc = cc;
+ cc->addref();
+ d->start = start;
+ d->count = count;
+ d->url = cc->url;
+ d->progress = 1.0;
+}
+
+/*!
+ Sets the QDeclarativeComponent to use the given QML \a data. If \a url
+ is provided, it is used to set the component name and to provide
+ a base path for items resolved by this component.
+*/
+void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url)
+{
+ Q_D(QDeclarativeComponent);
+
+ d->clear();
+
+ d->url = url;
+
+ QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url);
+
+ if (typeData->isCompleteOrError()) {
+ d->fromTypeData(typeData);
+ } else {
+ d->typeData = typeData;
+ d->typeData->registerCallback(d);
+ }
+
+ d->progress = 1.0;
+ emit statusChanged(status());
+ emit progressChanged(d->progress);
+}
+
+/*!
+Returns the QDeclarativeContext the component was created in. This is only
+valid for components created directly from QML.
+*/
+QDeclarativeContext *QDeclarativeComponent::creationContext() const
+{
+ Q_D(const QDeclarativeComponent);
+ if(d->creationContext)
+ return d->creationContext->asQDeclarativeContext();
+
+ return qmlContext(this);
+}
+
+/*!
+ Load the QDeclarativeComponent from the provided \a url.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+*/
+void QDeclarativeComponent::loadUrl(const QUrl &url)
+{
+ Q_D(QDeclarativeComponent);
+
+ d->clear();
+
+ if ((url.isRelative() && !url.isEmpty())
+ || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
+ d->url = d->engine->baseUrl().resolved(url);
+ else
+ d->url = url;
+
+ if (url.isEmpty()) {
+ QDeclarativeError error;
+ error.setDescription(tr("Invalid empty URL"));
+ d->state.errors << error;
+ return;
+ }
+
+ QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url);
+
+ if (data->isCompleteOrError()) {
+ d->fromTypeData(data);
+ d->progress = 1.0;
+ } else {
+ d->typeData = data;
+ d->typeData->registerCallback(d);
+ d->progress = data->progress();
+ }
+
+ emit statusChanged(status());
+ emit progressChanged(d->progress);
+}
+
+/*!
+ Return the list of errors that occurred during the last compile or create
+ operation. An empty list is returned if isError() is not set.
+*/
+QList<QDeclarativeError> QDeclarativeComponent::errors() const
+{
+ Q_D(const QDeclarativeComponent);
+ if (isError())
+ return d->state.errors;
+ else
+ return QList<QDeclarativeError>();
+}
+
+/*!
+ \qmlmethod string Component::errorString()
+
+ Returns a human-readable description of any errors.
+
+ The string includes the file, location, and description of each error.
+ If multiple errors are present they are separated by a newline character.
+
+ If no errors are present, an empty string is returned.
+*/
+
+/*!
+ \internal
+ errorString is only meant as a way to get the errors in script
+*/
+QString QDeclarativeComponent::errorString() const
+{
+ Q_D(const QDeclarativeComponent);
+ QString ret;
+ if(!isError())
+ return ret;
+ foreach(const QDeclarativeError &e, d->state.errors) {
+ ret += e.url().toString() + QLatin1Char(':') +
+ QString::number(e.line()) + QLatin1Char(' ') +
+ e.description() + QLatin1Char('\n');
+ }
+ return ret;
+}
+
+/*!
+ \qmlproperty url Component::url
+ The component URL. This is the URL that was used to construct the component.
+*/
+
+/*!
+ \property QDeclarativeComponent::url
+ The component URL. This is the URL passed to either the constructor,
+ or the loadUrl() or setData() methods.
+*/
+QUrl QDeclarativeComponent::url() const
+{
+ Q_D(const QDeclarativeComponent);
+ return d->url;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlmethod object Component::createObject(Item parent, object properties)
+
+ Creates and returns an object instance of this component that will have
+ the given \a parent and \a properties. The \a properties argument is optional.
+ Returns null if object creation fails.
+
+ The object will be created in the same context as the one in which the component
+ was created. This function will always return null when called on components
+ which were not created in QML.
+
+ If you wish to create an object without setting a parent, specify \c null for
+ the \a parent value. Note that if the returned object is to be displayed, you
+ must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
+ property, or else the object will not be visible.
+
+ If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
+ it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
+ since setting the Item parent does not change object ownership; only the graphical parent is changed.
+
+ As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
+ map of initial property values for the created object. These values are applied before object
+ creation is finalized. (This is more efficient than setting property values after object creation,
+ particularly where large sets of property values are defined, and also allows property bindings
+ to be set up before the object is created.)
+
+ The \a properties argument is specified as a map of property-value items. For example, the code
+ below creates an object with initial \c x and \c y values of 100 and 200, respectively:
+
+ \js
+ var component = Qt.createComponent("Button.qml");
+ if (component.status == Component.Ready)
+ component.createObject(parent, {"x": 100, "y": 100});
+ \endjs
+
+ Dynamically created instances can be deleted with the \c destroy() method.
+ See \l {Dynamic Object Management in QML} for more information.
+*/
+
+/*!
+ \internal
+ A version of create which returns a scriptObject, for use in script.
+ This function will only work on components created in QML.
+
+ Sets graphics object parent because forgetting to do this is a frequent
+ and serious problem.
+*/
+QScriptValue QDeclarativeComponent::createObject(QObject* parent)
+{
+ Q_D(QDeclarativeComponent);
+ return d->createObject(parent, QScriptValue(QScriptValue::NullValue));
+}
+
+/*!
+ \internal
+ Overloadable method allows properties to be set during creation
+*/
+QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap)
+{
+ Q_D(QDeclarativeComponent);
+
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ return QScriptValue(QScriptValue::NullValue);
+ }
+ return d->createObject(parent, valuemap);
+}
+
+QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap)
+{
+ Q_Q(QDeclarativeComponent);
+ QDeclarativeContext* ctxt = q->creationContext();
+ if(!ctxt && engine)
+ ctxt = engine->rootContext();
+ if (!ctxt)
+ return QScriptValue(QScriptValue::NullValue);
+ QObject* ret = q->beginCreate(ctxt);
+ if (!ret) {
+ q->completeCreate();
+ return QScriptValue(QScriptValue::NullValue);
+ }
+
+ if (publicParent) {
+ ret->setParent(publicParent);
+ QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
+
+ bool needParent = false;
+
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, publicParent);
+ if (res == QDeclarativePrivate::Parented) {
+ needParent = false;
+ break;
+ } else if (res == QDeclarativePrivate::IncompatibleParent) {
+ needParent = true;
+ }
+ }
+
+ if (needParent)
+ qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
+ }
+
+ QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeData::get(ret, true)->setImplicitDestructible();
+ QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
+
+ if (valuemap.isObject() && !valuemap.isArray()) {
+ //Iterate through and assign properties
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ QScriptValue prop = newObject;
+ QString propName = it.name();
+ int index = propName.indexOf(QLatin1Char('.'));
+ if (index > 0) {
+ QString subProp = propName;
+ int lastIndex = 0;
+ while (index > 0) {
+ subProp = propName.mid(lastIndex, index - lastIndex);
+ prop = prop.property(subProp);
+ lastIndex = index + 1;
+ index = propName.indexOf(QLatin1Char('.'), index + 1);
+ }
+ prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value());
+ } else {
+ newObject.setProperty(propName, it.value());
+ }
+ }
+ }
+
+ q->completeCreate();
+
+ return newObject;
+}
+
+/*!
+ Create an object instance from this component. Returns 0 if creation
+ failed. \a context specifies the context within which to create the object
+ instance.
+
+ If \a context is 0 (the default), it will create the instance in the
+ engine' s \l {QDeclarativeEngine::rootContext()}{root context}.
+*/
+QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
+{
+ Q_D(QDeclarativeComponent);
+
+ if (!context)
+ context = d->engine->rootContext();
+
+ QObject *rv = beginCreate(context);
+ completeCreate();
+ return rv;
+}
+
+/*!
+ This method provides more advanced control over component instance creation.
+ In general, programmers should use QDeclarativeComponent::create() to create a
+ component.
+
+ Create an object instance from this component. Returns 0 if creation
+ failed. \a context specifies the context within which to create the object
+ instance.
+
+ When QDeclarativeComponent constructs an instance, it occurs in three steps:
+ \list 1
+ \i The object hierarchy is created, and constant values are assigned.
+ \i Property bindings are evaluated for the the first time.
+ \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects.
+ \endlist
+ QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it
+ only performs step 1. QDeclarativeComponent::completeCreate() must be called to
+ complete steps 2 and 3.
+
+ This breaking point is sometimes useful when using attached properties to
+ communicate information to an instantiated component, as it allows their
+ initial values to be configured before property bindings take effect.
+*/
+QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
+{
+ Q_D(QDeclarativeComponent);
+ QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
+ if (rv) {
+ QDeclarativeData *ddata = QDeclarativeData::get(rv);
+ Q_ASSERT(ddata);
+ ddata->indestructible = true;
+ }
+ return rv;
+}
+
+QObject *
+QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
+{
+ Q_Q(QDeclarativeComponent);
+ if (!context) {
+ qWarning("QDeclarativeComponent: Cannot create a component in a null context");
+ return 0;
+ }
+
+ if (!context->isValid()) {
+ qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
+ return 0;
+ }
+
+ if (context->engine != engine) {
+ qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
+ return 0;
+ }
+
+ if (state.completePending) {
+ qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous");
+ return 0;
+ }
+
+ if (!q->isReady()) {
+ qWarning("QDeclarativeComponent: Component is not ready");
+ return 0;
+ }
+
+ return begin(context, creationContext, cc, start, count, &state, 0, bindings);
+}
+
+QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
+ QDeclarativeContextData *componentCreationContext,
+ QDeclarativeCompiledData *component, int start, int count,
+ ConstructionState *state, QList<QDeclarativeError> *errors,
+ const QBitField &bindings)
+{
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
+ bool isRoot = !enginePriv->inBeginCreate;
+
+ 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) {
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url);
+ }
+
+ QDeclarativeContextData *ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->url = component->url;
+ ctxt->imports = component->importCache;
+
+ // Nested global imports
+ if (componentCreationContext && start != -1)
+ ctxt->importedScripts = componentCreationContext->importedScripts;
+
+ component->importCache->addref();
+ ctxt->setParent(parentContext);
+
+ enginePriv->inBeginCreate = true;
+
+ QDeclarativeVME vme;
+ QObject *rv = vme.run(ctxt, component, start, count, bindings);
+
+ if (vme.isError()) {
+ if(errors) *errors = vme.errors();
+ else state->errors = vme.errors();
+ }
+
+ if (isRoot) {
+ enginePriv->inBeginCreate = false;
+
+ state->bindValues = enginePriv->bindValues;
+ state->parserStatus = enginePriv->parserStatus;
+ state->finalizedParserStatus = enginePriv->finalizedParserStatus;
+ state->componentAttached = enginePriv->componentAttached;
+ if (state->componentAttached)
+ state->componentAttached->prev = &state->componentAttached;
+
+ enginePriv->componentAttached = 0;
+ enginePriv->bindValues.clear();
+ enginePriv->parserStatus.clear();
+ enginePriv->finalizedParserStatus.clear();
+ state->completePending = true;
+ enginePriv->inProgressCreations++;
+ }
+
+ if (enginePriv->isDebugging && rv) {
+ if (!parentContext->isInternal)
+ parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
+ QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
+ }
+
+ return rv;
+}
+
+void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
+ QObject *object, ConstructionState *state)
+{
+ bool isRoot = !enginePriv->inBeginCreate;
+ enginePriv->inBeginCreate = true;
+
+ QDeclarativeVME vme;
+ vme.runDeferred(object);
+
+ if (vme.isError())
+ state->errors = vme.errors();
+
+ if (isRoot) {
+ enginePriv->inBeginCreate = false;
+
+ state->bindValues = enginePriv->bindValues;
+ state->parserStatus = enginePriv->parserStatus;
+ state->finalizedParserStatus = enginePriv->finalizedParserStatus;
+ state->componentAttached = enginePriv->componentAttached;
+ if (state->componentAttached)
+ state->componentAttached->prev = &state->componentAttached;
+
+ enginePriv->componentAttached = 0;
+ enginePriv->bindValues.clear();
+ enginePriv->parserStatus.clear();
+ enginePriv->finalizedParserStatus.clear();
+ state->completePending = true;
+ enginePriv->inProgressCreations++;
+ }
+}
+
+void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
+{
+ if (state->completePending) {
+
+ for (int ii = 0; ii < state->bindValues.count(); ++ii) {
+ QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
+ state->bindValues.at(ii);
+ for (int jj = 0; jj < bv.count; ++jj) {
+ if(bv.at(jj)) {
+ // XXX akennedy
+ bv.at(jj)->m_mePtr = 0;
+ bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
+ QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+ QDeclarativeEnginePrivate::clear(bv);
+ }
+
+ for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
+ QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
+ state->parserStatus.at(ii);
+
+ for (int jj = ps.count - 1; jj >= 0; --jj) {
+ QDeclarativeParserStatus *status = ps.at(jj);
+ if (status && status->d) {
+ status->d = 0;
+ status->componentComplete();
+ }
+ }
+ QDeclarativeEnginePrivate::clear(ps);
+ }
+
+ for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
+ QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
+ QObject *obj = status.first;
+ if (obj) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
+ status.second, args);
+ }
+ }
+
+ //componentComplete() can register additional finalization objects
+ //that are then never handled. Handle them manually here.
+ if (1 == enginePriv->inProgressCreations) {
+ for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) {
+ QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii);
+ QObject *obj = status.first;
+ if (obj) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
+ status.second, args);
+ }
+ }
+ enginePriv->finalizedParserStatus.clear();
+ }
+
+ while (state->componentAttached) {
+ QDeclarativeComponentAttached *a = state->componentAttached;
+ a->rem();
+ QDeclarativeData *d = QDeclarativeData::get(a->parent());
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ emit a->completed();
+ }
+
+ state->bindValues.clear();
+ state->parserStatus.clear();
+ state->finalizedParserStatus.clear();
+ state->completePending = false;
+
+ enginePriv->inProgressCreations--;
+ if (0 == enginePriv->inProgressCreations) {
+ while (enginePriv->erroredBindings) {
+ enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->erroredBindings->removeError();
+ }
+ }
+ }
+}
+
+/*!
+ This method provides more advanced control over component instance creation.
+ In general, programmers should use QDeclarativeComponent::create() to create a
+ component.
+
+ Complete a component creation begin with QDeclarativeComponent::beginCreate().
+*/
+void QDeclarativeComponent::completeCreate()
+{
+ Q_D(QDeclarativeComponent);
+ d->completeCreate();
+}
+
+void QDeclarativeComponentPrivate::completeCreate()
+{
+ if (state.completePending) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ complete(ep, &state);
+
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
+ }
+}
+
+QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent)
+: QObject(parent), prev(0), next(0)
+{
+}
+
+QDeclarativeComponentAttached::~QDeclarativeComponentAttached()
+{
+ if (prev) *prev = next;
+ if (next) next->prev = prev;
+ prev = 0;
+ next = 0;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj)
+{
+ QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj);
+
+ QDeclarativeEngine *engine = qmlEngine(obj);
+ if (!engine)
+ return a;
+
+ if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ a->add(&p->componentAttached);
+ } else {
+ QDeclarativeData *d = QDeclarativeData::get(obj);
+ Q_ASSERT(d);
+ Q_ASSERT(d->context);
+ a->add(&d->context->componentAttached);
+ }
+
+ return a;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
new file mode 100644
index 0000000000..9a60a8b4f7
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVECOMPONENT_H
+#define QDECLARATIVECOMPONENT_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeerror.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtScript/qscriptvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeCompiledData;
+class QByteArray;
+class QDeclarativeComponentPrivate;
+class QDeclarativeEngine;
+class QDeclarativeComponentAttached;
+class Q_DECLARATIVE_EXPORT QDeclarativeComponent : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeComponent)
+
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QUrl url READ url CONSTANT)
+
+public:
+ QDeclarativeComponent(QObject *parent = 0);
+ QDeclarativeComponent(QDeclarativeEngine *, QObject *parent=0);
+ QDeclarativeComponent(QDeclarativeEngine *, const QString &fileName, QObject *parent = 0);
+ QDeclarativeComponent(QDeclarativeEngine *, const QUrl &url, QObject *parent = 0);
+ virtual ~QDeclarativeComponent();
+
+ Q_ENUMS(Status)
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ QList<QDeclarativeError> errors() const;
+ Q_INVOKABLE QString errorString() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+
+ virtual QObject *create(QDeclarativeContext *context = 0);
+ virtual QObject *beginCreate(QDeclarativeContext *);
+ virtual void completeCreate();
+
+ void loadUrl(const QUrl &url);
+ void setData(const QByteArray &, const QUrl &baseUrl);
+
+ QDeclarativeContext *creationContext() const;
+
+ static QDeclarativeComponentAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void statusChanged(QDeclarativeComponent::Status);
+ void progressChanged(qreal);
+
+protected:
+ QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject* parent);
+ Q_INVOKABLE QScriptValue createObject(QObject* parent);
+ Q_INVOKABLE Q_REVISION(1) QScriptValue createObject(QObject* parent, const QScriptValue& valuemap); //XXX Versioning
+
+private:
+ QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, int, QObject *parent);
+
+ Q_DISABLE_COPY(QDeclarativeComponent)
+ friend class QDeclarativeVME;
+ friend class QDeclarativeCompositeTypeData;
+ friend class QDeclarativeTypeData;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeComponent::Status)
+QML_DECLARE_TYPE(QDeclarativeComponent)
+QML_DECLARE_TYPEINFO(QDeclarativeComponent, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVECOMPONENT_H
diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h
new file mode 100644
index 0000000000..f8bec2b475
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecomponent_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVECOMPONENT_P_H
+#define QDECLARATIVECOMPONENT_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 "qdeclarativecomponent.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativetypeloader_p.h"
+#include "private/qbitfield_p.h"
+#include "qdeclarativeerror.h"
+#include "qdeclarative.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QList>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeComponent;
+class QDeclarativeEngine;
+class QDeclarativeCompiledData;
+
+class QDeclarativeComponentAttached;
+class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, public QDeclarativeTypeData::TypeDataCallback
+{
+ Q_DECLARE_PUBLIC(QDeclarativeComponent)
+
+public:
+ QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {}
+
+ QObject *beginCreate(QDeclarativeContextData *, const QBitField &);
+ void completeCreate();
+
+ QDeclarativeTypeData *typeData;
+ virtual void typeDataReady(QDeclarativeTypeData *);
+ virtual void typeDataProgress(QDeclarativeTypeData *, qreal);
+
+ void fromTypeData(QDeclarativeTypeData *data);
+
+ QUrl url;
+ qreal progress;
+
+ int start;
+ int count;
+ QDeclarativeCompiledData *cc;
+
+ struct ConstructionState {
+ ConstructionState() : componentAttached(0), completePending(false) {}
+ QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> > bindValues;
+ QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> > parserStatus;
+ QList<QPair<QDeclarativeGuard<QObject>, int> > finalizedParserStatus;
+ QDeclarativeComponentAttached *componentAttached;
+ QList<QDeclarativeError> errors;
+ bool completePending;
+ };
+ ConstructionState state;
+
+ static QObject *begin(QDeclarativeContextData *parentContext, QDeclarativeContextData *componentCreationContext,
+ QDeclarativeCompiledData *component, int start, int count,
+ ConstructionState *state, QList<QDeclarativeError> *errors,
+ const QBitField &bindings = QBitField());
+ static void beginDeferred(QDeclarativeEnginePrivate *enginePriv, QObject *object,
+ ConstructionState *state);
+ static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state);
+
+ QScriptValue createObject(QObject *publicParent, const QScriptValue valuemap);
+
+ QDeclarativeEngine *engine;
+ QDeclarativeGuardedContextData creationContext;
+
+ void clear();
+
+ static QDeclarativeComponentPrivate *get(QDeclarativeComponent *c) {
+ return static_cast<QDeclarativeComponentPrivate *>(QObjectPrivate::get(c));
+ }
+};
+
+class QDeclarativeComponentAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeComponentAttached(QObject *parent = 0);
+ ~QDeclarativeComponentAttached();
+
+ void add(QDeclarativeComponentAttached **a) {
+ prev = a; next = *a; *a = this;
+ if (next) next->prev = &next;
+ }
+ void rem() {
+ if (next) next->prev = prev;
+ *prev = next;
+ next = 0; prev = 0;
+ }
+ QDeclarativeComponentAttached **prev;
+ QDeclarativeComponentAttached *next;
+
+Q_SIGNALS:
+ void completed();
+ void destruction();
+
+private:
+ friend class QDeclarativeContextData;
+ friend class QDeclarativeComponentPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECOMPONENT_P_H
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
new file mode 100644
index 0000000000..7637b72eb3
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -0,0 +1,774 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+
+#include "private/qdeclarativecomponent_p.h"
+#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 <qscriptengine.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeContextPrivate::QDeclarativeContextPrivate()
+: data(0), notifyIndex(-1)
+{
+}
+
+/*!
+ \class QDeclarativeContext
+ \since 4.7
+ \brief The QDeclarativeContext class defines a context within a QML engine.
+ \mainclass
+
+ Contexts allow data to be exposed to the QML components instantiated by the
+ QML engine.
+
+ Each QDeclarativeContext contains a set of properties, distinct from its QObject
+ properties, that allow data to be explicitly bound to a context by name. The
+ context properties are defined and updated by calling
+ QDeclarativeContext::setContextProperty(). The following example shows a Qt model
+ being bound to a context and then accessed from a QML file.
+
+ \code
+ QDeclarativeEngine engine;
+ QStringListModel modelData;
+ QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
+ context->setContextProperty("myModel", &modelData);
+
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
+ QObject *window = component.create(context);
+ \endcode
+
+ Note it is the responsibility of the creator to delete any QDeclarativeContext it
+ constructs. If the \c context object in the example is no longer needed when the
+ \c window component instance is destroyed, the \c context must be destroyed explicitly.
+ The simplest way to ensure this is to set \c window as the parent of \c context.
+
+ To simplify binding and maintaining larger data sets, a context object can be set
+ on a QDeclarativeContext. All the properties of the context object are available
+ by name in the context, as though they were all individually added through calls
+ to QDeclarativeContext::setContextProperty(). Changes to the property's values are
+ detected through the property's notify signal. Setting a context object is both
+ faster and easier than manually adding and maintaing context property values.
+
+ The following example has the same effect as the previous one, but it uses a context
+ object.
+
+ \code
+ class MyDataSet : ... {
+ ...
+ Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
+ ...
+ };
+
+ MyDataSet myDataSet;
+ QDeclarativeEngine engine;
+ QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
+ context->setContextObject(&myDataSet);
+
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl());
+ component.create(context);
+ \endcode
+
+ All properties added explicitly by QDeclarativeContext::setContextProperty() take
+ precedence over the context object's properties.
+
+ \section2 The Context Hierarchy
+
+ Contexts form a hierarchy. The root of this hierarchy is the QML engine's
+ \l {QDeclarativeEngine::rootContext()}{root context}. Child contexts inherit
+ the context properties of their parents; if a child context sets a context property
+ that already exists in its parent, the new context property overrides that of the
+ parent.
+
+ The following example defines two contexts - \c context1 and \c context2. The
+ second context overrides the "b" context property inherited from the first with a
+ new value.
+
+ \code
+ QDeclarativeEngine engine;
+ QDeclarativeContext *context1 = new QDeclarativeContext(engine.rootContext());
+ QDeclarativeContext *context2 = new QDeclarativeContext(context1);
+
+ context1->setContextProperty("a", 12);
+ context1->setContextProperty("b", 12);
+
+ context2->setContextProperty("b", 15);
+ \endcode
+
+ While QML objects instantiated in a context are not strictly owned by that
+ context, their bindings are. If a context is destroyed, the property bindings of
+ outstanding QML objects will stop evaluating.
+
+ \warning Setting the context object or adding new context properties after an object
+ has been created in that context is an expensive operation (essentially forcing all bindings
+ to reevaluate). Thus whenever possible you should complete "setup" of the context
+ before using it to create any objects.
+
+ \sa {Using QML Bindings in C++ Applications}
+*/
+
+/*! \internal */
+QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *e, bool)
+: QObject(*(new QDeclarativeContextPrivate))
+{
+ Q_D(QDeclarativeContext);
+ d->data = new QDeclarativeContextData(this);
+
+ d->data->engine = e;
+}
+
+/*!
+ Create a new QDeclarativeContext as a child of \a engine's root context, and the
+ QObject \a parent.
+*/
+QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *engine, QObject *parent)
+: QObject(*(new QDeclarativeContextPrivate), parent)
+{
+ Q_D(QDeclarativeContext);
+ d->data = new QDeclarativeContextData(this);
+
+ d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0);
+}
+
+/*!
+ Create a new QDeclarativeContext with the given \a parentContext, and the
+ QObject \a parent.
+*/
+QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QObject *parent)
+: QObject(*(new QDeclarativeContextPrivate), parent)
+{
+ Q_D(QDeclarativeContext);
+ d->data = new QDeclarativeContextData(this);
+
+ d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0);
+}
+
+/*!
+ \internal
+*/
+QDeclarativeContext::QDeclarativeContext(QDeclarativeContextData *data)
+: QObject(*(new QDeclarativeContextPrivate), 0)
+{
+ Q_D(QDeclarativeContext);
+ d->data = data;
+}
+
+/*!
+ Destroys the QDeclarativeContext.
+
+ Any expressions, or sub-contexts dependent on this context will be
+ invalidated, but not destroyed (unless they are parented to the QDeclarativeContext
+ object).
+ */
+QDeclarativeContext::~QDeclarativeContext()
+{
+ Q_D(QDeclarativeContext);
+
+ if (!d->data->isInternal)
+ d->data->destroy();
+}
+
+/*!
+ Returns whether the context is valid.
+
+ To be valid, a context must have a engine, and it's contextObject(), if any,
+ must not have been deleted.
+*/
+bool QDeclarativeContext::isValid() const
+{
+ Q_D(const QDeclarativeContext);
+ return d->data && d->data->isValid();
+}
+
+/*!
+ Return the context's QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the
+ QDeclarativeEngine was destroyed.
+*/
+QDeclarativeEngine *QDeclarativeContext::engine() const
+{
+ Q_D(const QDeclarativeContext);
+ return d->data->engine;
+}
+
+/*!
+ Return the context's parent QDeclarativeContext, or 0 if this context has no
+ parent or if the parent has been destroyed.
+*/
+QDeclarativeContext *QDeclarativeContext::parentContext() const
+{
+ Q_D(const QDeclarativeContext);
+ return d->data->parent?d->data->parent->asQDeclarativeContext():0;
+}
+
+/*!
+ Return the context object, or 0 if there is no context object.
+*/
+QObject *QDeclarativeContext::contextObject() const
+{
+ Q_D(const QDeclarativeContext);
+ return d->data->contextObject;
+}
+
+/*!
+ Set the context \a object.
+*/
+void QDeclarativeContext::setContextObject(QObject *object)
+{
+ Q_D(QDeclarativeContext);
+
+ QDeclarativeContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QDeclarativeContext: Cannot set context object for internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QDeclarativeContext: Cannot set context object on invalid context.");
+ return;
+ }
+
+ data->contextObject = object;
+}
+
+/*!
+ Set a the \a value of the \a name property on this context.
+*/
+void QDeclarativeContext::setContextProperty(const QString &name, const QVariant &value)
+{
+ Q_D(QDeclarativeContext);
+ if (d->notifyIndex == -1)
+ d->notifyIndex = this->metaObject()->methodCount();
+
+ QDeclarativeContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QDeclarativeContext: Cannot set property on internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QDeclarativeContext: Cannot set property on invalid context.");
+ return;
+ }
+
+ if (data->engine) {
+ bool ok;
+ QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok);
+ if (ok) {
+ setContextProperty(name, o);
+ return;
+ }
+ }
+
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+
+ int idx = data->propertyNames->value(name);
+ if (idx == -1) {
+ data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ d->propertyValues.append(value);
+
+ data->refreshExpressions();
+ } else {
+ d->propertyValues[idx] = value;
+ QMetaObject::activate(this, idx + d->notifyIndex, 0);
+ }
+}
+
+/*!
+ Set the \a value of the \a name property on this context.
+
+ QDeclarativeContext does \bold not take ownership of \a value.
+*/
+void QDeclarativeContext::setContextProperty(const QString &name, QObject *value)
+{
+ Q_D(QDeclarativeContext);
+ if (d->notifyIndex == -1)
+ d->notifyIndex = this->metaObject()->methodCount();
+
+ QDeclarativeContextData *data = d->data;
+
+ if (data->isInternal) {
+ qWarning("QDeclarativeContext: Cannot set property on internal context.");
+ return;
+ }
+
+ if (!isValid()) {
+ qWarning("QDeclarativeContext: Cannot set property on invalid context.");
+ return;
+ }
+
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+ int idx = data->propertyNames->value(name);
+
+ if (idx == -1) {
+ data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ d->propertyValues.append(QVariant::fromValue(value));
+
+ data->refreshExpressions();
+ } else {
+ d->propertyValues[idx] = QVariant::fromValue(value);
+ QMetaObject::activate(this, idx + d->notifyIndex, 0);
+ }
+}
+
+/*!
+ Returns the value of the \a name property for this context
+ as a QVariant.
+ */
+QVariant QDeclarativeContext::contextProperty(const QString &name) const
+{
+ Q_D(const QDeclarativeContext);
+ QVariant value;
+ int idx = -1;
+
+ QDeclarativeContextData *data = d->data;
+
+ if (data->propertyNames)
+ idx = data->propertyNames->value(name);
+
+ if (idx == -1) {
+ QByteArray utf8Name = name.toUtf8();
+ if (data->contextObject) {
+ QObject *obj = data->contextObject;
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *property =
+ QDeclarativePropertyCache::property(data->engine, obj, name, local);
+
+ if (property) value = obj->metaObject()->property(property->coreIndex).read(obj);
+ }
+ if (!value.isValid() && parentContext())
+ value = parentContext()->contextProperty(name);
+ } else {
+ if (idx >= d->propertyValues.count())
+ value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
+ else
+ value = d->propertyValues[idx];
+ }
+
+ return value;
+}
+
+/*!
+ Resolves the URL \a src relative to the URL of the
+ containing component.
+
+ \sa QDeclarativeEngine::baseUrl(), setBaseUrl()
+*/
+QUrl QDeclarativeContext::resolvedUrl(const QUrl &src)
+{
+ Q_D(QDeclarativeContext);
+ return d->data->resolvedUrl(src);
+}
+
+QUrl QDeclarativeContextData::resolvedUrl(const QUrl &src)
+{
+ QDeclarativeContextData *ctxt = this;
+
+ if (src.isRelative() && !src.isEmpty()) {
+ if (ctxt) {
+ while(ctxt) {
+ if(ctxt->url.isValid())
+ break;
+ else
+ ctxt = ctxt->parent;
+ }
+
+ if (ctxt)
+ return ctxt->url.resolved(src);
+ else if (engine)
+ return engine->baseUrl().resolved(src);
+ }
+ return QUrl();
+ } else {
+ return src;
+ }
+}
+
+
+/*!
+ Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
+
+ Calling this function will override the url of the containing
+ component used by default.
+
+ \sa resolvedUrl()
+*/
+void QDeclarativeContext::setBaseUrl(const QUrl &baseUrl)
+{
+ Q_D(QDeclarativeContext);
+
+ d->data->url = baseUrl;
+}
+
+/*!
+ Returns the base url of the component, or the containing component
+ if none is set.
+*/
+QUrl QDeclarativeContext::baseUrl() const
+{
+ Q_D(const QDeclarativeContext);
+ const QDeclarativeContextData* data = d->data;
+ while (data && data->url.isEmpty())
+ data = data->parent;
+
+ if (data)
+ return data->url;
+ else
+ return QUrl();
+}
+
+int QDeclarativeContextPrivate::context_count(QDeclarativeListProperty<QObject> *prop)
+{
+ QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
+ QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
+ int contextProperty = (int)(quintptr)prop->data;
+
+ if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ return 0;
+ } else {
+ return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
+ }
+}
+
+QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject> *prop, int index)
+{
+ QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object);
+ QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context);
+ int contextProperty = (int)(quintptr)prop->data;
+
+ if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ return 0;
+ } else {
+ return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
+ }
+}
+
+
+QDeclarativeContextData::QDeclarativeContextData()
+: parent(0), engine(0), isInternal(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)
+{
+}
+
+QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
+: parent(0), engine(0), isInternal(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)
+{
+}
+
+void QDeclarativeContextData::invalidate()
+{
+ while (childContexts)
+ childContexts->invalidate();
+
+ while (componentAttached) {
+ QDeclarativeComponentAttached *a = componentAttached;
+ componentAttached = a->next;
+ if (componentAttached) componentAttached->prev = &componentAttached;
+
+ a->next = 0;
+ a->prev = 0;
+
+ emit a->destruction();
+ }
+
+ if (prevChild) {
+ *prevChild = nextChild;
+ if (nextChild) nextChild->prevChild = prevChild;
+ nextChild = 0;
+ prevChild = 0;
+ }
+
+ engine = 0;
+ parent = 0;
+}
+
+void QDeclarativeContextData::clearContext()
+{
+ if (engine) {
+ while (componentAttached) {
+ QDeclarativeComponentAttached *a = componentAttached;
+ componentAttached = a->next;
+ if (componentAttached) componentAttached->prev = &componentAttached;
+
+ a->next = 0;
+ a->prev = 0;
+
+ emit a->destruction();
+ }
+ }
+
+ QDeclarativeAbstractExpression *expression = expressions;
+ while (expression) {
+ QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression;
+
+ expression->m_context = 0;
+ expression->m_prevExpression = 0;
+ expression->m_nextExpression = 0;
+
+ expression = nextExpression;
+ }
+ expressions = 0;
+}
+
+void QDeclarativeContextData::destroy()
+{
+ if (linkedContext)
+ linkedContext->destroy();
+
+ if (engine) invalidate();
+
+ clearContext();
+
+ while (contextObjects) {
+ QDeclarativeData *co = contextObjects;
+ contextObjects = contextObjects->nextContextObject;
+
+ co->context = 0;
+ co->outerContext = 0;
+ co->nextContextObject = 0;
+ co->prevContextObject = 0;
+ }
+
+ QDeclarativeGuardedContextData *contextGuard = contextGuards;
+ while (contextGuard) {
+ QDeclarativeGuardedContextData *next = contextGuard->m_next;
+ contextGuard->m_next = 0;
+ contextGuard->m_prev = 0;
+ contextGuard->m_contextData = 0;
+ contextGuard = next;
+ }
+ contextGuards = 0;
+
+ if (propertyNames)
+ propertyNames->release();
+
+ if (imports)
+ imports->release();
+
+ if (optimizedBindings)
+ optimizedBindings->release();
+
+ delete [] idValues;
+
+ if (isInternal)
+ delete publicContext;
+
+ delete this;
+}
+
+void QDeclarativeContextData::setParent(QDeclarativeContextData *p)
+{
+ if (p) {
+ parent = p;
+ engine = p->engine;
+ nextChild = p->childContexts;
+ if (nextChild) nextChild->prevChild = &nextChild;
+ prevChild = &p->childContexts;
+ p->childContexts = this;
+ }
+}
+
+/*
+Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
+context-tree dependent caches in the expressions, and should occur every time the context tree
+ *structure* (not values) changes.
+*/
+void QDeclarativeContextData::refreshExpressions()
+{
+ QDeclarativeContextData *child = childContexts;
+ while (child) {
+ child->refreshExpressions();
+ child = child->nextChild;
+ }
+
+ QDeclarativeAbstractExpression *expression = expressions;
+ while (expression) {
+ expression->refresh();
+ expression = expression->m_nextExpression;
+ }
+}
+
+void QDeclarativeContextData::addObject(QObject *o)
+{
+ QDeclarativeData *data = QDeclarativeData::get(o, true);
+
+ Q_ASSERT(data->context == 0);
+
+ data->context = this;
+ data->outerContext = this;
+
+ data->nextContextObject = contextObjects;
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = &data->nextContextObject;
+ data->prevContextObject = &contextObjects;
+ 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;
+ idValues[idx].context = this;
+}
+
+void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data)
+{
+ Q_ASSERT(!propertyNames);
+ propertyNames = data;
+ propertyNames->addref();
+
+ idValueCount = data->count();
+ idValues = new ContextGuard[idValueCount];
+}
+
+QString QDeclarativeContextData::findObjectId(const QObject *obj) const
+{
+ if (!idValues || !propertyNames)
+ return QString();
+
+ for (int i=0; i<idValueCount; i++) {
+ if (idValues[i] == obj)
+ return propertyNames->findId(i);
+ }
+
+ if (linkedContext)
+ return linkedContext->findObjectId(obj);
+ return QString();
+}
+
+QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext()
+{
+ if (!publicContext)
+ publicContext = new QDeclarativeContext(this);
+ return publicContext;
+}
+
+QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate()
+{
+ return QDeclarativeContextPrivate::get(asQDeclarativeContext());
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h
new file mode 100644
index 0000000000..66daca959d
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecontext.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 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 QDECLARATIVECONTEXT_H
+#define QDECLARATIVECONTEXT_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QString;
+class QDeclarativeEngine;
+class QDeclarativeRefCount;
+class QDeclarativeContextPrivate;
+class QDeclarativeCompositeTypeData;
+class QDeclarativeContextData;
+
+class Q_DECLARATIVE_EXPORT QDeclarativeContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeContext)
+
+public:
+ QDeclarativeContext(QDeclarativeEngine *parent, QObject *objParent=0);
+ QDeclarativeContext(QDeclarativeContext *parent, QObject *objParent=0);
+ virtual ~QDeclarativeContext();
+
+ bool isValid() const;
+
+ QDeclarativeEngine *engine() const;
+ QDeclarativeContext *parentContext() const;
+
+ QObject *contextObject() const;
+ void setContextObject(QObject *);
+
+ QVariant contextProperty(const QString &) const;
+ void setContextProperty(const QString &, QObject *);
+ void setContextProperty(const QString &, const QVariant &);
+
+ QUrl resolvedUrl(const QUrl &);
+
+ void setBaseUrl(const QUrl &);
+ QUrl baseUrl() const;
+
+private:
+ friend class QDeclarativeVME;
+ friend class QDeclarativeEngine;
+ friend class QDeclarativeEnginePrivate;
+ friend class QDeclarativeExpression;
+ friend class QDeclarativeExpressionPrivate;
+ friend class QDeclarativeContextScriptClass;
+ friend class QDeclarativeObjectScriptClass;
+ friend class QDeclarativeComponent;
+ friend class QDeclarativeComponentPrivate;
+ friend class QDeclarativeScriptPrivate;
+ friend class QDeclarativeBoundSignalProxy;
+ friend class QDeclarativeContextData;
+ QDeclarativeContext(QDeclarativeContextData *);
+ QDeclarativeContext(QDeclarativeEngine *, bool);
+ Q_DISABLE_COPY(QDeclarativeContext)
+};
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QList<QObject*>)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVECONTEXT_H
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
new file mode 100644
index 0000000000..b7e4c6aa7c
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVECONTEXT_P_H
+#define QDECLARATIVECONTEXT_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 "qdeclarativecontext.h"
+
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativeintegercache_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+#include "private/qdeclarativenotifier_p.h"
+#include "qdeclarativelist.h"
+#include "private/qdeclarativeparser_p.h"
+
+#include <QtCore/qhash.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/qset.h>
+
+#include <private/qobject_p.h>
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QDeclarativeExpression;
+class QDeclarativeEngine;
+class QDeclarativeExpression;
+class QDeclarativeExpressionPrivate;
+class QDeclarativeAbstractExpression;
+class QDeclarativeCompiledBindings;
+class QDeclarativeContextData;
+
+class QDeclarativeContextPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeContext)
+public:
+ QDeclarativeContextPrivate();
+
+ QDeclarativeContextData *data;
+
+ QList<QVariant> propertyValues;
+ int notifyIndex;
+
+ static QDeclarativeContextPrivate *get(QDeclarativeContext *context) {
+ return static_cast<QDeclarativeContextPrivate *>(QObjectPrivate::get(context));
+ }
+ static QDeclarativeContext *get(QDeclarativeContextPrivate *context) {
+ return static_cast<QDeclarativeContext *>(context->q_func());
+ }
+
+ // Only used for debugging
+ QList<QPointer<QObject> > instances;
+
+ static int context_count(QDeclarativeListProperty<QObject> *);
+ static QObject *context_at(QDeclarativeListProperty<QObject> *, int);
+};
+
+class QDeclarativeComponentAttached;
+class QDeclarativeGuardedContextData;
+class Q_AUTOTEST_EXPORT QDeclarativeContextData
+{
+public:
+ QDeclarativeContextData();
+ QDeclarativeContextData(QDeclarativeContext *);
+ void clearContext();
+ void destroy();
+ void invalidate();
+
+ inline bool isValid() const {
+ return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted);
+ }
+
+ // My parent context and engine
+ QDeclarativeContextData *parent;
+ QDeclarativeEngine *engine;
+
+ void setParent(QDeclarativeContextData *);
+ void refreshExpressions();
+
+ void addObject(QObject *);
+
+ QUrl resolvedUrl(const QUrl &);
+
+ // My containing QDeclarativeContext. If isInternal is true this owns publicContext.
+ // If internal is false publicContext owns this.
+ QDeclarativeContext *asQDeclarativeContext();
+ QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
+ bool isInternal;
+ QDeclarativeContext *publicContext;
+
+ // Property name cache
+ QDeclarativeIntegerCache *propertyNames;
+
+ // Context object
+ QObject *contextObject;
+
+ // Any script blocks that exist on this context
+ QList<QScriptValue> importedScripts;
+ void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script);
+
+ // Context base url
+ QUrl url;
+
+ // List of imports that apply to this context
+ QDeclarativeTypeNameCache *imports;
+
+ // My children
+ QDeclarativeContextData *childContexts;
+
+ // My peers in parent's childContexts list
+ QDeclarativeContextData *nextChild;
+ QDeclarativeContextData **prevChild;
+
+ // Expressions that use this context
+ QDeclarativeAbstractExpression *expressions;
+
+ // Doubly-linked list of objects that are owned by this context
+ QDeclarativeData *contextObjects;
+
+ // Doubly-linked list of context guards (XXX merge with contextObjects)
+ QDeclarativeGuardedContextData *contextGuards;
+
+ // id guards
+ struct ContextGuard : public QDeclarativeGuard<QObject>
+ {
+ ContextGuard() : context(0) {}
+ inline ContextGuard &operator=(QObject *obj)
+ { QDeclarativeGuard<QObject>::operator=(obj); return *this; }
+ virtual void objectDestroyed(QObject *) {
+ if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted) bindings.notify();
+ }
+ QDeclarativeContextData *context;
+ QDeclarativeNotifier bindings;
+ };
+ ContextGuard *idValues;
+ int idValueCount;
+ void setIdProperty(int, QObject *);
+ void setIdPropertyData(QDeclarativeIntegerCache *);
+
+ // Optimized binding pointer
+ QDeclarativeCompiledBindings *optimizedBindings;
+
+ // Linked contexts. this owns linkedContext.
+ QDeclarativeContextData *linkedContext;
+
+ // Linked list of uses of the Component attached property in this
+ // context
+ QDeclarativeComponentAttached *componentAttached;
+
+ // Return the outermost id for obj, if any.
+ QString findObjectId(const QObject *obj) const;
+
+ static QDeclarativeContextData *get(QDeclarativeContext *context) {
+ return QDeclarativeContextPrivate::get(context)->data;
+ }
+
+private:
+ ~QDeclarativeContextData() {}
+};
+
+class QDeclarativeGuardedContextData
+{
+public:
+ inline QDeclarativeGuardedContextData();
+ inline QDeclarativeGuardedContextData(QDeclarativeContextData *);
+ inline ~QDeclarativeGuardedContextData();
+
+ inline void setContextData(QDeclarativeContextData *);
+
+ inline QDeclarativeContextData *contextData();
+
+ inline operator QDeclarativeContextData*() const { return m_contextData; }
+ inline QDeclarativeContextData* operator->() const { return m_contextData; }
+ inline QDeclarativeGuardedContextData &operator=(QDeclarativeContextData *d);
+
+private:
+ QDeclarativeGuardedContextData &operator=(const QDeclarativeGuardedContextData &);
+ QDeclarativeGuardedContextData(const QDeclarativeGuardedContextData &);
+ friend class QDeclarativeContextData;
+
+ inline void clear();
+
+ QDeclarativeContextData *m_contextData;
+ QDeclarativeGuardedContextData *m_next;
+ QDeclarativeGuardedContextData **m_prev;
+};
+
+QDeclarativeGuardedContextData::QDeclarativeGuardedContextData()
+: m_contextData(0), m_next(0), m_prev(0)
+{
+}
+
+QDeclarativeGuardedContextData::QDeclarativeGuardedContextData(QDeclarativeContextData *data)
+: m_contextData(0), m_next(0), m_prev(0)
+{
+ setContextData(data);
+}
+
+QDeclarativeGuardedContextData::~QDeclarativeGuardedContextData()
+{
+ clear();
+}
+
+void QDeclarativeGuardedContextData::setContextData(QDeclarativeContextData *contextData)
+{
+ clear();
+
+ if (contextData) {
+ m_contextData = contextData;
+ m_next = contextData->contextGuards;
+ if (m_next) m_next->m_prev = &m_next;
+ m_prev = &contextData->contextGuards;
+ contextData->contextGuards = this;
+ }
+}
+
+QDeclarativeContextData *QDeclarativeGuardedContextData::contextData()
+{
+ return m_contextData;
+}
+
+void QDeclarativeGuardedContextData::clear()
+{
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_contextData = 0;
+ m_next = 0;
+ m_prev = 0;
+ }
+}
+
+QDeclarativeGuardedContextData &
+QDeclarativeGuardedContextData::operator=(QDeclarativeContextData *d)
+{
+ setContextData(d);
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECONTEXT_P_H
diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp
new file mode 100644
index 0000000000..3abd78794a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativecontextscriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativetypenamescriptclass_p.h"
+#include "private/qdeclarativelistscriptclass_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+struct ContextData : public QScriptDeclarativeClass::Object {
+ ContextData() : overrideObject(0), isSharedContext(true) {}
+ ContextData(QDeclarativeContextData *c, QObject *o)
+ : context(c), scopeObject(o), overrideObject(0), isSharedContext(false), isUrlContext(false) {}
+ QDeclarativeGuardedContextData context;
+ QDeclarativeGuard<QObject> scopeObject;
+ QObject *overrideObject;
+ bool isSharedContext:1;
+ bool isUrlContext:1;
+
+ QDeclarativeContextData *getContext(QDeclarativeEngine *engine) {
+ if (isSharedContext) {
+ return QDeclarativeEnginePrivate::get(engine)->sharedContext;
+ } else {
+ return context.contextData();
+ }
+ }
+
+ QObject *getScope(QDeclarativeEngine *engine) {
+ if (isSharedContext) {
+ return QDeclarativeEnginePrivate::get(engine)->sharedScope;
+ } else {
+ return scopeObject.data();
+ }
+ }
+};
+
+struct UrlContextData : public ContextData {
+ UrlContextData(QDeclarativeContextData *c, QObject *o, const QString &u)
+ : ContextData(c, o), url(u) {
+ isUrlContext = true;
+ }
+ UrlContextData(const QString &u)
+ : ContextData(0, 0), url(u) {
+ isUrlContext = true;
+ }
+ QString url;
+};
+
+/*
+ The QDeclarativeContextScriptClass handles property access for a QDeclarativeContext
+ via QtScript.
+ */
+QDeclarativeContextScriptClass::QDeclarativeContextScriptClass(QDeclarativeEngine *bindEngine)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine),
+ lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1)
+{
+}
+
+QDeclarativeContextScriptClass::~QDeclarativeContextScriptClass()
+{
+}
+
+QScriptValue QDeclarativeContextScriptClass::newContext(QDeclarativeContextData *context, QObject *scopeObject)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new ContextData(context, scopeObject));
+}
+
+QScriptValue QDeclarativeContextScriptClass::newUrlContext(QDeclarativeContextData *context, QObject *scopeObject,
+ const QString &url)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new UrlContextData(context, scopeObject, url));
+}
+
+QScriptValue QDeclarativeContextScriptClass::newUrlContext(const QString &url)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new UrlContextData(url));
+}
+
+QScriptValue QDeclarativeContextScriptClass::newSharedContext()
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new ContextData());
+}
+
+QDeclarativeContextData *QDeclarativeContextScriptClass::contextFromValue(const QScriptValue &v)
+{
+ if (scriptClass(v) != this)
+ return 0;
+
+ ContextData *data = (ContextData *)object(v);
+ return data->getContext(engine);
+}
+
+QUrl QDeclarativeContextScriptClass::urlFromValue(const QScriptValue &v)
+{
+ if (scriptClass(v) != this)
+ return QUrl();
+
+ ContextData *data = (ContextData *)object(v);
+ if (data->isUrlContext) {
+ return QUrl(static_cast<UrlContextData *>(data)->url);
+ } else {
+ return QUrl();
+ }
+}
+
+QObject *QDeclarativeContextScriptClass::setOverrideObject(QScriptValue &v, QObject *override)
+{
+ if (scriptClass(v) != this)
+ return 0;
+
+ ContextData *data = (ContextData *)object(v);
+ QObject *rv = data->overrideObject;
+ data->overrideObject = override;
+ return rv;
+}
+
+QScriptClass::QueryFlags
+QDeclarativeContextScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(flags);
+
+ lastScopeObject = 0;
+ lastContext = 0;
+ lastData = 0;
+ lastPropertyIndex = -1;
+
+ QDeclarativeContextData *bindContext = ((ContextData *)object)->getContext(engine);
+ QObject *scopeObject = ((ContextData *)object)->getScope(engine);
+ if (!bindContext)
+ return 0;
+
+ QObject *overrideObject = ((ContextData *)object)->overrideObject;
+ if (overrideObject) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QScriptClass::QueryFlags rv =
+ ep->objectClass->queryProperty(overrideObject, name, flags, bindContext,
+ QDeclarativeObjectScriptClass::ImplicitObject |
+ QDeclarativeObjectScriptClass::SkipAttachedProperties);
+ if (rv) {
+ lastScopeObject = overrideObject;
+ lastContext = bindContext;
+ return rv;
+ }
+ }
+
+ bool includeTypes = true;
+ while (bindContext) {
+ QScriptClass::QueryFlags rv =
+ queryProperty(bindContext, scopeObject, name, flags, includeTypes);
+ scopeObject = 0; // Only applies to the first context
+ includeTypes = false; // Only applies to the first context
+ if (rv) return rv;
+ bindContext = bindContext->parent;
+ }
+
+ return 0;
+}
+
+QScriptClass::QueryFlags
+QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindContext, QObject *scopeObject,
+ const Identifier &name,
+ QScriptClass::QueryFlags flags,
+ bool includeTypes)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ lastPropertyIndex = bindContext->propertyNames?bindContext->propertyNames->value(name):-1;
+ if (lastPropertyIndex != -1) {
+ lastContext = bindContext;
+ return QScriptClass::HandlesReadAccess;
+ }
+
+ if (includeTypes && bindContext->imports) {
+ QDeclarativeTypeNameCache::Data *data = bindContext->imports->data(name);
+
+ if (data) {
+ lastData = data;
+ lastContext = bindContext;
+ lastScopeObject = scopeObject;
+ return QScriptClass::HandlesReadAccess;
+ }
+ }
+
+ if (scopeObject) {
+ QScriptClass::QueryFlags rv =
+ ep->objectClass->queryProperty(scopeObject, name, flags, bindContext,
+ QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
+ if (rv) {
+ lastScopeObject = scopeObject;
+ lastContext = bindContext;
+ return rv;
+ }
+ }
+
+ if (bindContext->contextObject) {
+ QScriptClass::QueryFlags rv =
+ ep->objectClass->queryProperty(bindContext->contextObject, name, flags, bindContext,
+ QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
+
+ if (rv) {
+ lastScopeObject = bindContext->contextObject;
+ lastContext = bindContext;
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+QDeclarativeContextScriptClass::Value
+QDeclarativeContextScriptClass::property(Object *object, const Identifier &name)
+{
+ Q_UNUSED(object);
+
+ QDeclarativeContextData *bindContext = lastContext;
+ Q_ASSERT(bindContext);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (lastData) {
+
+ if (lastData->type) {
+ return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type));
+ } else if (lastData->typeNamespace) {
+ return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace));
+ } else {
+ int index = lastData->importedScriptIndex;
+ if (index < bindContext->importedScripts.count()) {
+ return Value(scriptEngine, bindContext->importedScripts.at(index));
+ } else {
+ return Value();
+ }
+ }
+
+ } else if (lastScopeObject) {
+
+ return ep->objectClass->property(lastScopeObject, name);
+
+ } else if (lastPropertyIndex != -1) {
+
+ QScriptValue rv;
+ if (lastPropertyIndex < bindContext->idValueCount) {
+ rv = ep->objectClass->newQObject(bindContext->idValues[lastPropertyIndex].data());
+
+ if (ep->captureProperties)
+ ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(&bindContext->idValues[lastPropertyIndex].bindings);
+ } else {
+ QDeclarativeContextPrivate *cp = bindContext->asQDeclarativeContextPrivate();
+ const QVariant &value = cp->propertyValues.at(lastPropertyIndex);
+ if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
+ rv = ep->listClass->newList(QDeclarativeListProperty<QObject>(bindContext->asQDeclarativeContext(), (void*)lastPropertyIndex, 0, QDeclarativeContextPrivate::context_count, QDeclarativeContextPrivate::context_at), qMetaTypeId<QDeclarativeListProperty<QObject> >());
+ } else {
+ rv = ep->scriptValueFromVariant(value);
+ }
+
+ if (ep->captureProperties)
+ ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(bindContext->asQDeclarativeContext(), -1, lastPropertyIndex + cp->notifyIndex);
+ }
+
+ return Value(scriptEngine, rv);
+
+ } else {
+
+ return Value(scriptEngine, lastFunction);
+
+ }
+}
+
+void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifier &name,
+ const QScriptValue &value)
+{
+ Q_UNUSED(object);
+ Q_ASSERT(lastScopeObject);
+
+ QDeclarativeContextData *bindContext = lastContext;
+ Q_ASSERT(bindContext);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ ep->objectClass->setProperty(lastScopeObject, name, value, context(), bindContext);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecontextscriptclass_p.h b/src/declarative/qml/qdeclarativecontextscriptclass_p.h
new file mode 100644
index 0000000000..26d82724f3
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecontextscriptclass_p.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 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 QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+#define QDECLARATIVECONTEXTSCRIPTCLASS_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/qdeclarativetypenamecache_p.h"
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeContextData;
+class QDeclarativeContextScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeContextScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeContextScriptClass();
+
+ QScriptValue newContext(QDeclarativeContextData *, QObject * = 0);
+ QScriptValue newUrlContext(QDeclarativeContextData *, QObject *, const QString &);
+ QScriptValue newUrlContext(const QString &);
+ QScriptValue newSharedContext();
+
+ QDeclarativeContextData *contextFromValue(const QScriptValue &);
+ QUrl urlFromValue(const QScriptValue &);
+
+ QObject *setOverrideObject(QScriptValue &, QObject *);
+
+protected:
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+
+private:
+ QScriptClass::QueryFlags queryProperty(QDeclarativeContextData *, QObject *scopeObject,
+ const Identifier &,
+ QScriptClass::QueryFlags flags,
+ bool includeTypes);
+
+ QDeclarativeEngine *engine;
+
+ QObject *lastScopeObject;
+ QDeclarativeContextData *lastContext;
+ QDeclarativeTypeNameCache::Data *lastData;
+ int lastPropertyIndex;
+ QScriptValue lastFunction;
+
+ uint m_id;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+
diff --git a/src/declarative/qml/qdeclarativecustomparser.cpp b/src/declarative/qml/qdeclarativecustomparser.cpp
new file mode 100644
index 0000000000..856108c87b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecustomparser.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativecustomparser_p.h"
+#include "private/qdeclarativecustomparser_p_p.h"
+
+#include "private/qdeclarativeparser_p.h"
+#include "private/qdeclarativecompiler_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeParser;
+
+/*!
+ \class QDeclarativeCustomParser
+ \brief The QDeclarativeCustomParser class allows you to add new arbitrary types to QML.
+ \internal
+
+ By subclassing QDeclarativeCustomParser, you can add a parser for
+ building a particular type.
+
+ The subclass must implement compile() and setCustomData(), and register
+ itself in the meta type system by calling the macro:
+
+ \code
+ QML_REGISTER_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass)
+ \endcode
+*/
+
+/*
+ \fn QByteArray QDeclarativeCustomParser::compile(const QList<QDeclarativeCustomParserProperty> & properties)
+
+ The custom parser processes \a properties, and returns
+ a QByteArray containing data meaningful only to the
+ custom parser; the type engine will pass this same data to
+ setCustomData() when making an instance of the data.
+
+ Errors must be reported via the error() functions.
+
+ The QByteArray may be cached between executions of the system, so
+ it must contain correctly-serialized data (not, for example,
+ pointers to stack objects).
+*/
+
+/*
+ \fn void QDeclarativeCustomParser::setCustomData(QObject *object, const QByteArray &data)
+
+ This function sets \a object to have the properties defined
+ by \a data, which is a block of data previously returned by a call
+ to compile().
+
+ Errors should be reported using qmlInfo(object).
+
+ The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE.
+*/
+
+QDeclarativeCustomParserNode
+QDeclarativeCustomParserNodePrivate::fromObject(QDeclarativeParser::Object *root)
+{
+ QDeclarativeCustomParserNode rootNode;
+ rootNode.d->name = root->typeName;
+ rootNode.d->location = root->location.start;
+
+ for(QHash<QByteArray, Property *>::Iterator iter = root->properties.begin();
+ iter != root->properties.end();
+ ++iter) {
+
+ Property *p = *iter;
+
+ rootNode.d->properties << fromProperty(p);
+ }
+
+ if (root->defaultProperty)
+ rootNode.d->properties << fromProperty(root->defaultProperty);
+
+ return rootNode;
+}
+
+QDeclarativeCustomParserProperty
+QDeclarativeCustomParserNodePrivate::fromProperty(QDeclarativeParser::Property *p)
+{
+ QDeclarativeCustomParserProperty prop;
+ prop.d->name = p->name;
+ prop.d->isList = (p->values.count() > 1);
+ prop.d->location = p->location.start;
+
+ if (p->value) {
+ QDeclarativeCustomParserNode node = fromObject(p->value);
+ QList<QDeclarativeCustomParserProperty> props = node.properties();
+ for (int ii = 0; ii < props.count(); ++ii)
+ prop.d->values << QVariant::fromValue(props.at(ii));
+ } else {
+ for(int ii = 0; ii < p->values.count(); ++ii) {
+ QDeclarativeParser::Value *v = p->values.at(ii);
+ v->type = QDeclarativeParser::Value::Literal;
+
+ if(v->object) {
+ QDeclarativeCustomParserNode node = fromObject(v->object);
+ prop.d->values << QVariant::fromValue(node);
+ } else {
+ prop.d->values << QVariant::fromValue(v->value);
+ }
+
+ }
+ }
+
+ return prop;
+}
+
+QDeclarativeCustomParserNode::QDeclarativeCustomParserNode()
+: d(new QDeclarativeCustomParserNodePrivate)
+{
+}
+
+QDeclarativeCustomParserNode::QDeclarativeCustomParserNode(const QDeclarativeCustomParserNode &other)
+: d(new QDeclarativeCustomParserNodePrivate)
+{
+ *this = other;
+}
+
+QDeclarativeCustomParserNode &QDeclarativeCustomParserNode::operator=(const QDeclarativeCustomParserNode &other)
+{
+ d->name = other.d->name;
+ d->properties = other.d->properties;
+ d->location = other.d->location;
+ return *this;
+}
+
+QDeclarativeCustomParserNode::~QDeclarativeCustomParserNode()
+{
+ delete d; d = 0;
+}
+
+QByteArray QDeclarativeCustomParserNode::name() const
+{
+ return d->name;
+}
+
+QList<QDeclarativeCustomParserProperty> QDeclarativeCustomParserNode::properties() const
+{
+ return d->properties;
+}
+
+QDeclarativeParser::Location QDeclarativeCustomParserNode::location() const
+{
+ return d->location;
+}
+
+QDeclarativeCustomParserProperty::QDeclarativeCustomParserProperty()
+: d(new QDeclarativeCustomParserPropertyPrivate)
+{
+}
+
+QDeclarativeCustomParserProperty::QDeclarativeCustomParserProperty(const QDeclarativeCustomParserProperty &other)
+: d(new QDeclarativeCustomParserPropertyPrivate)
+{
+ *this = other;
+}
+
+QDeclarativeCustomParserProperty &QDeclarativeCustomParserProperty::operator=(const QDeclarativeCustomParserProperty &other)
+{
+ d->name = other.d->name;
+ d->isList = other.d->isList;
+ d->values = other.d->values;
+ d->location = other.d->location;
+ return *this;
+}
+
+QDeclarativeCustomParserProperty::~QDeclarativeCustomParserProperty()
+{
+ delete d; d = 0;
+}
+
+QByteArray QDeclarativeCustomParserProperty::name() const
+{
+ return d->name;
+}
+
+bool QDeclarativeCustomParserProperty::isList() const
+{
+ return d->isList;
+}
+
+QDeclarativeParser::Location QDeclarativeCustomParserProperty::location() const
+{
+ return d->location;
+}
+
+QList<QVariant> QDeclarativeCustomParserProperty::assignedValues() const
+{
+ return d->values;
+}
+
+void QDeclarativeCustomParser::clearErrors()
+{
+ exceptions.clear();
+}
+
+/*!
+ Reports an error with the given \a description.
+
+ This can only be used during the compile() step. For errors during setCustomData(), use qmlInfo().
+
+ An error is generated referring to the position of the element in the source file.
+*/
+void QDeclarativeCustomParser::error(const QString& description)
+{
+ Q_ASSERT(object);
+ QDeclarativeError error;
+ QString exceptionDescription;
+ error.setLine(object->location.start.line);
+ error.setColumn(object->location.start.column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ Reports an error in parsing \a prop, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QDeclarativeCustomParser::error(const QDeclarativeCustomParserProperty& prop, const QString& description)
+{
+ QDeclarativeError error;
+ QString exceptionDescription;
+ error.setLine(prop.location().line);
+ error.setColumn(prop.location().column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ Reports an error in parsing \a node, with the given \a description.
+
+ An error is generated referring to the position of \a node in the source file.
+*/
+void QDeclarativeCustomParser::error(const QDeclarativeCustomParserNode& node, const QString& description)
+{
+ QDeclarativeError error;
+ QString exceptionDescription;
+ error.setLine(node.location().line);
+ error.setColumn(node.location().column);
+ error.setDescription(description);
+ exceptions << error;
+}
+
+/*!
+ If \a script is a simply enum expression (eg. Text.AlignLeft),
+ returns the integer equivalent (eg. 1).
+
+ Otherwise, returns -1.
+*/
+int QDeclarativeCustomParser::evaluateEnum(const QByteArray& script) const
+{
+ return compiler->evaluateEnum(script);
+}
+
+/*!
+ Resolves \a name to a type, or 0 if it is not a type. This can be used
+ to type-check object nodes.
+*/
+const QMetaObject *QDeclarativeCustomParser::resolveType(const QByteArray& name) const
+{
+ return compiler->resolveType(name);
+}
+
+/*!
+ Rewrites \a expression and returns an identifier that can be
+ used to construct the binding later. \a name
+ is used as the name of the rewritten function.
+*/
+QDeclarativeBinding::Identifier QDeclarativeCustomParser::rewriteBinding(const QString& expression, const QByteArray& name)
+{
+ return compiler->rewriteBinding(expression, name);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h
new file mode 100644
index 0000000000..be9f5146e1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecustomparser_p.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVECUSTOMPARSER_H
+#define QDECLARATIVECUSTOMPARSER_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/qdeclarativemetatype_p.h"
+#include "qdeclarativeerror.h"
+#include "private/qdeclarativeparser_p.h"
+#include "private/qdeclarativebinding_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qxmlstream.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeCompiler;
+
+class QDeclarativeCustomParserPropertyPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeCustomParserProperty
+{
+public:
+ QDeclarativeCustomParserProperty();
+ QDeclarativeCustomParserProperty(const QDeclarativeCustomParserProperty &);
+ QDeclarativeCustomParserProperty &operator=(const QDeclarativeCustomParserProperty &);
+ ~QDeclarativeCustomParserProperty();
+
+ QByteArray name() const;
+ QDeclarativeParser::Location location() const;
+
+ bool isList() const;
+ // Will be one of QDeclarativeParser::Variant, QDeclarativeCustomParserProperty or
+ // QDeclarativeCustomParserNode
+ QList<QVariant> assignedValues() const;
+
+private:
+ friend class QDeclarativeCustomParserNodePrivate;
+ friend class QDeclarativeCustomParserPropertyPrivate;
+ QDeclarativeCustomParserPropertyPrivate *d;
+};
+
+class QDeclarativeCustomParserNodePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeCustomParserNode
+{
+public:
+ QDeclarativeCustomParserNode();
+ QDeclarativeCustomParserNode(const QDeclarativeCustomParserNode &);
+ QDeclarativeCustomParserNode &operator=(const QDeclarativeCustomParserNode &);
+ ~QDeclarativeCustomParserNode();
+
+ QByteArray name() const;
+ QDeclarativeParser::Location location() const;
+
+ QList<QDeclarativeCustomParserProperty> properties() const;
+
+private:
+ friend class QDeclarativeCustomParserNodePrivate;
+ QDeclarativeCustomParserNodePrivate *d;
+};
+
+class Q_DECLARATIVE_EXPORT QDeclarativeCustomParser
+{
+public:
+ enum Flag {
+ NoFlag = 0x00000000,
+ AcceptsAttachedProperties = 0x00000001
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QDeclarativeCustomParser() : compiler(0), object(0), m_flags(NoFlag) {}
+ QDeclarativeCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {}
+ virtual ~QDeclarativeCustomParser() {}
+
+ void clearErrors();
+ Flags flags() const { return m_flags; }
+
+ virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &)=0;
+ virtual void setCustomData(QObject *, const QByteArray &)=0;
+
+ QList<QDeclarativeError> errors() const { return exceptions; }
+
+protected:
+ void error(const QString& description);
+ void error(const QDeclarativeCustomParserProperty&, const QString& description);
+ void error(const QDeclarativeCustomParserNode&, const QString& description);
+
+ int evaluateEnum(const QByteArray&) const;
+
+ const QMetaObject *resolveType(const QByteArray&) const;
+
+ QDeclarativeBinding::Identifier rewriteBinding(const QString&, const QByteArray&);
+
+private:
+ QList<QDeclarativeError> exceptions;
+ QDeclarativeCompiler *compiler;
+ QDeclarativeParser::Object *object;
+ Flags m_flags;
+ friend class QDeclarativeCompiler;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeCustomParser::Flags);
+
+#if 0
+#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \
+ qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE)
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeCustomParserProperty)
+Q_DECLARE_METATYPE(QDeclarativeCustomParserNode)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/qml/qdeclarativecustomparser_p_p.h b/src/declarative/qml/qdeclarativecustomparser_p_p.h
new file mode 100644
index 0000000000..acfbfe789e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativecustomparser_p_p.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 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 QDECLARATIVECUSTOMPARSER_P_H
+#define QDECLARATIVECUSTOMPARSER_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/qdeclarativecustomparser_p.h"
+
+#include "private/qdeclarativeparser_p.h"
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeCustomParserNodePrivate
+{
+public:
+ QByteArray name;
+ QList<QDeclarativeCustomParserProperty> properties;
+ QDeclarativeParser::Location location;
+
+ static QDeclarativeCustomParserNode fromObject(QDeclarativeParser::Object *);
+ static QDeclarativeCustomParserProperty fromProperty(QDeclarativeParser::Property *);
+};
+
+class QDeclarativeCustomParserPropertyPrivate
+{
+public:
+ QDeclarativeCustomParserPropertyPrivate()
+ : isList(false) {}
+
+ QByteArray name;
+ bool isList;
+ QDeclarativeParser::Location location;
+ QList<QVariant> values;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVECUSTOMPARSER_P_H
diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h
new file mode 100644
index 0000000000..33458dc2f4
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedata_p.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEDATA_P_H
+#define QDECLARATIVEDATA_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 <QtScript/qscriptvalue.h>
+#include <private/qobject_p.h>
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeCompiledData;
+class QDeclarativeAbstractBinding;
+class QDeclarativeContext;
+class QDeclarativePropertyCache;
+class QDeclarativeContextData;
+class QDeclarativeNotifier;
+class QDeclarativeDataExtended;
+// This class is structured in such a way, that simply zero'ing it is the
+// default state for elemental object allocations. This is crucial in the
+// workings of the QDeclarativeInstruction::CreateSimpleObject instruction.
+// Don't change anything here without first considering that case!
+class Q_AUTOTEST_EXPORT QDeclarativeData : public QAbstractDeclarativeData
+{
+public:
+ QDeclarativeData()
+ : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
+ context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0),
+ bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0),
+ scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) {
+ init();
+ }
+
+ static inline void init() {
+ QAbstractDeclarativeData::destroyed = destroyed;
+ QAbstractDeclarativeData::parentChanged = parentChanged;
+ QAbstractDeclarativeData::objectNameChanged = objectNameChanged;
+ }
+
+ static void destroyed(QAbstractDeclarativeData *, QObject *);
+ static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *);
+ static void objectNameChanged(QAbstractDeclarativeData *, QObject *);
+
+ void destroyed(QObject *);
+ void parentChanged(QObject *, QObject *);
+ void objectNameChanged(QObject *);
+
+ void setImplicitDestructible() {
+ if (!explicitIndestructibleSet) indestructible = false;
+ }
+
+ quint32 ownMemory:1;
+ quint32 ownContext:1;
+ quint32 indestructible:1;
+ quint32 explicitIndestructibleSet:1;
+ quint32 dummy:28;
+
+ // The context that created the C++ object
+ QDeclarativeContextData *context;
+ // The outermost context in which this object lives
+ QDeclarativeContextData *outerContext;
+
+ QDeclarativeAbstractBinding *bindings;
+
+ // Linked list for QDeclarativeContext::contextObjects
+ QDeclarativeData *nextContextObject;
+ QDeclarativeData**prevContextObject;
+
+ int bindingBitsSize;
+ quint32 *bindingBits;
+ bool hasBindingBit(int) const;
+ void clearBindingBit(int);
+ void setBindingBit(QObject *obj, int);
+
+ ushort lineNumber;
+ ushort columnNumber;
+
+ QDeclarativeCompiledData *deferredComponent; // Can't this be found from the context?
+ unsigned int deferredIdx;
+
+ // ### Can we make this QScriptValuePrivate so we incur no additional allocation
+ // cost?
+ QScriptValue *scriptValue;
+ quint32 objectDataRefCount;
+ QDeclarativePropertyCache *propertyCache;
+
+ QDeclarativeGuard<QObject> *guards;
+
+ static QDeclarativeData *get(const QObject *object, bool create = false) {
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+ if (priv->wasDeleted) {
+ Q_ASSERT(!create);
+ return 0;
+ } else if (priv->declarativeData) {
+ return static_cast<QDeclarativeData *>(priv->declarativeData);
+ } else if (create) {
+ priv->declarativeData = new QDeclarativeData;
+ return static_cast<QDeclarativeData *>(priv->declarativeData);
+ } else {
+ return 0;
+ }
+ }
+
+ bool hasExtendedData() const { return extendedData != 0; }
+ QDeclarativeNotifier *objectNameNotifier() const;
+ QHash<int, QObject *> *attachedProperties() const;
+
+private:
+ // For objectNameNotifier and attachedProperties
+ mutable QDeclarativeDataExtended *extendedData;
+};
+
+template<class T>
+void QDeclarativeGuard<T>::addGuard()
+{
+ Q_ASSERT(!prev);
+
+ if (QObjectPrivate::get(o)->wasDeleted)
+ return;
+
+ QDeclarativeData *data = QDeclarativeData::get(o, true);
+ next = data->guards;
+ if (next) reinterpret_cast<QDeclarativeGuard<T> *>(next)->prev = &next;
+ data->guards = reinterpret_cast<QDeclarativeGuard<QObject> *>(this);
+ prev = &data->guards;
+}
+
+template<class T>
+void QDeclarativeGuard<T>::remGuard()
+{
+ Q_ASSERT(prev);
+
+ if (next) reinterpret_cast<QDeclarativeGuard<T> *>(next)->prev = prev;
+ *prev = next;
+ next = 0;
+ prev = 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEDATA_P_H
diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp
new file mode 100644
index 0000000000..b5ad33d63e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedirparser.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativedirparser_p.h"
+#include "qdeclarativeerror.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeDirParser::QDeclarativeDirParser()
+ : _isParsed(false)
+{
+}
+
+QDeclarativeDirParser::~QDeclarativeDirParser()
+{
+}
+
+QUrl QDeclarativeDirParser::url() const
+{
+ return _url;
+}
+
+void QDeclarativeDirParser::setUrl(const QUrl &url)
+{
+ _url = url;
+}
+
+QString QDeclarativeDirParser::source() const
+{
+ return _source;
+}
+
+void QDeclarativeDirParser::setSource(const QString &source)
+{
+ _isParsed = false;
+ _source = source;
+}
+
+bool QDeclarativeDirParser::isParsed() const
+{
+ return _isParsed;
+}
+
+bool QDeclarativeDirParser::parse()
+{
+ if (_isParsed)
+ return true;
+
+ _isParsed = true;
+ _errors.clear();
+ _plugins.clear();
+ _components.clear();
+
+ QTextStream stream(&_source);
+ int lineNumber = 0;
+
+ forever {
+ ++lineNumber;
+
+ const QString line = stream.readLine();
+ if (line.isNull())
+ break;
+
+ QString sections[3];
+ int sectionCount = 0;
+
+ int index = 0;
+ const int length = line.length();
+
+ while (index != length) {
+ const QChar ch = line.at(index);
+
+ if (ch.isSpace()) {
+ do { ++index; }
+ while (index != length && line.at(index).isSpace());
+
+ } else if (ch == QLatin1Char('#')) {
+ // recognized a comment
+ break;
+
+ } else {
+ const int start = index;
+
+ do { ++index; }
+ while (index != length && !line.at(index).isSpace());
+
+ const QString lexeme = line.mid(start, index - start);
+
+ if (sectionCount >= 3) {
+ reportError(lineNumber, start, QLatin1String("unexpected token"));
+
+ } else {
+ sections[sectionCount++] = lexeme;
+ }
+ }
+ }
+
+ if (sectionCount == 0) {
+ continue; // no sections, no party.
+
+ } 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));
+
+ continue;
+ }
+
+ const Plugin entry(sections[1], sections[2]);
+
+ _plugins.append(entry);
+
+ } 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));
+ continue;
+ }
+ Component entry(sections[1], sections[2], -1, -1);
+ entry.internal = true;
+ _components.append(entry);
+
+ } else if (sectionCount == 2) {
+ // No version specified (should only be used for relative qmldir files)
+ const Component entry(sections[0], sections[1], -1, -1);
+ _components.append(entry);
+ } else if (sectionCount == 3) {
+ const QString &version = sections[1];
+ const int dotIndex = version.indexOf(QLatin1Char('.'));
+
+ if (dotIndex == -1) {
+ reportError(lineNumber, -1, QLatin1String("expected '.'"));
+ } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) {
+ reportError(lineNumber, -1, QLatin1String("unexpected '.'"));
+ } else {
+ bool validVersionNumber = false;
+ const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber);
+
+ if (validVersionNumber) {
+ const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber);
+
+ if (validVersionNumber) {
+ const Component entry(sections[0], sections[2], majorVersion, minorVersion);
+
+ _components.append(entry);
+ }
+ }
+ }
+ } else {
+ reportError(lineNumber, -1,
+ QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided").arg(sectionCount + 1));
+ }
+ }
+
+ return hasError();
+}
+
+void QDeclarativeDirParser::reportError(int line, int column, const QString &description)
+{
+ QDeclarativeError error;
+ error.setUrl(_url);
+ error.setLine(line);
+ error.setColumn(column);
+ error.setDescription(description);
+ _errors.append(error);
+}
+
+bool QDeclarativeDirParser::hasError() const
+{
+ if (! _errors.isEmpty())
+ return true;
+
+ return false;
+}
+
+QList<QDeclarativeError> QDeclarativeDirParser::errors() const
+{
+ return _errors;
+}
+
+QList<QDeclarativeDirParser::Plugin> QDeclarativeDirParser::plugins() const
+{
+ return _plugins;
+}
+
+QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() const
+{
+ return _components;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h
new file mode 100644
index 0000000000..95f14bc487
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedirparser_p.h
@@ -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 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 QDECLARATIVEDIRPARSER_P_H
+#define QDECLARATIVEDIRPARSER_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/QUrl>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeError;
+class QDeclarativeDirParser
+{
+ Q_DISABLE_COPY(QDeclarativeDirParser)
+
+public:
+ QDeclarativeDirParser();
+ ~QDeclarativeDirParser();
+
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+ QString source() const;
+ void setSource(const QString &source);
+
+ bool isParsed() const;
+ bool parse();
+
+ bool hasError() const;
+ QList<QDeclarativeError> errors() const;
+
+ struct Plugin
+ {
+ Plugin() {}
+
+ Plugin(const QString &name, const QString &path)
+ : name(name), path(path) {}
+
+ QString name;
+ QString path;
+ };
+
+ struct Component
+ {
+ Component()
+ : majorVersion(0), minorVersion(0), internal(false) {}
+
+ Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
+ : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
+ internal(false) {}
+
+ QString typeName;
+ QString fileName;
+ int majorVersion;
+ int minorVersion;
+ bool internal;
+ };
+
+ QList<Component> components() const;
+ QList<Plugin> plugins() const;
+
+private:
+ void reportError(int line, int column, const QString &message);
+
+private:
+ QList<QDeclarativeError> _errors;
+ QUrl _url;
+ QString _source;
+ QList<Component> _components;
+ QList<Plugin> _plugins;
+ unsigned _isParsed: 1;
+};
+
+typedef QList<QDeclarativeDirParser::Component> QDeclarativeDirComponents;
+
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEDIRPARSER_P_H
diff --git a/src/declarative/qml/qdeclarativedom.cpp b/src/declarative/qml/qdeclarativedom.cpp
new file mode 100644
index 0000000000..f1296aaf18
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedom.cpp
@@ -0,0 +1,1835 @@
+/****************************************************************************
+**
+** Copyright (C) 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
new file mode 100644
index 0000000000..64300d47e7
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedom_p.h
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** Copyright (C) 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
new file mode 100644
index 0000000000..7ce99ec74d
--- /dev/null
+++ b/src/declarative/qml/qdeclarativedom_p_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..9fde18c81c
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -0,0 +1,2512 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeengine_p.h"
+#include "qdeclarativeengine.h"
+
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "qdeclarative.h"
+#include "qdeclarativecontext.h"
+#include "qdeclarativeexpression.h"
+#include "qdeclarativecomponent.h"
+#include "private/qdeclarativebinding_p_p.h"
+#include "private/qdeclarativevme_p.h"
+#include "private/qdeclarativeenginedebug_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qdeclarativexmlhttprequest_p.h"
+#include "private/qdeclarativesqldatabase_p.h"
+#include "private/qdeclarativetypenamescriptclass_p.h"
+#include "private/qdeclarativelistscriptclass_p.h"
+#include "qdeclarativescriptstring.h"
+#include "private/qdeclarativeglobal_p.h"
+#include "private/qdeclarativeworkerscript_p.h"
+#include "private/qdeclarativecomponent_p.h"
+#include "qdeclarativenetworkaccessmanagerfactory.h"
+#include "qdeclarativeimageprovider.h"
+#include "private/qdeclarativedirparser_p.h"
+#include "qdeclarativeextensioninterface.h"
+#include "private/qdeclarativelist_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+#include "private/qdeclarativeinclude_p.h"
+#include "private/qdeclarativenotifier_p.h"
+#include "private/qdeclarativedebugtrace_p.h"
+#include "private/qdeclarativeapplication_p.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QScriptClass>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QNetworkAccessManager>
+#include <QDesktopServices>
+#include <QTimer>
+#include <QList>
+#include <QPair>
+#include <QDebug>
+#include <QMetaObject>
+#include <QStack>
+#include <QMap>
+#include <QPluginLoader>
+#include <QtGui/qfontdatabase.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qthreadstorage.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qsound.h>
+#include <QtCore/qcryptographichash.h>
+
+#include <private/qobject_p.h>
+#include <private/qscriptdeclarativeclass_p.h>
+
+#include <private/qdeclarativeitemsmodule_p.h>
+#include <private/qdeclarativeutilmodule_p.h>
+
+#ifdef Q_OS_WIN // for %APPDATA%
+#include <qt_windows.h>
+#include <qlibrary.h>
+#include <windows.h>
+
+#define CSIDL_APPDATA 0x001a // <username>\Application Data
+#endif
+
+Q_DECLARE_METATYPE(QDeclarativeProperty)
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass QtObject QObject
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The QtObject element is the most basic element in QML.
+
+ The QtObject element is a non-visual element which contains only the
+ objectName property.
+
+ It can be useful to create a QtObject if you need an extremely
+ lightweight element to enclose a set of custom properties:
+
+ \snippet doc/src/snippets/declarative/qtobject.qml 0
+
+ It can also be useful for C++ integration, as it is just a plain
+ QObject. See the QObject documentation for further details.
+*/
+/*!
+ \qmlproperty string QML:QtObject::objectName
+ This property holds the QObject::objectName for this specific object instance.
+
+ This allows a C++ application to locate an item within a QML component
+ using the QObject::findChild() method. For example, the following C++
+ application locates the child \l Rectangle item and dynamically changes its
+ \c color value:
+
+ \qml
+ // MyRect.qml
+
+ import QtQuick 1.0
+
+ Item {
+ width: 200; height: 200
+
+ Rectangle {
+ anchors.fill: parent
+ color: "red"
+ objectName: "myRect"
+ }
+ }
+ \endqml
+
+ \code
+ // main.cpp
+
+ QDeclarativeView view;
+ view.setSource(QUrl::fromLocalFile("MyRect.qml"));
+ view.show();
+
+ QDeclarativeItem *item = view.rootObject()->findChild<QDeclarativeItem*>("myRect");
+ if (item)
+ item->setProperty("color", QColor(Qt::yellow));
+ \endcode
+*/
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+static bool qt_QmlQtModule_registered = false;
+bool QDeclarativeEnginePrivate::qml_debugging_enabled = false;
+
+void QDeclarativeEnginePrivate::defineModule()
+{
+ qmlRegisterType<QDeclarativeComponent>("QtQuick",1,0,"Component");
+ qmlRegisterType<QObject>("QtQuick",1,0,"QtObject");
+ qmlRegisterType<QDeclarativeWorkerScript>("QtQuick",1,0,"WorkerScript");
+
+#ifndef QT_NO_IMPORT_QT47_QML
+ qmlRegisterType<QDeclarativeComponent>("Qt",4,7,"Component");
+ qmlRegisterType<QObject>("Qt",4,7,"QtObject");
+ qmlRegisterType<QDeclarativeWorkerScript>("Qt",4,7,"WorkerScript");
+#endif
+
+ qmlRegisterType<QDeclarativeBinding>();
+}
+
+/*!
+\qmlclass QML:Qt QDeclarativeEnginePrivate
+ \ingroup qml-utility-elements
+\brief The QML global Qt object provides useful enums and functions from Qt.
+
+\keyword QmlGlobalQtObject
+
+\brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files.
+
+The \c Qt object is a global object with utility functions, properties and enums.
+
+It is not instantiable; to use it, call the members of the global \c Qt object directly.
+For example:
+
+\qml
+import QtQuick 1.0
+
+Text {
+ color: Qt.rgba(1, 0, 0, 1)
+ text: Qt.md5("hello, world")
+}
+\endqml
+
+
+\section1 Enums
+
+The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access
+the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton.
+
+
+\section1 Types
+The Qt object also contains helper functions for creating objects of specific
+data types. This is primarily useful when setting the properties of an item
+when the property has one of the following types:
+
+\list
+\o \c color - use \l{QML:Qt::rgba()}{Qt.rgba()}, \l{QML:Qt::hsla()}{Qt.hsla()}, \l{QML:Qt::darker()}{Qt.darker()}, \l{QML:Qt::lighter()}{Qt.lighter()} or \l{QML:Qt::tint()}{Qt.tint()}
+\o \c rect - use \l{QML:Qt::rect()}{Qt.rect()}
+\o \c point - use \l{QML:Qt::point()}{Qt.point()}
+\o \c size - use \l{QML:Qt::size()}{Qt.size()}
+\o \c vector3d - use \l{QML:Qt::vector3d()}{Qt.vector3d()}
+\endlist
+
+There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information.
+
+\section1 Date/Time Formatters
+
+The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
+
+\list
+ \o \l{QML:Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
+ \o \l{QML:Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
+ \o \l{QML:Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
+\endlist
+
+The format specification is described at \l{QML:Qt::formatDateTime}{Qt.formatDateTime}.
+
+
+\section1 Dynamic Object Creation
+The following functions on the global object allow you to dynamically create QML
+items from files or strings. See \l{Dynamic Object Management in QML} for an overview
+of their use.
+
+\list
+ \o \l{QML:Qt::createComponent()}{object Qt.createComponent(url)}
+ \o \l{QML:Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
+\endlist
+*/
+
+
+/*!
+ \qmlproperty object QML:Qt::application
+ \since QtQuick 1.1
+
+ The \c application object provides access to global application state
+ properties shared by many QML components.
+
+ Its properties are:
+
+ \table
+ \row
+ \o \c application.active
+ \o
+ This read-only property indicates whether the application is the top-most and focused
+ application, and the user is able to interact with the application. The property
+ is false when the application is in the background, the device keylock or screen
+ saver is active, the screen backlight is turned off, or the global system dialog
+ is being displayed on top of the application. It can be used for stopping and
+ pausing animations, timers and active processing of data in order to save device
+ battery power and free device memory and processor load when the application is not
+ active.
+
+ \row
+ \o \c application.layoutDirection
+ \o
+ This read-only property can be used to query the default layout direction of the
+ application. On system start-up, the default layout direction depends on the
+ application's language. The property has a value of \c Qt.RightToLeft in locales
+ where text and graphic elements are read from right to left, and \c Qt.LeftToRight
+ where the reading direction flows from left to right. You can bind to this
+ property to customize your application layouts to support both layout directions.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight - Text and graphics elements should be positioned
+ from left to right.
+ \o Qt.RightToLeft - Text and graphics elements should be positioned
+ from right to left.
+ \endlist
+ \endtable
+
+ The following example uses the \c application object to indicate
+ whether the application is currently active:
+
+ \snippet doc/src/snippets/declarative/application.qml document
+
+*/
+
+
+/*!
+\qmlmethod object Qt::include(string url, jsobject callback)
+
+Includes another JavaScript file. This method can only be used from within JavaScript files,
+and not regular QML files.
+
+This imports all functions from \a url into the current script's namespace.
+
+Qt.include() returns an object that describes the status of the operation. The object has
+a single property, \c {status}, that is set to one of the following values:
+
+\table
+\header \o Symbol \o Value \o Description
+\row \o result.OK \o 0 \o The include completed successfully.
+\row \o result.LOADING \o 1 \o Data is being loaded from the network.
+\row \o result.NETWORK_ERROR \o 2 \o A network error occurred while fetching the url.
+\row \o result.EXCEPTION \o 3 \o A JavaScript exception occurred while executing the included code.
+An additional \c exception property will be set in this case.
+\endtable
+
+The \c status property will be updated as the operation progresses.
+
+If provided, \a callback is invoked when the operation completes. The callback is passed
+the same object as is returned from the Qt.include() call.
+*/
+// Qt.include() is implemented in qdeclarativeinclude.cpp
+
+
+QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
+: captureProperties(false), rootContext(0), isDebugging(false),
+ outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0),
+ 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)
+{
+ if (!qt_QmlQtModule_registered) {
+ qt_QmlQtModule_registered = true;
+ QDeclarativeItemModule::defineModule();
+ QDeclarativeUtilModule::defineModule();
+ QDeclarativeEnginePrivate::defineModule();
+ QDeclarativeValueTypeFactory::registerValueTypes();
+ }
+ globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
+}
+
+/*!
+ \qmlmethod url Qt::resolvedUrl(url url)
+ Returns \a url resolved relative to the URL of the caller.
+*/
+QUrl QDeclarativeScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url)
+{
+ if (p) {
+ QDeclarativeContextData *ctxt = p->getContext(context);
+ if (ctxt)
+ return ctxt->resolvedUrl(url);
+ else
+ return p->getUrl(context).resolved(url);
+ }
+ return baseUrl.resolved(url);
+}
+
+QDeclarativeScriptEngine::QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv)
+: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0)
+{
+ // Note that all documentation for stuff put on the global object goes in
+ // doc/src/declarative/globalobject.qdoc
+
+ bool mainthread = priv != 0;
+
+ QScriptValue qtObject =
+ newQMetaObject(StaticQtMetaObject::get());
+ globalObject().setProperty(QLatin1String("Qt"), qtObject);
+
+#ifndef QT_NO_DESKTOPSERVICES
+ offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator())
+ + QDir::separator() + QLatin1String("QML")
+ + QDir::separator() + QLatin1String("OfflineStorage");
+#endif
+
+#ifndef QT_NO_XMLSTREAMREADER
+ qt_add_qmlxmlhttprequest(this);
+#endif
+ qt_add_qmlsqldatabase(this);
+ // XXX A Multimedia "Qt.Sound" class also needs to be made available,
+ // XXX but we don't want a dependency in that cirection.
+ // XXX When the above a done some better way, that way should also be
+ // XXX used to add Qt.Sound class.
+
+ //types
+ if (mainthread)
+ qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::include, 2));
+ else
+ qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::worker_include, 2));
+
+ qtObject.setProperty(QLatin1String("isQtObject"), newFunction(QDeclarativeEnginePrivate::isQtObject, 1));
+ qtObject.setProperty(QLatin1String("rgba"), newFunction(QDeclarativeEnginePrivate::rgba, 4));
+ qtObject.setProperty(QLatin1String("hsla"), newFunction(QDeclarativeEnginePrivate::hsla, 4));
+ qtObject.setProperty(QLatin1String("rect"), newFunction(QDeclarativeEnginePrivate::rect, 4));
+ qtObject.setProperty(QLatin1String("point"), newFunction(QDeclarativeEnginePrivate::point, 2));
+ qtObject.setProperty(QLatin1String("size"), newFunction(QDeclarativeEnginePrivate::size, 2));
+ qtObject.setProperty(QLatin1String("vector3d"), newFunction(QDeclarativeEnginePrivate::vector3d, 3));
+
+ if (mainthread) {
+ //color helpers
+ qtObject.setProperty(QLatin1String("lighter"), newFunction(QDeclarativeEnginePrivate::lighter, 1));
+ qtObject.setProperty(QLatin1String("darker"), newFunction(QDeclarativeEnginePrivate::darker, 1));
+ qtObject.setProperty(QLatin1String("tint"), newFunction(QDeclarativeEnginePrivate::tint, 2));
+ }
+
+#ifndef QT_NO_DATESTRING
+ //date/time formatting
+ qtObject.setProperty(QLatin1String("formatDate"),newFunction(QDeclarativeEnginePrivate::formatDate, 2));
+ qtObject.setProperty(QLatin1String("formatTime"),newFunction(QDeclarativeEnginePrivate::formatTime, 2));
+ qtObject.setProperty(QLatin1String("formatDateTime"),newFunction(QDeclarativeEnginePrivate::formatDateTime, 2));
+#endif
+
+ //misc methods
+ qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QDeclarativeEnginePrivate::desktopOpenUrl, 1));
+ qtObject.setProperty(QLatin1String("fontFamilies"),newFunction(QDeclarativeEnginePrivate::fontFamilies, 0));
+ qtObject.setProperty(QLatin1String("md5"),newFunction(QDeclarativeEnginePrivate::md5, 1));
+ qtObject.setProperty(QLatin1String("btoa"),newFunction(QDeclarativeEnginePrivate::btoa, 1));
+ qtObject.setProperty(QLatin1String("atob"),newFunction(QDeclarativeEnginePrivate::atob, 1));
+ qtObject.setProperty(QLatin1String("quit"), newFunction(QDeclarativeEnginePrivate::quit, 0));
+ qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QDeclarativeScriptEngine::resolvedUrl, 1));
+
+ if (mainthread) {
+ qtObject.setProperty(QLatin1String("createQmlObject"),
+ newFunction(QDeclarativeEnginePrivate::createQmlObject, 1));
+ qtObject.setProperty(QLatin1String("createComponent"),
+ newFunction(QDeclarativeEnginePrivate::createComponent, 1));
+ }
+
+ //firebug/webkit compat
+ QScriptValue consoleObject = newObject();
+ consoleObject.setProperty(QLatin1String("log"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
+ consoleObject.setProperty(QLatin1String("debug"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
+ globalObject().setProperty(QLatin1String("console"), consoleObject);
+
+ // translation functions need to be installed
+ // before the global script class is constructed (QTBUG-6437)
+ installTranslatorFunctions();
+}
+
+QDeclarativeScriptEngine::~QDeclarativeScriptEngine()
+{
+ delete sqlQueryClass;
+ delete nodeListClass;
+ delete namedNodeMapClass;
+}
+
+QScriptValue QDeclarativeScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QString arg = ctxt->argument(0).toString();
+ QUrl r = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg));
+ return QScriptValue(r.toString());
+}
+
+QNetworkAccessManager *QDeclarativeScriptEngine::networkAccessManager()
+{
+ return p->getNetworkAccessManager();
+}
+
+QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
+{
+ Q_ASSERT(inProgressCreations == 0);
+ Q_ASSERT(bindValues.isEmpty());
+ Q_ASSERT(parserStatus.isEmpty());
+
+ while (cleanup) {
+ QDeclarativeCleanup *c = cleanup;
+ cleanup = c->next;
+ if (cleanup) cleanup->prev = &cleanup;
+ c->next = 0;
+ c->prev = 0;
+ c->clear();
+ }
+
+ delete rootContext;
+ rootContext = 0;
+ delete contextClass;
+ contextClass = 0;
+ delete objectClass;
+ objectClass = 0;
+ delete valueTypeClass;
+ valueTypeClass = 0;
+ delete typeNameClass;
+ typeNameClass = 0;
+ delete listClass;
+ listClass = 0;
+ delete globalClass;
+ globalClass = 0;
+
+ for(QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter)
+ (*iter)->release();
+ for(QHash<const QMetaObject *, QDeclarativePropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
+ (*iter)->release();
+ for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
+ (*iter)->release();
+
+}
+
+void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs)
+{
+ bvs.clear();
+}
+
+void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeParserStatus> &pss)
+{
+ for (int ii = 0; ii < pss.count; ++ii) {
+ QDeclarativeParserStatus *ps = pss.at(ii);
+ if(ps)
+ ps->d = 0;
+ }
+ pss.clear();
+}
+
+void QDeclarativePrivate::qdeclarativeelement_destructor(QObject *o)
+{
+ QObjectPrivate *p = QObjectPrivate::get(o);
+ if (p->declarativeData) {
+ QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData);
+ if (d->ownContext && d->context) {
+ d->context->destroy();
+ d->context = 0;
+ }
+ }
+}
+
+void QDeclarativeData::destroyed(QAbstractDeclarativeData *d, QObject *o)
+{
+ static_cast<QDeclarativeData *>(d)->destroyed(o);
+}
+
+void QDeclarativeData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
+{
+ static_cast<QDeclarativeData *>(d)->parentChanged(o, p);
+}
+
+void QDeclarativeData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o)
+{
+ static_cast<QDeclarativeData *>(d)->objectNameChanged(o);
+}
+
+void QDeclarativeEnginePrivate::init()
+{
+ Q_Q(QDeclarativeEngine);
+ qRegisterMetaType<QVariant>("QVariant");
+ qRegisterMetaType<QDeclarativeScriptString>("QDeclarativeScriptString");
+ qRegisterMetaType<QScriptValue>("QScriptValue");
+ qRegisterMetaType<QDeclarativeComponent::Status>("QDeclarativeComponent::Status");
+
+ QDeclarativeData::init();
+
+ contextClass = new QDeclarativeContextScriptClass(q);
+ objectClass = new QDeclarativeObjectScriptClass(q);
+ valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
+ typeNameClass = new QDeclarativeTypeNameScriptClass(q);
+ listClass = new QDeclarativeListScriptClass(q);
+ rootContext = new QDeclarativeContext(q,true);
+
+ QScriptValue applicationObject = objectClass->newQObject(new QDeclarativeApplication(q));
+ scriptEngine.globalObject().property(QLatin1String("Qt")).setProperty(QLatin1String("application"), applicationObject);
+
+ if (QCoreApplication::instance()->thread() == q->thread() &&
+ QDeclarativeEngineDebugServer::isDebuggingEnabled()) {
+ isDebugging = true;
+ QDeclarativeEngineDebugServer::instance()->addEngine(q);
+ }
+}
+
+QDeclarativeWorkerScriptEngine *QDeclarativeEnginePrivate::getWorkerScriptEngine()
+{
+ Q_Q(QDeclarativeEngine);
+ if (!workerScriptEngine)
+ workerScriptEngine = new QDeclarativeWorkerScriptEngine(q);
+ return workerScriptEngine;
+}
+
+/*!
+ \class QDeclarativeEngine
+ \since 4.7
+ \brief The QDeclarativeEngine class provides an environment for instantiating QML components.
+ \mainclass
+
+ Each QML component is instantiated in a QDeclarativeContext.
+ QDeclarativeContext's are essential for passing data to QML
+ components. In QML, contexts are arranged hierarchically and this
+ hierarchy is managed by the QDeclarativeEngine.
+
+ Prior to creating any QML components, an application must have
+ created a QDeclarativeEngine to gain access to a QML context. The
+ following example shows how to create a simple Text item.
+
+ \code
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine);
+ component.setData("import QtQuick 1.0\nText { text: \"Hello world!\" }", QUrl());
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(component.create());
+
+ //add item to view, etc
+ ...
+ \endcode
+
+ In this case, the Text item will be created in the engine's
+ \l {QDeclarativeEngine::rootContext()}{root context}.
+
+ \sa QDeclarativeComponent QDeclarativeContext
+*/
+
+/*!
+ Create a new QDeclarativeEngine with the given \a parent.
+*/
+QDeclarativeEngine::QDeclarativeEngine(QObject *parent)
+: QObject(*new QDeclarativeEnginePrivate(this), parent)
+{
+ Q_D(QDeclarativeEngine);
+ d->init();
+}
+
+/*!
+ Destroys the QDeclarativeEngine.
+
+ Any QDeclarativeContext's created on this engine will be
+ invalidated, but not destroyed (unless they are parented to the
+ QDeclarativeEngine object).
+*/
+QDeclarativeEngine::~QDeclarativeEngine()
+{
+ Q_D(QDeclarativeEngine);
+ if (d->isDebugging)
+ QDeclarativeEngineDebugServer::instance()->remEngine(this);
+}
+
+/*! \fn void QDeclarativeEngine::quit()
+ This signal is emitted when the QML loaded by the engine would like to quit.
+ */
+
+/*! \fn void QDeclarativeEngine::warnings(const QList<QDeclarativeError> &warnings)
+ This signal is emitted when \a warnings messages are generated by QML.
+ */
+
+/*!
+ Clears the engine's internal component cache.
+
+ Normally the QDeclarativeEngine caches components loaded from qml
+ files. This method clears this cache and forces the component to be
+ reloaded.
+ */
+void QDeclarativeEngine::clearComponentCache()
+{
+ Q_D(QDeclarativeEngine);
+ d->typeLoader.clearCache();
+}
+
+/*!
+ Returns the engine's root context.
+
+ The root context is automatically created by the QDeclarativeEngine.
+ Data that should be available to all QML component instances
+ instantiated by the engine should be put in the root context.
+
+ Additional data that should only be available to a subset of
+ component instances should be added to sub-contexts parented to the
+ root context.
+*/
+QDeclarativeContext *QDeclarativeEngine::rootContext() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->rootContext;
+}
+
+/*!
+ Sets the \a factory to use for creating QNetworkAccessManager(s).
+
+ QNetworkAccessManager is used for all network access by QML. By
+ implementing a factory it is possible to create custom
+ QNetworkAccessManager with specialized caching, proxy and cookie
+ support.
+
+ The factory must be set before executing the engine.
+*/
+void QDeclarativeEngine::setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *factory)
+{
+ Q_D(QDeclarativeEngine);
+ QMutexLocker locker(&d->mutex);
+ d->networkAccessManagerFactory = factory;
+}
+
+/*!
+ Returns the current QDeclarativeNetworkAccessManagerFactory.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QDeclarativeNetworkAccessManagerFactory *QDeclarativeEngine::networkAccessManagerFactory() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->networkAccessManagerFactory;
+}
+
+QNetworkAccessManager *QDeclarativeEnginePrivate::createNetworkAccessManager(QObject *parent) const
+{
+ QMutexLocker locker(&mutex);
+ QNetworkAccessManager *nam;
+ if (networkAccessManagerFactory) {
+ nam = networkAccessManagerFactory->create(parent);
+ } else {
+ nam = new QNetworkAccessManager(parent);
+ }
+
+ return nam;
+}
+
+QNetworkAccessManager *QDeclarativeEnginePrivate::getNetworkAccessManager() const
+{
+ Q_Q(const QDeclarativeEngine);
+ if (!networkAccessManager)
+ networkAccessManager = createNetworkAccessManager(const_cast<QDeclarativeEngine*>(q));
+ return networkAccessManager;
+}
+
+/*!
+ Returns a common QNetworkAccessManager which can be used by any QML
+ element instantiated by this engine.
+
+ If a QDeclarativeNetworkAccessManagerFactory has been set and a
+ QNetworkAccessManager has not yet been created, the
+ QDeclarativeNetworkAccessManagerFactory will be used to create the
+ QNetworkAccessManager; otherwise the returned QNetworkAccessManager
+ will have no proxy or cache set.
+
+ \sa setNetworkAccessManagerFactory()
+*/
+QNetworkAccessManager *QDeclarativeEngine::networkAccessManager() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->getNetworkAccessManager();
+}
+
+/*!
+
+ Sets the \a provider to use for images requested via the \e
+ image: url scheme, with host \a providerId. The QDeclarativeEngine
+ takes ownership of \a provider.
+
+ Image providers enable support for pixmap and threaded image
+ requests. See the QDeclarativeImageProvider documentation for details on
+ implementing and using image providers.
+
+ All required image providers should be added to the engine before any
+ QML sources files are loaded.
+
+ Note that images loaded from a QDeclarativeImageProvider are cached
+ by QPixmapCache, similar to any image loaded by QML.
+
+ \sa removeImageProvider()
+*/
+void QDeclarativeEngine::addImageProvider(const QString &providerId, QDeclarativeImageProvider *provider)
+{
+ Q_D(QDeclarativeEngine);
+ QMutexLocker locker(&d->mutex);
+ d->imageProviders.insert(providerId.toLower(), QSharedPointer<QDeclarativeImageProvider>(provider));
+}
+
+/*!
+ Returns the QDeclarativeImageProvider set for \a providerId.
+*/
+QDeclarativeImageProvider *QDeclarativeEngine::imageProvider(const QString &providerId) const
+{
+ Q_D(const QDeclarativeEngine);
+ QMutexLocker locker(&d->mutex);
+ return d->imageProviders.value(providerId).data();
+}
+
+/*!
+ Removes the QDeclarativeImageProvider for \a providerId.
+
+ Returns the provider if it was found; otherwise returns 0.
+
+ \sa addImageProvider()
+*/
+void QDeclarativeEngine::removeImageProvider(const QString &providerId)
+{
+ Q_D(QDeclarativeEngine);
+ QMutexLocker locker(&d->mutex);
+ d->imageProviders.take(providerId);
+}
+
+QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProviderType(const QUrl &url)
+{
+ QMutexLocker locker(&mutex);
+ QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider)
+ return provider->imageType();
+ return static_cast<QDeclarativeImageProvider::ImageType>(-1);
+}
+
+QImage QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QImage image;
+ QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ image = provider->requestImage(imageId, size, req_size);
+ }
+ return image;
+}
+
+QPixmap QDeclarativeEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QPixmap pixmap;
+ QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host());
+ locker.unlock();
+ if (provider) {
+ QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1);
+ pixmap = provider->requestPixmap(imageId, size, req_size);
+ }
+ return pixmap;
+}
+
+/*!
+ Return the base URL for this engine. The base URL is only used to
+ resolve components when a relative URL is passed to the
+ QDeclarativeComponent constructor.
+
+ If a base URL has not been explicitly set, this method returns the
+ application's current working directory.
+
+ \sa setBaseUrl()
+*/
+QUrl QDeclarativeEngine::baseUrl() const
+{
+ Q_D(const QDeclarativeEngine);
+ if (d->baseUrl.isEmpty()) {
+ return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
+ } else {
+ return d->baseUrl;
+ }
+}
+
+/*!
+ Set the base URL for this engine to \a url.
+
+ \sa baseUrl()
+*/
+void QDeclarativeEngine::setBaseUrl(const QUrl &url)
+{
+ Q_D(QDeclarativeEngine);
+ d->baseUrl = url;
+}
+
+/*!
+ Returns true if warning messages will be output to stderr in addition
+ to being emitted by the warnings() signal, otherwise false.
+
+ The default value is true.
+*/
+bool QDeclarativeEngine::outputWarningsToStandardError() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->outputWarningsToStdErr;
+}
+
+/*!
+ Set whether warning messages will be output to stderr to \a enabled.
+
+ If \a enabled is true, any warning messages generated by QML will be
+ output to stderr and emitted by the warnings() signal. If \a enabled
+ is false, on the warnings() signal will be emitted. This allows
+ applications to handle warning output themselves.
+
+ The default value is true.
+*/
+void QDeclarativeEngine::setOutputWarningsToStandardError(bool enabled)
+{
+ Q_D(QDeclarativeEngine);
+ d->outputWarningsToStdErr = enabled;
+}
+
+/*!
+ Returns the QDeclarativeContext for the \a object, or 0 if no
+ context has been set.
+
+ When the QDeclarativeEngine instantiates a QObject, the context is
+ set automatically.
+ */
+QDeclarativeContext *QDeclarativeEngine::contextForObject(const QObject *object)
+{
+ if(!object)
+ return 0;
+
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+
+ QDeclarativeData *data =
+ static_cast<QDeclarativeData *>(priv->declarativeData);
+
+ if (!data)
+ return 0;
+ else if (data->outerContext)
+ return data->outerContext->asQDeclarativeContext();
+ else
+ return 0;
+}
+
+/*!
+ Sets the QDeclarativeContext for the \a object to \a context.
+ If the \a object already has a context, a warning is
+ output, but the context is not changed.
+
+ When the QDeclarativeEngine instantiates a QObject, the context is
+ set automatically.
+ */
+void QDeclarativeEngine::setContextForObject(QObject *object, QDeclarativeContext *context)
+{
+ if (!object || !context)
+ return;
+
+ QDeclarativeData *data = QDeclarativeData::get(object, true);
+ if (data->context) {
+ qWarning("QDeclarativeEngine::setContextForObject(): Object already has a QDeclarativeContext");
+ return;
+ }
+
+ QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
+ contextData->addObject(object);
+}
+
+/*!
+ \enum QDeclarativeEngine::ObjectOwnership
+
+ Ownership controls whether or not QML automatically destroys the
+ QObject when the object is garbage collected by the JavaScript
+ engine. The two ownership options are:
+
+ \value CppOwnership The object is owned by C++ code, and will
+ never be deleted by QML. The JavaScript destroy() method cannot be
+ used on objects with CppOwnership. This option is similar to
+ QScriptEngine::QtOwnership.
+
+ \value JavaScriptOwnership The object is owned by JavaScript.
+ When the object is returned to QML as the return value of a method
+ call or property access, QML will delete the object if there are no
+ remaining JavaScript references to it and it has no
+ QObject::parent(). This option is similar to
+ QScriptEngine::ScriptOwnership.
+
+ Generally an application doesn't need to set an object's ownership
+ explicitly. QML uses a heuristic to set the default object
+ ownership. By default, an object that is created by QML has
+ JavaScriptOwnership. The exception to this are the root objects
+ created by calling QDeclarativeCompnent::create() or
+ QDeclarativeComponent::beginCreate() which have CppOwnership by
+ default. The ownership of these root-level objects is considered to
+ have been transferred to the C++ caller.
+
+ Objects not-created by QML have CppOwnership by default. The
+ exception to this is objects returned from a C++ method call. The
+ ownership of these objects is passed to JavaScript.
+
+ Calling setObjectOwnership() overrides the default ownership
+ heuristic used by QML.
+*/
+
+/*!
+ Sets the \a ownership of \a object.
+*/
+void QDeclarativeEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
+{
+ if (!object)
+ return;
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+ if (!ddata)
+ return;
+
+ ddata->indestructible = (ownership == CppOwnership)?true:false;
+ ddata->explicitIndestructibleSet = true;
+}
+
+/*!
+ Returns the ownership of \a object.
+*/
+QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject *object)
+{
+ if (!object)
+ return CppOwnership;
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (!ddata)
+ return CppOwnership;
+ else
+ return ddata->indestructible?CppOwnership:JavaScriptOwnership;
+}
+
+Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object);
+
+ if (data && data->deferredComponent) {
+ if (QDeclarativeDebugService::isDebuggingEnabled()) {
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
+ QString typeName = type ? QLatin1String(type->qmlTypeName()) : QString::fromLatin1(object->metaObject()->className());
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, typeName);
+ if (data->outerContext)
+ QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, data->outerContext->url, data->lineNumber);
+ }
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context->engine);
+
+ QDeclarativeComponentPrivate::ConstructionState state;
+ QDeclarativeComponentPrivate::beginDeferred(ep, object, &state);
+
+ data->deferredComponent->release();
+ data->deferredComponent = 0;
+
+ QDeclarativeComponentPrivate::complete(ep, &state);
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
+ }
+}
+
+QDeclarativeContext *qmlContext(const QObject *obj)
+{
+ return QDeclarativeEngine::contextForObject(obj);
+}
+
+QDeclarativeEngine *qmlEngine(const QObject *obj)
+{
+ QDeclarativeContext *context = QDeclarativeEngine::contextForObject(obj);
+ return context?context->engine():0;
+}
+
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object);
+ if (!data)
+ return 0; // Attached properties are only on objects created by QML
+
+ QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
+ if (rv || !create)
+ return rv;
+
+ QDeclarativeAttachedPropertiesFunc pf = QDeclarativeMetaType::attachedPropertiesFuncById(id);
+ if (!pf)
+ return 0;
+
+ rv = pf(const_cast<QObject *>(object));
+
+ if (rv)
+ data->attachedProperties()->insert(id, rv);
+
+ return rv;
+}
+
+QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
+ const QMetaObject *attachedMetaObject, bool create)
+{
+ if (*idCache == -1)
+ *idCache = QDeclarativeMetaType::attachedPropertiesFuncId(attachedMetaObject);
+
+ if (*idCache == -1 || !object)
+ return 0;
+
+ return qmlAttachedPropertiesObjectById(*idCache, object, create);
+}
+
+class QDeclarativeDataExtended {
+public:
+ QDeclarativeDataExtended();
+ ~QDeclarativeDataExtended();
+
+ QHash<int, QObject *> attachedProperties;
+ QDeclarativeNotifier objectNameNotifier;
+};
+
+QDeclarativeDataExtended::QDeclarativeDataExtended()
+{
+}
+
+QDeclarativeDataExtended::~QDeclarativeDataExtended()
+{
+}
+
+QDeclarativeNotifier *QDeclarativeData::objectNameNotifier() const
+{
+ if (!extendedData) extendedData = new QDeclarativeDataExtended;
+ return &extendedData->objectNameNotifier;
+}
+
+QHash<int, QObject *> *QDeclarativeData::attachedProperties() const
+{
+ if (!extendedData) extendedData = new QDeclarativeDataExtended;
+ return &extendedData->attachedProperties;
+}
+
+void QDeclarativeData::destroyed(QObject *object)
+{
+ if (deferredComponent)
+ deferredComponent->release();
+
+ if (nextContextObject)
+ nextContextObject->prevContextObject = prevContextObject;
+ if (prevContextObject)
+ *prevContextObject = nextContextObject;
+
+ QDeclarativeAbstractBinding *binding = bindings;
+ while (binding) {
+ QDeclarativeAbstractBinding *next = binding->m_nextBinding;
+ binding->m_prevBinding = 0;
+ binding->m_nextBinding = 0;
+ binding->destroy();
+ binding = next;
+ }
+
+ if (bindingBits)
+ free(bindingBits);
+
+ if (propertyCache)
+ propertyCache->release();
+
+ if (ownContext && context)
+ context->destroy();
+
+ while (guards) {
+ QDeclarativeGuard<QObject> *guard = guards;
+ *guard = (QObject *)0;
+ guard->objectDestroyed(object);
+ }
+
+ if (scriptValue)
+ delete scriptValue;
+
+ if (extendedData)
+ delete extendedData;
+
+ if (ownMemory)
+ delete this;
+}
+
+void QDeclarativeData::parentChanged(QObject *, QObject *parent)
+{
+ if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; }
+}
+
+void QDeclarativeData::objectNameChanged(QObject *)
+{
+ if (extendedData) objectNameNotifier()->notify();
+}
+
+bool QDeclarativeData::hasBindingBit(int bit) const
+{
+ if (bindingBitsSize > bit)
+ return bindingBits[bit / 32] & (1 << (bit % 32));
+ else
+ return false;
+}
+
+void QDeclarativeData::clearBindingBit(int bit)
+{
+ if (bindingBitsSize > bit)
+ bindingBits[bit / 32] &= ~(1 << (bit % 32));
+}
+
+void QDeclarativeData::setBindingBit(QObject *obj, int bit)
+{
+ if (bindingBitsSize <= bit) {
+ int props = obj->metaObject()->propertyCount();
+ Q_ASSERT(bit < props);
+
+ int arraySize = (props + 31) / 32;
+ int oldArraySize = bindingBitsSize / 32;
+
+ bindingBits = (quint32 *)realloc(bindingBits,
+ arraySize * sizeof(quint32));
+
+ memset(bindingBits + oldArraySize,
+ 0x00,
+ sizeof(quint32) * (arraySize - oldArraySize));
+
+ bindingBitsSize = arraySize * 32;
+ }
+
+ bindingBits[bit / 32] |= (1 << (bit % 32));
+}
+
+/*!
+ Creates a QScriptValue allowing you to use \a object in QML script.
+ \a engine is the QDeclarativeEngine it is to be created in.
+
+ The QScriptValue returned is a QtScript Object, not a QtScript QObject, due
+ to the special needs of QML requiring more functionality than a standard
+ QtScript QObject.
+*/
+QScriptValue QDeclarativeEnginePrivate::qmlScriptObject(QObject* object,
+ QDeclarativeEngine* engine)
+{
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+ return enginePriv->objectClass->newQObject(object);
+}
+
+/*!
+ Returns the QDeclarativeContext for the executing QScript \a ctxt.
+*/
+QDeclarativeContextData *QDeclarativeEnginePrivate::getContext(QScriptContext *ctxt)
+{
+ QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
+ Q_ASSERT(scopeNode.isValid());
+ Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
+ return contextClass->contextFromValue(scopeNode);
+}
+
+/*!
+ Returns the QUrl associated with the script \a ctxt for the case that there is
+ no QDeclarativeContext.
+*/
+QUrl QDeclarativeEnginePrivate::getUrl(QScriptContext *ctxt)
+{
+ QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
+ Q_ASSERT(scopeNode.isValid());
+ Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
+ return contextClass->urlFromValue(scopeNode);
+}
+
+QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
+{
+ if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
+ if (url.authority().isEmpty())
+ return QLatin1Char(':') + url.path();
+ return QString();
+ }
+ return url.toLocalFile();
+}
+
+/*!
+\qmlmethod object Qt::createComponent(url)
+
+Returns a \l Component object created using the QML file at the specified \a url,
+or \c null if an empty string was given.
+
+The returned component's \l Component::status property indicates whether the
+component was successfully created. If the status is \c Component.Error,
+see \l Component::errorString() for an error description.
+
+Call \l {Component::createObject()}{Component.createObject()} on the returned
+component to create an object instance of the component.
+
+For example:
+
+\snippet doc/src/snippets/declarative/createComponent-simple.qml 0
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+
+To create a QML object from an arbitrary string of QML (instead of a file),
+use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
+*/
+
+QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *activeEnginePriv =
+ static_cast<QDeclarativeScriptEngine*>(engine)->p;
+ QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
+
+ if(ctxt->argumentCount() != 1) {
+ return ctxt->throwError(QLatin1String("Qt.createComponent(): Invalid arguments"));
+ } else {
+
+ QString arg = ctxt->argument(0).toString();
+ if (arg.isEmpty())
+ return engine->nullValue();
+ QUrl url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt, QUrl(arg));
+ QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
+ QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine);
+ QDeclarativeComponentPrivate::get(c)->creationContext = context;
+ QDeclarativeData::get(c, true)->setImplicitDestructible();
+ return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>());
+ }
+}
+
+/*!
+\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
+
+Returns a new object created from the given \a string of QML which will have the specified \a parent,
+or \c null if there was an error in creating the object.
+
+If \a filepath is specified, it will be used for error reporting for the created object.
+
+Example (where \c parentItem is the id of an existing QML item):
+
+\snippet doc/src/snippets/declarative/createQmlObject.qml 0
+
+In the case of an error, a QtScript Error object is thrown. This object has an additional property,
+\c qmlErrors, which is an array of the errors encountered.
+Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
+
+Note that this function returns immediately, and therefore may not work if
+the \a qml string loads new components (that is, external QML files that have not yet been loaded).
+If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+*/
+
+QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *activeEnginePriv =
+ static_cast<QDeclarativeScriptEngine*>(engine)->p;
+ QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
+
+ if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3)
+ return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Invalid arguments"));
+
+ QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
+ Q_ASSERT(context);
+
+ QString qml = ctxt->argument(0).toString();
+ if (qml.isEmpty())
+ return engine->nullValue();
+
+ QUrl url;
+ if(ctxt->argumentCount() > 2)
+ url = QUrl(ctxt->argument(2).toString());
+ else
+ url = QUrl(QLatin1String("inline"));
+
+ if (url.isValid() && url.isRelative())
+ url = context->resolvedUrl(url);
+
+ QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1));
+ if(!parentArg)
+ return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Missing parent object"));
+
+ QDeclarativeComponent component(activeEngine);
+ component.setData(qml.toUtf8(), url);
+
+ if(component.isError()) {
+ QList<QDeclarativeError> errors = component.errors();
+ QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
+ QScriptValue arr = ctxt->engine()->newArray(errors.length());
+ int i = 0;
+ foreach (const QDeclarativeError &error, errors){
+ errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n");
+ QScriptValue qmlErrObject = ctxt->engine()->newObject();
+ qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
+ qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
+ qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
+ qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
+ arr.setProperty(i++, qmlErrObject);
+ }
+ QScriptValue err = ctxt->throwError(errstr);
+ err.setProperty(QLatin1String("qmlErrors"),arr);
+ return err;
+ }
+
+ if (!component.isReady())
+ return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Component is not ready"));
+
+ QObject *obj = component.beginCreate(context->asQDeclarativeContext());
+ if(obj)
+ QDeclarativeData::get(obj, true)->setImplicitDestructible();
+ component.completeCreate();
+
+ if(component.isError()) {
+ QList<QDeclarativeError> errors = component.errors();
+ QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
+ QScriptValue arr = ctxt->engine()->newArray(errors.length());
+ int i = 0;
+ foreach (const QDeclarativeError &error, errors){
+ errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n");
+ QScriptValue qmlErrObject = ctxt->engine()->newObject();
+ qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
+ qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
+ qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
+ qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
+ arr.setProperty(i++, qmlErrObject);
+ }
+ QScriptValue err = ctxt->throwError(errstr);
+ err.setProperty(QLatin1String("qmlErrors"),arr);
+ return err;
+ }
+
+ Q_ASSERT(obj);
+
+ obj->setParent(parentArg);
+
+ QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
+ break;
+ }
+
+ QDeclarativeData::get(obj, true)->setImplicitDestructible();
+ return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar);
+}
+
+/*!
+\qmlmethod bool Qt::isQtObject(object)
+Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
+*/
+QScriptValue QDeclarativeEnginePrivate::isQtObject(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (ctxt->argumentCount() == 0)
+ return QScriptValue(engine, false);
+
+ return QScriptValue(engine, 0 != ctxt->argument(0).toQObject());
+}
+
+/*!
+\qmlmethod Qt::vector3d(real x, real y, real z)
+Returns a Vector3D with the specified \c x, \c y and \c z.
+*/
+QScriptValue QDeclarativeEnginePrivate::vector3d(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 3)
+ return ctxt->throwError(QLatin1String("Qt.vector(): Invalid arguments"));
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ qsreal z = ctxt->argument(2).toNumber();
+ return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QVector3D(x, y, z)));
+}
+
+/*!
+\qmlmethod string Qt::formatDate(datetime date, variant format)
+
+Returns a string representation of \c date, optionally formatted according
+to \c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, or QDateTime value. The \a format parameter may be any of
+the possible format values as described for
+\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a date is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+#ifndef QT_NO_DATESTRING
+QScriptValue QDeclarativeEnginePrivate::formatDate(QScriptContext*ctxt, QScriptEngine*engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount == 0 || argCount > 2)
+ return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid arguments"));
+
+ QDate date = ctxt->argument(0).toDateTime().date();
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ if (argCount == 2) {
+ QScriptValue formatArg = ctxt->argument(1);
+ if (formatArg.isString()) {
+ QString format = formatArg.toString();
+ return engine->newVariant(QVariant::fromValue(date.toString(format)));
+ } else if (formatArg.isNumber()) {
+ enumFormat = Qt::DateFormat(formatArg.toUInt32());
+ } else {
+ return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid date format"));
+ }
+ }
+ return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
+}
+
+/*!
+\qmlmethod string Qt::formatTime(datetime time, variant format)
+
+Returns a string representation of \c time, optionally formatted according to
+\c format.
+
+The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
+value. The \a format parameter may be any of the possible format values as
+described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a time is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+QScriptValue QDeclarativeEnginePrivate::formatTime(QScriptContext*ctxt, QScriptEngine*engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount == 0 || argCount > 2)
+ return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid arguments"));
+
+ QTime time;
+ QScriptValue sv = ctxt->argument(0);
+ if (sv.isDate())
+ time = sv.toDateTime().time();
+ else if (sv.toVariant().type() == QVariant::Time)
+ time = sv.toVariant().toTime();
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ if (argCount == 2) {
+ QScriptValue formatArg = ctxt->argument(1);
+ if (formatArg.isString()) {
+ QString format = formatArg.toString();
+ return engine->newVariant(QVariant::fromValue(time.toString(format)));
+ } else if (formatArg.isNumber()) {
+ enumFormat = Qt::DateFormat(formatArg.toUInt32());
+ } else {
+ return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid time format"));
+ }
+ }
+ return engine->newVariant(QVariant::fromValue(time.toString(enumFormat)));
+}
+
+/*!
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+
+Returns a string representation of \c datetime, optionally formatted according to
+\c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, QTime, or QDateTime value.
+
+If \a format is not provided, \a dateTime is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
+\a format should be either.
+
+\list
+\o One of the Qt::DateFormat enumeration values, such as
+ \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+\o A string that specifies the format of the returned string, as detailed below.
+\endlist
+
+If \a format specifies a format string, it should use the following expressions
+to specify the date:
+
+ \table
+ \header \i Expression \i Output
+ \row \i d \i the day as number without a leading zero (1 to 31)
+ \row \i dd \i the day as number with a leading zero (01 to 31)
+ \row \i ddd
+ \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses QDate::shortDayName().
+ \row \i dddd
+ \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
+ Uses QDate::longDayName().
+ \row \i M \i the month as number without a leading zero (1-12)
+ \row \i MM \i the month as number with a leading zero (01-12)
+ \row \i MMM
+ \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses QDate::shortMonthName().
+ \row \i MMMM
+ \i the long localized month name (e.g. 'January' to 'December').
+ Uses QDate::longMonthName().
+ \row \i yy \i the year as two digit number (00-99)
+ \row \i yyyy \i the year as four digit number
+ \endtable
+
+In addition the following expressions can be used to specify the time:
+
+ \table
+ \header \i Expression \i Output
+ \row \i h
+ \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \i hh
+ \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \i m \i the minute without a leading zero (0 to 59)
+ \row \i mm \i the minute with a leading zero (00 to 59)
+ \row \i s \i the second without a leading zero (0 to 59)
+ \row \i ss \i the second with a leading zero (00 to 59)
+ \row \i z \i the milliseconds without leading zeroes (0 to 999)
+ \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
+ \row \i AP
+ \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
+ \row \i ap
+ \i use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \endtable
+
+ All other input characters will be ignored. Any sequence of characters that
+ are enclosed in single quotes will be treated as text and not be used as an
+ expression. Two consecutive single quotes ("''") are replaced by a single quote
+ in the output.
+
+For example, if the following date/time value was specified:
+
+ \code
+ // 21 May 2001 14:13:09
+ var dateTime = new Date(2001, 5, 21, 14, 13, 09)
+ \endcode
+
+This \a dateTime value could be passed to \c Qt.formatDateTime(),
+\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
+with the \a format values below to produce the following results:
+
+ \table
+ \header \i Format \i Result
+ \row \i "dd.MM.yyyy" \i 21.05.2001
+ \row \i "ddd MMMM d yy" \i Tue May 21 01
+ \row \i "hh:mm:ss.zzz" \i 14:13:09.042
+ \row \i "h:m:s ap" \i 2:13:9 pm
+ \endtable
+*/
+QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScriptEngine*engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount == 0 || argCount > 2)
+ return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid arguments"));
+
+ QDateTime date = ctxt->argument(0).toDateTime();
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ if (argCount == 2) {
+ QScriptValue formatArg = ctxt->argument(1);
+ if (formatArg.isString()) {
+ QString format = formatArg.toString();
+ return engine->newVariant(QVariant::fromValue(date.toString(format)));
+ } else if (formatArg.isNumber()) {
+ enumFormat = Qt::DateFormat(formatArg.toUInt32());
+ } else {
+ return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid datetime format"));
+ }
+ }
+ return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
+}
+#endif // QT_NO_DATESTRING
+
+/*!
+\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
+
+Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount < 3 || argCount > 4)
+ return ctxt->throwError(QLatin1String("Qt.rgba(): Invalid arguments"));
+ qsreal r = ctxt->argument(0).toNumber();
+ qsreal g = ctxt->argument(1).toNumber();
+ qsreal b = ctxt->argument(2).toNumber();
+ qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
+
+ if (r < 0.0) r=0.0;
+ if (r > 1.0) r=1.0;
+ if (g < 0.0) g=0.0;
+ if (g > 1.0) g=1.0;
+ if (b < 0.0) b=0.0;
+ if (b > 1.0) b=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return engine->toScriptValue(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
+}
+
+/*!
+\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
+
+Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ int argCount = ctxt->argumentCount();
+ if(argCount < 3 || argCount > 4)
+ return ctxt->throwError(QLatin1String("Qt.hsla(): Invalid arguments"));
+ qsreal h = ctxt->argument(0).toNumber();
+ qsreal s = ctxt->argument(1).toNumber();
+ qsreal l = ctxt->argument(2).toNumber();
+ qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
+
+ if (h < 0.0) h=0.0;
+ if (h > 1.0) h=1.0;
+ if (s < 0.0) s=0.0;
+ if (s > 1.0) s=1.0;
+ if (l < 0.0) l=0.0;
+ if (l > 1.0) l=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return engine->toScriptValue(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
+}
+
+/*!
+\qmlmethod rect Qt::rect(int x, int y, int width, int height)
+
+Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
+
+The returned object has \c x, \c y, \c width and \c height attributes with the given values.
+*/
+QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 4)
+ return ctxt->throwError(QLatin1String("Qt.rect(): Invalid arguments"));
+
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ qsreal w = ctxt->argument(2).toNumber();
+ qsreal h = ctxt->argument(3).toNumber();
+
+ if (w < 0 || h < 0)
+ return engine->nullValue();
+
+ return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+}
+
+/*!
+\qmlmethod point Qt::point(int x, int y)
+Returns a Point with the specified \c x and \c y coordinates.
+*/
+QScriptValue QDeclarativeEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return ctxt->throwError(QLatin1String("Qt.point(): Invalid arguments"));
+ qsreal x = ctxt->argument(0).toNumber();
+ qsreal y = ctxt->argument(1).toNumber();
+ return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QPointF(x, y)));
+}
+
+/*!
+\qmlmethod Qt::size(int width, int height)
+Returns a Size with the specified \c width and \c height.
+*/
+QScriptValue QDeclarativeEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return ctxt->throwError(QLatin1String("Qt.size(): Invalid arguments"));
+ qsreal w = ctxt->argument(0).toNumber();
+ qsreal h = ctxt->argument(1).toNumber();
+ return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QSizeF(w, h)));
+}
+
+/*!
+\qmlmethod color Qt::lighter(color baseColor, real factor)
+Returns a color lighter than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this functions returns a lighter color.
+Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
+the return color is darker, but we recommend using the Qt.darker() function for this purpose.
+If the factor is 0 or negative, the return value is unspecified.
+
+The function converts the current RGB color to HSV, multiplies the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
+*/
+QScriptValue QDeclarativeEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
+ return ctxt->throwError(QLatin1String("Qt.lighter(): Invalid arguments"));
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+ qsreal factor = 1.5;
+ if (ctxt->argumentCount() == 2)
+ factor = ctxt->argument(1).toNumber();
+ color = color.lighter(int(qRound(factor*100.)));
+ return engine->toScriptValue(QVariant::fromValue(color));
+}
+
+/*!
+\qmlmethod color Qt::darker(color baseColor, real factor)
+Returns a color darker than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this function returns a darker color.
+Setting factor to 3.0 returns a color that has one-third the brightness.
+If the factor is less than 1.0, the return color is lighter, but we recommend using
+the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
+value is unspecified.
+
+The function converts the current RGB color to HSV, divides the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
+*/
+QScriptValue QDeclarativeEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
+ return ctxt->throwError(QLatin1String("Qt.darker(): Invalid arguments"));
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+ qsreal factor = 2.0;
+ if (ctxt->argumentCount() == 2)
+ factor = ctxt->argument(1).toNumber();
+ color = color.darker(int(qRound(factor*100.)));
+ return engine->toScriptValue(QVariant::fromValue(color));
+}
+
+/*!
+\qmlmethod bool Qt::openUrlExternally(url target)
+Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
+*/
+QScriptValue QDeclarativeEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() < 1)
+ return QScriptValue(e, false);
+ bool ret = false;
+#ifndef QT_NO_DESKTOPSERVICES
+ ret = QDesktopServices::openUrl(QDeclarativeScriptEngine::get(e)->resolvedUrl(ctxt, QUrl(ctxt->argument(0).toString())));
+#endif
+ return QScriptValue(e, ret);
+}
+
+/*!
+\qmlmethod list<string> Qt::fontFamilies()
+Returns a list of the font families available to the application.
+*/
+
+QScriptValue QDeclarativeEnginePrivate::fontFamilies(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() != 0)
+ return ctxt->throwError(QLatin1String("Qt.fontFamilies(): Invalid arguments"));
+
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(e);
+ QFontDatabase database;
+ return p->scriptValueFromVariant(database.families());
+}
+
+/*!
+\qmlmethod string Qt::md5(data)
+Returns a hex string of the md5 hash of \c data.
+*/
+QScriptValue QDeclarativeEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *)
+{
+ if (ctxt->argumentCount() != 1)
+ return ctxt->throwError(QLatin1String("Qt.md5(): Invalid arguments"));
+
+ QByteArray data = ctxt->argument(0).toString().toUtf8();
+ QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
+
+ return QScriptValue(QLatin1String(result.toHex()));
+}
+
+/*!
+\qmlmethod string Qt::btoa(data)
+Binary to ASCII - this function returns a base64 encoding of \c data.
+*/
+QScriptValue QDeclarativeEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *)
+{
+ if (ctxt->argumentCount() != 1)
+ return ctxt->throwError(QLatin1String("Qt.btoa(): Invalid arguments"));
+
+ QByteArray data = ctxt->argument(0).toString().toUtf8();
+
+ return QScriptValue(QLatin1String(data.toBase64()));
+}
+
+/*!
+\qmlmethod string Qt::atob(data)
+ASCII to binary - this function returns a base64 decoding of \c data.
+*/
+
+QScriptValue QDeclarativeEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *)
+{
+ if (ctxt->argumentCount() != 1)
+ return ctxt->throwError(QLatin1String("Qt.atob(): Invalid arguments"));
+
+ QByteArray data = ctxt->argument(0).toString().toUtf8();
+
+ return QScriptValue(QLatin1String(QByteArray::fromBase64(data)));
+}
+
+QScriptValue QDeclarativeEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e)
+{
+ if(ctxt->argumentCount() < 1)
+ return e->newVariant(QVariant(false));
+
+ QByteArray msg;
+
+ for (int i=0; i<ctxt->argumentCount(); ++i) {
+ if (!msg.isEmpty()) msg += ' ';
+ msg += ctxt->argument(i).toString().toLocal8Bit();
+ // does not support firebug "%[a-z]" formatting, since firebug really
+ // does just ignore the format letter, which makes it pointless.
+ }
+
+ qDebug("%s",msg.constData());
+
+ return e->newVariant(QVariant(true));
+}
+
+void QDeclarativeEnginePrivate::sendQuit()
+{
+ Q_Q(QDeclarativeEngine);
+ emit q->quit();
+ if (q->receivers(SIGNAL(quit())) == 0) {
+ qWarning("Signal QDeclarativeEngine::quit() emitted, but no receivers connected to handle it.");
+ }
+}
+
+static void dumpwarning(const QDeclarativeError &error)
+{
+ qWarning().nospace() << qPrintable(error.toString());
+}
+
+static void dumpwarning(const QList<QDeclarativeError> &errors)
+{
+ for (int ii = 0; ii < errors.count(); ++ii)
+ dumpwarning(errors.at(ii));
+}
+
+void QDeclarativeEnginePrivate::warning(const QDeclarativeError &error)
+{
+ Q_Q(QDeclarativeEngine);
+ q->warnings(QList<QDeclarativeError>() << error);
+ if (outputWarningsToStdErr)
+ dumpwarning(error);
+}
+
+void QDeclarativeEnginePrivate::warning(const QList<QDeclarativeError> &errors)
+{
+ Q_Q(QDeclarativeEngine);
+ q->warnings(errors);
+ if (outputWarningsToStdErr)
+ dumpwarning(errors);
+}
+
+void QDeclarativeEnginePrivate::warning(QDeclarativeEngine *engine, const QDeclarativeError &error)
+{
+ if (engine)
+ QDeclarativeEnginePrivate::get(engine)->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QDeclarativeEnginePrivate::warning(QDeclarativeEngine *engine, const QList<QDeclarativeError> &error)
+{
+ if (engine)
+ QDeclarativeEnginePrivate::get(engine)->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate *engine, const QDeclarativeError &error)
+{
+ if (engine)
+ engine->warning(error);
+ else
+ dumpwarning(error);
+}
+
+void QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate *engine, const QList<QDeclarativeError> &error)
+{
+ if (engine)
+ engine->warning(error);
+ else
+ dumpwarning(error);
+}
+
+/*!
+\qmlmethod Qt::quit()
+This function causes the QDeclarativeEngine::quit() signal to be emitted.
+Within the \l {QML Viewer}, this causes the launcher application to exit;
+to quit a C++ application when this method is called, connect the
+QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
+*/
+
+QScriptValue QDeclarativeEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e)
+{
+ QDeclarativeEnginePrivate *qe = get (e);
+ qe->sendQuit();
+ return QScriptValue();
+}
+
+/*!
+ \qmlmethod color Qt::tint(color baseColor, color tintColor)
+ This function allows tinting one color with another.
+
+ The tint color should usually be mostly transparent, or you will not be
+ able to see the underlying color. The below example provides a slight red
+ tint by having the tint color be pure red which is only 1/16th opaque.
+
+ \qml
+ Item {
+ Rectangle {
+ x: 0; width: 80; height: 80
+ color: "lightsteelblue"
+ }
+ Rectangle {
+ x: 100; width: 80; height: 80
+ color: Qt.tint("lightsteelblue", "#10FF0000")
+ }
+ }
+ \endqml
+ \image declarative-rect_tint.png
+
+ Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
+*/
+QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if(ctxt->argumentCount() != 2)
+ return ctxt->throwError(QLatin1String("Qt.tint(): Invalid arguments"));
+ //get color
+ QVariant v = ctxt->argument(0).toVariant();
+ QColor color;
+ if (v.userType() == QVariant::Color)
+ color = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+
+ //get tint color
+ v = ctxt->argument(1).toVariant();
+ QColor tintColor;
+ if (v.userType() == QVariant::Color)
+ tintColor = v.value<QColor>();
+ else if (v.userType() == QVariant::String) {
+ bool ok;
+ tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok)
+ return engine->nullValue();
+ } else
+ return engine->nullValue();
+
+ //tint
+ QColor finalColor;
+ int a = tintColor.alpha();
+ if (a == 0xFF)
+ finalColor = tintColor;
+ else if (a == 0x00)
+ finalColor = color;
+ else {
+ qreal a = tintColor.alphaF();
+ qreal inv_a = 1.0 - a;
+
+ finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
+ tintColor.greenF() * a + color.greenF() * inv_a,
+ tintColor.blueF() * a + color.blueF() * inv_a,
+ a + inv_a * color.alphaF());
+ }
+
+ return engine->toScriptValue(QVariant::fromValue(finalColor));
+}
+
+QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
+{
+ if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ QDeclarativeListReferencePrivate *p =
+ QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
+ if (p->object) {
+ return listClass->newList(p->property, p->propertyType);
+ } else {
+ return scriptEngine.nullValue();
+ }
+ } else if (val.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list = *(QList<QObject *>*)val.constData();
+ QScriptValue rv = scriptEngine.newArray(list.count());
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *object = list.at(ii);
+ rv.setProperty(ii, objectClass->newQObject(object));
+ }
+ return rv;
+ } else if (QDeclarativeValueType *vt = valueTypes[val.userType()]) {
+ return valueTypeClass->newObject(val, vt);
+ }
+
+ bool objOk;
+ QObject *obj = QDeclarativeMetaType::toQObject(val, &objOk);
+ if (objOk) {
+ return objectClass->newQObject(obj);
+ } else {
+ return scriptEngine.toScriptValue(val);
+ }
+}
+
+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 == valueTypeClass)
+ return valueTypeClass->toVariant(val);
+ else if (dc == contextClass)
+ return QVariant();
+
+ // Convert to a QList<QObject*> only if val is an array and we were explicitly hinted
+ if (hint == qMetaTypeId<QList<QObject *> >() && val.isArray()) {
+ QList<QObject *> list;
+ int length = val.property(QLatin1String("length")).toInt32();
+ for (int ii = 0; ii < length; ++ii) {
+ QScriptValue arrayItem = val.property(ii);
+ QObject *d = arrayItem.toQObject();
+ list << d;
+ }
+ return QVariant::fromValue(list);
+ }
+
+ return val.toVariant();
+}
+
+/*!
+ Adds \a path as a directory where the engine searches for
+ installed modules in a URL-based directory structure.
+ The \a path may be a local filesystem directory or a URL.
+
+ The newly added \a path will be first in the importPathList().
+
+ \sa setImportPathList(), {QML Modules}
+*/
+void QDeclarativeEngine::addImportPath(const QString& path)
+{
+ Q_D(QDeclarativeEngine);
+ d->importDatabase.addImportPath(path);
+}
+
+/*!
+ Returns the list of directories where the engine searches for
+ installed modules in a URL-based directory structure.
+
+ For example, if \c /opt/MyApp/lib/imports is in the path, then QML that
+ imports \c com.mycompany.Feature will cause the QDeclarativeEngine to look
+ in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components
+ provided by that module. A \c qmldir file is required for defining the
+ type version mapping and possibly declarative extensions plugins.
+
+ By default, the list contains the directory of the application executable,
+ paths specified in the \c QML_IMPORT_PATH environment variable,
+ and the builtin \c ImportsPath from QLibraryInfo.
+
+ \sa addImportPath() setImportPathList()
+*/
+QStringList QDeclarativeEngine::importPathList() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->importDatabase.importPathList();
+}
+
+/*!
+ Sets \a paths as the list of directories where the engine searches for
+ installed modules in a URL-based directory structure.
+
+ By default, the list contains the directory of the application executable,
+ paths specified in the \c QML_IMPORT_PATH environment variable,
+ and the builtin \c ImportsPath from QLibraryInfo.
+
+ \sa importPathList() addImportPath()
+ */
+void QDeclarativeEngine::setImportPathList(const QStringList &paths)
+{
+ Q_D(QDeclarativeEngine);
+ d->importDatabase.setImportPathList(paths);
+}
+
+
+/*!
+ Adds \a path as a directory where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file).
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ The newly added \a path will be first in the pluginPathList().
+
+ \sa setPluginPathList()
+*/
+void QDeclarativeEngine::addPluginPath(const QString& path)
+{
+ Q_D(QDeclarativeEngine);
+ d->importDatabase.addPluginPath(path);
+}
+
+
+/*!
+ Returns the list of directories where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file).
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ \sa addPluginPath() setPluginPathList()
+*/
+QStringList QDeclarativeEngine::pluginPathList() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->importDatabase.pluginPathList();
+}
+
+/*!
+ Sets the list of directories where the engine searches for
+ native plugins for imported modules (referenced in the \c qmldir file)
+ to \a paths.
+
+ By default, the list contains only \c ., i.e. the engine searches
+ in the directory of the \c qmldir file itself.
+
+ \sa pluginPathList() addPluginPath()
+ */
+void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
+{
+ Q_D(QDeclarativeEngine);
+ d->importDatabase.setPluginPathList(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, *\a errorString will be set to a message describing the failure.
+
+ The plugin has to be a Qt plugin which implements the QDeclarativeExtensionPlugin interface.
+*/
+bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+{
+ Q_D(QDeclarativeEngine);
+ return d->importDatabase.importPlugin(filePath, uri, errorString);
+}
+
+/*!
+ \property QDeclarativeEngine::offlineStoragePath
+ \brief the directory for storing offline user data
+
+ Returns the directory where SQL and other offline
+ storage is placed.
+
+ QDeclarativeWebView and the SQL databases created with openDatabase()
+ are stored here.
+
+ The default is QML/OfflineStorage in the platform-standard
+ user application data directory.
+
+ Note that the path may not currently exist on the filesystem, so
+ callers wanting to \e create new files at this location should create
+ it first - see QDir::mkpath().
+*/
+void QDeclarativeEngine::setOfflineStoragePath(const QString& dir)
+{
+ Q_D(QDeclarativeEngine);
+ d->scriptEngine.offlineStoragePath = dir;
+}
+
+QString QDeclarativeEngine::offlineStoragePath() const
+{
+ Q_D(const QDeclarativeEngine);
+ return d->scriptEngine.offlineStoragePath;
+}
+
+static void voidptr_destructor(void *v)
+{
+ void **ptr = (void **)v;
+ delete ptr;
+}
+
+static void *voidptr_constructor(const void *v)
+{
+ if (!v) {
+ return new void*;
+ } else {
+ return new void*(*(void **)v);
+ }
+}
+
+QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(const QMetaObject *mo)
+{
+ Q_Q(QDeclarativeEngine);
+
+ if (!mo->superClass()) {
+ QDeclarativePropertyCache *rv = new QDeclarativePropertyCache(q, mo);
+ propertyCache.insert(mo, rv);
+ return rv;
+ } else {
+ QDeclarativePropertyCache *super = cache(mo->superClass());
+ QDeclarativePropertyCache *rv = super->copy();
+ rv->append(q, mo);
+ propertyCache.insert(mo, rv);
+ return rv;
+ }
+}
+
+QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeType *type, int minorVersion,
+ QDeclarativeError &error)
+{
+ QList<QDeclarativeType *> types;
+
+ int maxMinorVersion = 0;
+
+ const QMetaObject *metaObject = type->metaObject();
+ while (metaObject) {
+ QDeclarativeType *t = QDeclarativeMetaType::qmlType(metaObject, type->module(),
+ type->majorVersion(), minorVersion);
+ if (t) {
+ maxMinorVersion = qMax(maxMinorVersion, t->minorVersion());
+ types << t;
+ } else {
+ types << 0;
+ }
+
+ metaObject = metaObject->superClass();
+ }
+
+ if (QDeclarativePropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
+ c->addref();
+ typePropertyCache.insert(qMakePair(type, minorVersion), c);
+ return c;
+ }
+
+ QDeclarativePropertyCache *raw = cache(type->metaObject());
+
+ bool hasCopied = false;
+
+ for (int ii = 0; ii < types.count(); ++ii) {
+ QDeclarativeType *currentType = types.at(ii);
+ if (!currentType)
+ continue;
+
+ int rev = currentType->metaObjectRevision();
+ int moIndex = types.count() - 1 - ii;
+
+ if (raw->allowedRevisionCache[moIndex] != rev) {
+ if (!hasCopied) {
+ raw = raw->copy();
+ hasCopied = true;
+ }
+ raw->allowedRevisionCache[moIndex] = rev;
+ }
+ }
+
+ // Test revision compatibility - the basic rule is:
+ // * Anything that is excluded, cannot overload something that is not excluded *
+
+ // Signals override:
+ // * other signals and methods of the same name.
+ // * properties named on<Signal Name>
+ // * automatic <property name>Changed notify signals
+
+ // Methods override:
+ // * other methods of the same name
+
+ // Properties override:
+ // * other elements of the same name
+
+ bool overloadError = false;
+ QString overloadName;
+
+#if 0
+ for (QDeclarativePropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
+ !overloadError && iter != raw->stringCache.end();
+ ++iter) {
+
+ QDeclarativePropertyCache::Data *d = *iter;
+ if (raw->isAllowedInRevision(d))
+ continue; // Not excluded - no problems
+
+ // check that a regular "name" overload isn't happening
+ QDeclarativePropertyCache::Data *current = d;
+ while (!overloadError && current) {
+ current = d->overrideData(current);
+ if (current && raw->isAllowedInRevision(current))
+ overloadError = true;
+ }
+ }
+#endif
+
+ if (overloadError) {
+ if (hasCopied) raw->release();
+
+ error.setDescription(QLatin1String("Type ") + QString::fromUtf8(type->qmlTypeName()) + QLatin1String(" ") + QString::number(type->majorVersion()) + QLatin1String(".") + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
+ return 0;
+ }
+
+ if (!hasCopied) raw->addref();
+ typePropertyCache.insert(qMakePair(type, minorVersion), raw);
+
+ if (minorVersion != maxMinorVersion) {
+ raw->addref();
+ typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
+ }
+
+ return raw;
+}
+
+void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData *data)
+{
+ QByteArray name = data->root->className();
+
+ QByteArray ptr = name + '*';
+ QByteArray lst = "QDeclarativeListProperty<" + name + '>';
+
+ int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor,
+ voidptr_constructor);
+ int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor,
+ voidptr_constructor);
+
+ m_qmlLists.insert(lst_type, ptr_type);
+ m_compositeTypes.insert(ptr_type, data);
+ data->addref();
+}
+
+bool QDeclarativeEnginePrivate::isList(int t) const
+{
+ return m_qmlLists.contains(t) || QDeclarativeMetaType::isList(t);
+}
+
+int QDeclarativeEnginePrivate::listType(int t) const
+{
+ QHash<int, int>::ConstIterator iter = m_qmlLists.find(t);
+ if (iter != m_qmlLists.end())
+ return *iter;
+ else
+ return QDeclarativeMetaType::listType(t);
+}
+
+bool QDeclarativeEnginePrivate::isQObject(int t)
+{
+ return m_compositeTypes.contains(t) || QDeclarativeMetaType::isQObject(t);
+}
+
+QObject *QDeclarativeEnginePrivate::toQObject(const QVariant &v, bool *ok) const
+{
+ int t = v.userType();
+ if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
+ if (ok) *ok = true;
+ return *(QObject **)(v.constData());
+ } else {
+ return QDeclarativeMetaType::toQObject(v, ok);
+ }
+}
+
+QDeclarativeMetaType::TypeCategory QDeclarativeEnginePrivate::typeCategory(int t) const
+{
+ if (m_compositeTypes.contains(t))
+ return QDeclarativeMetaType::Object;
+ else if (m_qmlLists.contains(t))
+ return QDeclarativeMetaType::List;
+ else
+ return QDeclarativeMetaType::typeCategory(t);
+}
+
+const QMetaObject *QDeclarativeEnginePrivate::rawMetaObjectForType(int t) const
+{
+ QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(t);
+ return type?type->baseMetaObject():0;
+ }
+}
+
+const QMetaObject *QDeclarativeEnginePrivate::metaObjectForType(int t) const
+{
+ QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t);
+ if (iter != m_compositeTypes.end()) {
+ return (*iter)->root;
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(t);
+ return type?type->metaObject():0;
+ }
+}
+
+bool QDeclarative_isFileCaseCorrect(const QString &fileName)
+{
+#if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
+ QFileInfo info(fileName);
+
+ QString absolute = info.absoluteFilePath();
+
+#if defined(Q_OS_MAC)
+ QString canonical = info.canonicalFilePath();
+#elif defined(Q_OS_WIN32)
+ wchar_t buffer[1024];
+
+ DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
+ if (rv == 0 || rv >= 1024) return true;
+ rv = ::GetLongPathName(buffer, buffer, 1024);
+ if (rv == 0 || rv >= 1024) return true;
+
+ QString canonical((QChar *)buffer);
+#endif
+
+ int absoluteLength = absolute.length();
+ int canonicalLength = canonical.length();
+
+ int length = qMin(absoluteLength, canonicalLength);
+ for (int ii = 0; ii < length; ++ii) {
+ const QChar &a = absolute.at(absoluteLength - 1 - ii);
+ const QChar &c = canonical.at(canonicalLength - 1 - ii);
+
+ if (a.toLower() != c.toLower())
+ return true;
+ if (a != c)
+ return false;
+ }
+#else
+ Q_UNUSED(fileName)
+#endif
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h
new file mode 100644
index 0000000000..631fc5ec57
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -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 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 QDECLARATIVEENGINE_H
+#define QDECLARATIVEENGINE_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtDeclarative/qdeclarativeerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeComponent;
+class QDeclarativeEnginePrivate;
+class QDeclarativeImportsPrivate;
+class QDeclarativeExpression;
+class QDeclarativeContext;
+class QDeclarativeType;
+class QUrl;
+class QScriptEngine;
+class QScriptContext;
+class QDeclarativeImageProvider;
+class QNetworkAccessManager;
+class QDeclarativeNetworkAccessManagerFactory;
+class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QObject
+{
+ Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
+ Q_OBJECT
+public:
+ QDeclarativeEngine(QObject *p = 0);
+ virtual ~QDeclarativeEngine();
+
+ QDeclarativeContext *rootContext() const;
+
+ void clearComponentCache();
+
+ QStringList importPathList() const;
+ void setImportPathList(const QStringList &paths);
+ void addImportPath(const QString& dir);
+
+ QStringList pluginPathList() const;
+ void setPluginPathList(const QStringList &paths);
+ void addPluginPath(const QString& dir);
+
+ bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+
+ void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *);
+ QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const;
+
+ QNetworkAccessManager *networkAccessManager() const;
+
+ void addImageProvider(const QString &id, QDeclarativeImageProvider *);
+ QDeclarativeImageProvider *imageProvider(const QString &id) const;
+ void removeImageProvider(const QString &id);
+
+ void setOfflineStoragePath(const QString& dir);
+ QString offlineStoragePath() const;
+
+ QUrl baseUrl() const;
+ void setBaseUrl(const QUrl &);
+
+ bool outputWarningsToStandardError() const;
+ void setOutputWarningsToStandardError(bool);
+
+ static QDeclarativeContext *contextForObject(const QObject *);
+ static void setContextForObject(QObject *, QDeclarativeContext *);
+
+ enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+ static void setObjectOwnership(QObject *, ObjectOwnership);
+ static ObjectOwnership objectOwnership(QObject *);
+
+Q_SIGNALS:
+ void quit();
+ void warnings(const QList<QDeclarativeError> &warnings);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeEngine)
+ Q_DECLARE_PRIVATE(QDeclarativeEngine)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEENGINE_H
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
new file mode 100644
index 0000000000..88b4e800f8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEENGINE_P_H
+#define QDECLARATIVEENGINE_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 "qdeclarativeengine.h"
+
+#include "private/qdeclarativetypeloader_p.h"
+#include "private/qdeclarativeimport_p.h"
+#include "private/qpodvector_p.h"
+#include "qdeclarative.h"
+#include "private/qdeclarativevaluetype_p.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+#include "qdeclarativeexpression.h"
+#include "qdeclarativeimageprovider.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativeobjectscriptclass_p.h"
+#include "private/qdeclarativecontextscriptclass_p.h"
+#include "private/qdeclarativevaluetypescriptclass_p.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "private/qdeclarativedirparser_p.h"
+
+#include <QtScript/QScriptClass>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptString>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qmutex.h>
+#include <QtScript/qscriptengine.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QDeclarativeEngine;
+class QDeclarativeContextPrivate;
+class QDeclarativeExpression;
+class QDeclarativeContextScriptClass;
+class QDeclarativeImportDatabase;
+class QDeclarativeObjectScriptClass;
+class QDeclarativeTypeNameScriptClass;
+class QDeclarativeValueTypeScriptClass;
+class QScriptEngineDebugger;
+class QNetworkReply;
+class QNetworkAccessManager;
+class QDeclarativeNetworkAccessManagerFactory;
+class QDeclarativeAbstractBinding;
+class QScriptDeclarativeClass;
+class QDeclarativeTypeNameScriptClass;
+class QDeclarativeTypeNameCache;
+class QDeclarativeComponentAttached;
+class QDeclarativeListScriptClass;
+class QDeclarativeCleanup;
+class QDeclarativeDelayedError;
+class QDeclarativeWorkerScriptEngine;
+class QDeclarativeGlobalScriptClass;
+class QDir;
+
+class QDeclarativeScriptEngine : public QScriptEngine
+{
+public:
+ QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv);
+ virtual ~QDeclarativeScriptEngine();
+
+ QUrl resolvedUrl(QScriptContext *context, const QUrl& url); // resolved against p's context, or baseUrl if no p
+ static QScriptValue resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine);
+
+ static QDeclarativeScriptEngine *get(QScriptEngine* e) { return static_cast<QDeclarativeScriptEngine*>(e); }
+
+ QDeclarativeEnginePrivate *p;
+
+ // User by SQL API
+ QScriptClass *sqlQueryClass;
+ QString offlineStoragePath;
+
+ // Used by DOM Core 3 API
+ QScriptClass *namedNodeMapClass;
+ QScriptClass *nodeListClass;
+
+ QUrl baseUrl;
+
+ virtual QNetworkAccessManager *networkAccessManager();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeEngine)
+public:
+ QDeclarativeEnginePrivate(QDeclarativeEngine *);
+ ~QDeclarativeEnginePrivate();
+
+ void init();
+
+ struct CapturedProperty {
+ CapturedProperty(QObject *o, int c, int n)
+ : object(o), coreIndex(c), notifier(0), notifyIndex(n) {}
+ CapturedProperty(QDeclarativeNotifier *n)
+ : object(0), coreIndex(-1), notifier(n), notifyIndex(-1) {}
+
+ QObject *object;
+ int coreIndex;
+ QDeclarativeNotifier *notifier;
+ int notifyIndex;
+ };
+ bool captureProperties;
+ QPODVector<CapturedProperty> capturedProperties;
+
+ QDeclarativeContext *rootContext;
+ bool isDebugging;
+
+ bool outputWarningsToStdErr;
+
+ QDeclarativeContextScriptClass *contextClass;
+ QDeclarativeContextData *sharedContext;
+ QObject *sharedScope;
+ QDeclarativeObjectScriptClass *objectClass;
+ QDeclarativeValueTypeScriptClass *valueTypeClass;
+ QDeclarativeTypeNameScriptClass *typeNameClass;
+ QDeclarativeListScriptClass *listClass;
+ // Global script class
+ QDeclarativeGlobalScriptClass *globalClass;
+
+ // Registered cleanup handlers
+ QDeclarativeCleanup *cleanup;
+
+ // Bindings that have had errors during startup
+ QDeclarativeDelayedError *erroredBindings;
+ int inProgressCreations;
+
+ QDeclarativeScriptEngine scriptEngine;
+
+ QDeclarativeWorkerScriptEngine *getWorkerScriptEngine();
+ QDeclarativeWorkerScriptEngine *workerScriptEngine;
+
+ QUrl baseUrl;
+
+ template<class T>
+ struct SimpleList {
+ SimpleList()
+ : count(0), values(0) {}
+ SimpleList(int r)
+ : count(0), values(new T*[r]) {}
+
+ int count;
+ T **values;
+
+ void append(T *v) {
+ values[count++] = v;
+ }
+
+ T *at(int idx) const {
+ return values[idx];
+ }
+
+ void clear() {
+ delete [] values;
+ }
+ };
+
+ static void clear(SimpleList<QDeclarativeAbstractBinding> &);
+ static void clear(SimpleList<QDeclarativeParserStatus> &);
+
+ QList<SimpleList<QDeclarativeAbstractBinding> > bindValues;
+ QList<SimpleList<QDeclarativeParserStatus> > parserStatus;
+ QList<QPair<QDeclarativeGuard<QObject>,int> > finalizedParserStatus;
+ QDeclarativeComponentAttached *componentAttached;
+
+ void registerFinalizedParserStatusObject(QObject *obj, int index) {
+ finalizedParserStatus.append(qMakePair(QDeclarativeGuard<QObject>(obj), index));
+ }
+
+ bool inBeginCreate;
+
+ QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
+ QNetworkAccessManager *getNetworkAccessManager() const;
+ mutable QNetworkAccessManager *networkAccessManager;
+ mutable QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory;
+
+ QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders;
+ QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
+ QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+
+ mutable QMutex mutex;
+
+ QDeclarativeTypeLoader typeLoader;
+ QDeclarativeImportDatabase importDatabase;
+
+ QString offlineStoragePath;
+
+ mutable quint32 uniqueId;
+ quint32 getUniqueId() const {
+ return uniqueId++;
+ }
+
+ QDeclarativeValueTypeFactory valueTypes;
+
+ QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
+ QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
+ inline QDeclarativePropertyCache *cache(QObject *obj);
+ inline QDeclarativePropertyCache *cache(const QMetaObject *);
+ inline QDeclarativePropertyCache *cache(QDeclarativeType *, int, QDeclarativeError &error);
+ QDeclarativePropertyCache *createCache(const QMetaObject *);
+ QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error);
+
+ void registerCompositeType(QDeclarativeCompiledData *);
+
+ bool isQObject(int);
+ QObject *toQObject(const QVariant &, bool *ok = 0) const;
+ QDeclarativeMetaType::TypeCategory typeCategory(int) const;
+ bool isList(int) const;
+ int listType(int) const;
+ const QMetaObject *rawMetaObjectForType(int) const;
+ const QMetaObject *metaObjectForType(int) const;
+ 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);
+
+ void sendQuit();
+ void warning(const QDeclarativeError &);
+ void warning(const QList<QDeclarativeError> &);
+ static void warning(QDeclarativeEngine *, const QDeclarativeError &);
+ static void warning(QDeclarativeEngine *, const QList<QDeclarativeError> &);
+ static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
+ static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
+
+ static QScriptValue qmlScriptObject(QObject*, QDeclarativeEngine*);
+
+ static QScriptValue createComponent(QScriptContext*, QScriptEngine*);
+ static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*);
+ static QScriptValue isQtObject(QScriptContext*, QScriptEngine*);
+ static QScriptValue vector3d(QScriptContext*, QScriptEngine*);
+ static QScriptValue rgba(QScriptContext*, QScriptEngine*);
+ static QScriptValue hsla(QScriptContext*, QScriptEngine*);
+ static QScriptValue point(QScriptContext*, QScriptEngine*);
+ static QScriptValue size(QScriptContext*, QScriptEngine*);
+ static QScriptValue rect(QScriptContext*, QScriptEngine*);
+
+ static QScriptValue lighter(QScriptContext*, QScriptEngine*);
+ static QScriptValue darker(QScriptContext*, QScriptEngine*);
+ static QScriptValue tint(QScriptContext*, QScriptEngine*);
+
+ static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*);
+ static QScriptValue fontFamilies(QScriptContext*, QScriptEngine*);
+ static QScriptValue md5(QScriptContext*, QScriptEngine*);
+ static QScriptValue btoa(QScriptContext*, QScriptEngine*);
+ static QScriptValue atob(QScriptContext*, QScriptEngine*);
+ static QScriptValue consoleLog(QScriptContext*, QScriptEngine*);
+ static QScriptValue quit(QScriptContext*, QScriptEngine*);
+
+#ifndef QT_NO_DATESTRING
+ static QScriptValue formatDate(QScriptContext*, QScriptEngine*);
+ static QScriptValue formatTime(QScriptContext*, QScriptEngine*);
+ static QScriptValue formatDateTime(QScriptContext*, QScriptEngine*);
+#endif
+ static QScriptEngine *getScriptEngine(QDeclarativeEngine *e) { return &e->d_func()->scriptEngine; }
+ static QDeclarativeEngine *getEngine(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p->q_func(); }
+ static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); }
+ static QDeclarativeEnginePrivate *get(QDeclarativeContext *c) { return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0; }
+ static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; }
+ static QDeclarativeEnginePrivate *get(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p; }
+ static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); }
+ QDeclarativeContextData *getContext(QScriptContext *);
+ QUrl getUrl(QScriptContext *);
+
+ static QString urlToLocalFileOrQrc(const QUrl& url);
+
+ static void defineModule();
+
+ static bool qml_debugging_enabled;
+};
+
+/*!
+Returns a QDeclarativePropertyCache for \a obj if one is available.
+
+If \a obj is null, being deleted or contains a dynamic meta object 0
+is returned.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QObject *obj)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return 0;
+
+ const QMetaObject *mo = obj->metaObject();
+ QDeclarativePropertyCache *rv = propertyCache.value(mo);
+ if (!rv) rv = createCache(mo);
+ return rv;
+}
+
+/*!
+Returns a QDeclarativePropertyCache for \a metaObject.
+
+As the cache is persisted for the life of the engine, \a metaObject must be
+a static "compile time" meta-object, or a meta-object that is otherwise known to
+exist for the lifetime of the QDeclarativeEngine.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+
+ QDeclarativePropertyCache *rv = propertyCache.value(metaObject);
+ if (!rv) rv = createCache(metaObject);
+ return rv;
+}
+
+/*!
+Returns a QDeclarativePropertyCache for \a type with \a minorVersion.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QDeclarativeType *type, int minorVersion, QDeclarativeError &error)
+{
+ Q_ASSERT(type);
+
+ if (minorVersion == -1 || !type->containsRevisionedAttributes())
+ return cache(type->metaObject());
+
+ QDeclarativePropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
+ if (!rv) rv = createCache(type, minorVersion, error);
+ return rv;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEENGINE_P_H
diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp
new file mode 100644
index 0000000000..b2a05c3235
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeenginedebug.cpp
@@ -0,0 +1,735 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeenginedebug_p.h"
+
+#include "private/qdeclarativeboundsignal_p.h"
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativewatcher_p.h"
+#include "private/qdeclarativevaluetype_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativepropertychanges_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDeclarativeEngineDebugServer, qmlEngineDebugServer);
+
+QDeclarativeEngineDebugServer *QDeclarativeEngineDebugServer::instance()
+{
+ return qmlEngineDebugServer();
+}
+
+QDeclarativeEngineDebugServer::QDeclarativeEngineDebugServer(QObject *parent)
+: QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent),
+ m_watch(new QDeclarativeWatcher(this))
+{
+ QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
+ this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
+{
+ ds << data.url << data.lineNumber << data.columnNumber << data.idString
+ << data.objectName << data.objectType << data.objectId << data.contextId;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
+{
+ ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
+ >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
+{
+ ds << (int)data.type << data.name << data.value << data.valueTypeName
+ << data.binding << data.hasNotifySignal;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
+{
+ int type;
+ ds >> type >> data.name >> data.value >> data.valueTypeName
+ >> data.binding >> data.hasNotifySignal;
+ data.type = (QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Type)type;
+ return ds;
+}
+
+static inline bool isSignalPropertyName(const QString &signalName)
+{
+ // see QmlCompiler::isSignalPropertyName
+ return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
+ signalName.at(2).isLetter() && signalName.at(2).isUpper();
+}
+
+static bool hasValidSignal(QObject *object, const QString &propertyName)
+{
+ if (!isSignalPropertyName(propertyName))
+ return false;
+
+ QString signalName = propertyName.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ int sigIdx = QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
+
+ if (sigIdx == -1)
+ return false;
+
+ return true;
+}
+
+QDeclarativeEngineDebugServer::QDeclarativeObjectProperty
+QDeclarativeEngineDebugServer::propertyData(QObject *obj, int propIdx)
+{
+ QDeclarativeObjectProperty rv;
+
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+
+ rv.type = QDeclarativeObjectProperty::Unknown;
+ rv.valueTypeName = QString::fromUtf8(prop.typeName());
+ rv.name = QString::fromUtf8(prop.name());
+ rv.hasNotifySignal = prop.hasNotifySignal();
+ QDeclarativeAbstractBinding *binding =
+ QDeclarativePropertyPrivate::binding(QDeclarativeProperty(obj, rv.name));
+ if (binding)
+ rv.binding = binding->expression();
+
+ QVariant value;
+ if (prop.userType() != 0) {
+ value = prop.read(obj);
+ }
+ rv.value = valueContents(value);
+
+ if (QDeclarativeValueTypeFactory::isValueType(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::Basic;
+ } else if (QDeclarativeMetaType::isQObject(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::Object;
+ } else if (QDeclarativeMetaType::isList(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::List;
+ }
+
+ return rv;
+}
+
+QVariant QDeclarativeEngineDebugServer::valueContents(const QVariant &value) const
+{
+ int userType = value.userType();
+
+ if (value.type() == QVariant::List) {
+ QVariantList contents;
+ QVariantList list = value.toList();
+ int count = list.size();
+ for (int i = 0; i < count; i++)
+ contents << valueContents(list.at(i));
+ return contents;
+ }
+
+ if (QDeclarativeValueTypeFactory::isValueType(userType))
+ return value;
+
+ if (QDeclarativeMetaType::isQObject(userType)) {
+ QObject *o = QDeclarativeMetaType::toQObject(value);
+ if (o) {
+ QString name = o->objectName();
+ if (name.isEmpty())
+ name = QLatin1String("<unnamed object>");
+ return name;
+ }
+ }
+
+ return QLatin1String("<unknown value>");
+}
+
+void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message,
+ QObject *object, bool recur, bool dumpProperties)
+{
+ message << objectData(object);
+
+ QObjectList children = object->children();
+
+ int childrenCount = children.count();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ if (qobject_cast<QDeclarativeContext*>(children[ii]) || QDeclarativeBoundSignal::cast(children[ii]))
+ --childrenCount;
+ }
+
+ message << childrenCount << recur;
+
+ QList<QDeclarativeObjectProperty> fakeProperties;
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ if (qobject_cast<QDeclarativeContext*>(child))
+ continue;
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal) {
+ if (!dumpProperties)
+ continue;
+ QDeclarativeObjectProperty prop;
+ prop.type = QDeclarativeObjectProperty::SignalProperty;
+ prop.hasNotifySignal = false;
+ QDeclarativeExpression *expr = signal->expression();
+ if (expr) {
+ prop.value = expr->expression();
+ QObject *scope = expr->scopeObject();
+ if (scope) {
+ QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature());
+ int lparen = sig.indexOf(QLatin1Char('('));
+ if (lparen >= 0) {
+ QString methodName = sig.mid(0, lparen);
+ prop.name = QLatin1String("on") + methodName[0].toUpper()
+ + methodName.mid(1);
+ }
+ }
+ }
+ fakeProperties << prop;
+ } else {
+ if (recur)
+ buildObjectDump(message, child, recur, dumpProperties);
+ else
+ message << objectData(child);
+ }
+ }
+
+ if (!dumpProperties) {
+ message << 0;
+ return;
+ }
+
+ QList<int> propertyIndexes;
+ for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) {
+ if (object->metaObject()->property(ii).isScriptable())
+ propertyIndexes << ii;
+ }
+
+ message << propertyIndexes.size() + fakeProperties.count();
+
+ for (int ii = 0; ii < propertyIndexes.size(); ++ii)
+ message << propertyData(object, propertyIndexes.at(ii));
+
+ for (int ii = 0; ii < fakeProperties.count(); ++ii)
+ message << fakeProperties[ii];
+}
+
+void QDeclarativeEngineDebugServer::prepareDeferredObjects(QObject *obj)
+{
+ qmlExecuteDeferred(obj);
+
+ QObjectList children = obj->children();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ prepareDeferredObjects(child);
+ }
+
+}
+
+void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, QDeclarativeContext *ctxt)
+{
+ QDeclarativeContextData *p = QDeclarativeContextData::get(ctxt);
+
+ QString ctxtName = ctxt->objectName();
+ int ctxtId = QDeclarativeDebugService::idForObject(ctxt);
+
+ message << ctxtName << ctxtId;
+
+ int count = 0;
+
+ QDeclarativeContextData *child = p->childContexts;
+ while (child) {
+ ++count;
+ child = child->nextChild;
+ }
+
+ message << count;
+
+ child = p->childContexts;
+ while (child) {
+ buildObjectList(message, child->asQDeclarativeContext());
+ child = child->nextChild;
+ }
+
+ // Clean deleted objects
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ if (!ctxtPriv->instances.at(ii)) {
+ ctxtPriv->instances.removeAt(ii);
+ --ii;
+ }
+ }
+
+ message << ctxtPriv->instances.count();
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ message << objectData(ctxtPriv->instances.at(ii));
+ }
+}
+
+void QDeclarativeEngineDebugServer::buildStatesList(QDeclarativeContext *ctxt, bool cleanList=false)
+{
+ if (cleanList)
+ m_allStates.clear();
+
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ buildStatesList(ctxtPriv->instances.at(ii));
+ }
+
+ QDeclarativeContextData *child = QDeclarativeContextData::get(ctxt)->childContexts;
+ while (child) {
+ buildStatesList(child->asQDeclarativeContext());
+ child = child->nextChild;
+ }
+}
+
+void QDeclarativeEngineDebugServer::buildStatesList(QObject *obj)
+{
+ if (QDeclarativeState *state = qobject_cast<QDeclarativeState *>(obj)) {
+ m_allStates.append(state);
+ }
+
+ QObjectList children = obj->children();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ buildStatesList(children.at(ii));
+ }
+}
+
+QDeclarativeEngineDebugServer::QDeclarativeObjectData
+QDeclarativeEngineDebugServer::objectData(QObject *object)
+{
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ QDeclarativeObjectData rv;
+ if (ddata && ddata->outerContext) {
+ rv.url = ddata->outerContext->url;
+ rv.lineNumber = ddata->lineNumber;
+ rv.columnNumber = ddata->columnNumber;
+ } else {
+ rv.lineNumber = -1;
+ rv.columnNumber = -1;
+ }
+
+ QDeclarativeContext *context = qmlContext(object);
+ if (context) {
+ QDeclarativeContextData *cdata = QDeclarativeContextData::get(context);
+ if (cdata)
+ rv.idString = cdata->findObjectId(object);
+ }
+
+ rv.objectName = object->objectName();
+ rv.objectId = QDeclarativeDebugService::idForObject(object);
+ rv.contextId = QDeclarativeDebugService::idForObject(qmlContext(object));
+
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
+ if (type) {
+ QString typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
+ } else {
+ rv.objectType = QString::fromUtf8(object->metaObject()->className());
+ int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
+ if (marker != -1)
+ rv.objectType = rv.objectType.left(marker);
+ }
+
+ return rv;
+}
+
+void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
+{
+ QDataStream ds(message);
+
+ QByteArray type;
+ ds >> type;
+
+ if (type == "LIST_ENGINES") {
+ int queryId;
+ ds >> queryId;
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_ENGINES_R");
+ rs << queryId << m_engines.count();
+
+ for (int ii = 0; ii < m_engines.count(); ++ii) {
+ QDeclarativeEngine *engine = m_engines.at(ii);
+
+ QString engineName = engine->objectName();
+ int engineId = QDeclarativeDebugService::idForObject(engine);
+
+ rs << engineName << engineId;
+ }
+
+ sendMessage(reply);
+ } else if (type == "LIST_OBJECTS") {
+ int queryId;
+ int engineId = -1;
+ ds >> queryId >> engineId;
+
+ QDeclarativeEngine *engine =
+ qobject_cast<QDeclarativeEngine *>(QDeclarativeDebugService::objectForId(engineId));
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_OBJECTS_R") << queryId;
+
+ if (engine) {
+ buildObjectList(rs, engine->rootContext());
+ buildStatesList(engine->rootContext(), true);
+ }
+
+ sendMessage(reply);
+ } else if (type == "FETCH_OBJECT") {
+ int queryId;
+ int objectId;
+ bool recurse;
+ bool dumpProperties = true;
+
+ ds >> queryId >> objectId >> recurse >> dumpProperties;
+
+ QObject *object = QDeclarativeDebugService::objectForId(objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("FETCH_OBJECT_R") << queryId;
+
+ if (object) {
+ if (recurse)
+ prepareDeferredObjects(object);
+ buildObjectDump(rs, object, recurse, dumpProperties);
+ }
+
+ sendMessage(reply);
+ } else if (type == "WATCH_OBJECT") {
+ int queryId;
+ int objectId;
+
+ ds >> queryId >> objectId;
+ bool ok = m_watch->addWatch(queryId, objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_PROPERTY") {
+ int queryId;
+ int objectId;
+ QByteArray property;
+
+ ds >> queryId >> objectId >> property;
+ bool ok = m_watch->addWatch(queryId, objectId, property);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_EXPR_OBJECT") {
+ int queryId;
+ int debugId;
+ QString expr;
+
+ ds >> queryId >> debugId >> expr;
+ bool ok = m_watch->addWatch(queryId, debugId, expr);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
+ sendMessage(reply);
+ } else if (type == "NO_WATCH") {
+ int queryId;
+
+ ds >> queryId;
+ m_watch->removeWatch(queryId);
+ } else if (type == "EVAL_EXPRESSION") {
+ int queryId;
+ int objectId;
+ QString expr;
+
+ ds >> queryId >> objectId >> expr;
+
+ QObject *object = QDeclarativeDebugService::objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ QVariant result;
+ if (object && context) {
+ QDeclarativeExpression exprObj(context, object, expr);
+ bool undefined = false;
+ QVariant value = exprObj.evaluate(&undefined);
+ if (undefined)
+ result = QLatin1String("<undefined>");
+ else
+ result = valueContents(value);
+ } else {
+ result = QLatin1String("<unknown context>");
+ }
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
+
+ sendMessage(reply);
+ } else if (type == "SET_BINDING") {
+ int objectId;
+ QString propertyName;
+ QVariant expr;
+ bool isLiteralValue;
+ ds >> objectId >> propertyName >> expr >> isLiteralValue;
+ setBinding(objectId, propertyName, expr, isLiteralValue);
+ } else if (type == "RESET_BINDING") {
+ int objectId;
+ QString propertyName;
+ ds >> objectId >> propertyName;
+ resetBinding(objectId, propertyName);
+ } else if (type == "SET_METHOD_BODY") {
+ int objectId;
+ QString methodName;
+ QString methodBody;
+ ds >> objectId >> methodName >> methodBody;
+ setMethodBody(objectId, methodName, methodBody);
+ }
+}
+
+void QDeclarativeEngineDebugServer::setBinding(int objectId,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+
+ if (object && context) {
+ QDeclarativeProperty property(object, propertyName, context);
+ if (property.isValid()) {
+
+ bool inBaseState = true;
+
+ foreach(QWeakPointer<QDeclarativeState> statePointer, m_allStates) {
+ if (QDeclarativeState *state = statePointer.data()) {
+ // here we assume that the revert list on itself defines the base state
+ if (state->isStateActive() && state->containsPropertyInRevertList(object, propertyName)) {
+ inBaseState = false;
+
+ QDeclarativeBinding *newBinding = 0;
+ if (!isLiteralValue) {
+ newBinding = new QDeclarativeBinding(expression.toString(), object, context);
+ newBinding->setTarget(property);
+ newBinding->setNotifyOnValueChanged(true);
+ }
+
+ state->changeBindingInRevertList(object, propertyName, newBinding);
+
+ if (isLiteralValue)
+ state->changeValueInRevertList(object, propertyName, expression);
+ }
+ }
+ }
+
+ if (inBaseState) {
+ if (isLiteralValue) {
+ property.write(expression);
+ } else if (hasValidSignal(object, propertyName)) {
+ QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString());
+ QDeclarativeExpression *oldExpression = QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression);
+ declarativeExpression->setSourceLocation(oldExpression->sourceFile(), oldExpression->lineNumber());
+ } else if (property.isProperty()) {
+ QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context);
+ binding->setTarget(property);
+ binding->setNotifyOnValueChanged(true);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding);
+ if (oldBinding)
+ oldBinding->destroy();
+ binding->update();
+ } else {
+ qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+
+ } else {
+ // not a valid property
+ if (QDeclarativePropertyChanges *propertyChanges = qobject_cast<QDeclarativePropertyChanges *>(object)) {
+ if (isLiteralValue) {
+ propertyChanges->changeValue(propertyName, expression);
+ } else {
+ propertyChanges->changeExpression(propertyName, expression.toString());
+ }
+ } else {
+ qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+ }
+}
+
+void QDeclarativeEngineDebugServer::resetBinding(int objectId, const QString &propertyName)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+
+ if (object && context) {
+ if (object->property(propertyName.toLatin1()).isValid()) {
+ QDeclarativeProperty property(object, propertyName);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(property);
+ if (oldBinding) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, 0);
+ if (oldBinding)
+ oldBinding->destroy();
+ }
+ if (property.isResettable()) {
+ // Note: this will reset the property in any case, without regard to states
+ // Right now almost no QDeclarativeItem has reset methods for its properties (with the
+ // notable exception of QDeclarativeAnchors), so this is not a big issue
+ // later on, setBinding does take states into account
+ property.reset();
+ } else {
+ // overwrite with default value
+ if (QDeclarativeType *objType = QDeclarativeMetaType::qmlType(object->metaObject())) {
+ if (QObject *emptyObject = objType->create()) {
+ if (emptyObject->property(propertyName.toLatin1()).isValid()) {
+ QVariant defaultValue = QDeclarativeProperty(emptyObject, propertyName).read();
+ if (defaultValue.isValid()) {
+ setBinding(objectId, propertyName, defaultValue, true);
+ }
+ }
+ delete emptyObject;
+ }
+ }
+ }
+ } else {
+ if (QDeclarativePropertyChanges *propertyChanges = qobject_cast<QDeclarativePropertyChanges *>(object)) {
+ propertyChanges->removeProperty(propertyName);
+ }
+ }
+ }
+}
+
+void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &method, const QString &body)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ if (!object || !context || !context->engine())
+ return;
+ QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
+ if (!contextData)
+ return;
+
+ QDeclarativePropertyCache::Data dummy;
+ QDeclarativePropertyCache::Data *prop =
+ QDeclarativePropertyCache::property(context->engine(), object, method, dummy);
+
+ if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction))
+ return;
+
+ QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
+ QList<QByteArray> paramNames = metaMethod.parameterNames();
+
+ QString paramStr;
+ for (int ii = 0; ii < paramNames.count(); ++ii) {
+ if (ii != 0) paramStr.append(QLatin1String(","));
+ paramStr.append(QString::fromUtf8(paramNames.at(ii)));
+ }
+
+ QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr +
+ QLatin1String(") {");
+ jsfunction += body;
+ jsfunction += QLatin1String("\n})");
+
+ QDeclarativeVMEMetaObject *vmeMetaObject =
+ static_cast<QDeclarativeVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
+ vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0));
+}
+
+void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
+
+ sendMessage(reply);
+}
+
+void QDeclarativeEngineDebugServer::addEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(!m_engines.contains(engine));
+
+ m_engines.append(engine);
+}
+
+void QDeclarativeEngineDebugServer::remEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ m_engines.removeAll(engine);
+}
+
+void QDeclarativeEngineDebugServer::objectCreated(QDeclarativeEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ int engineId = QDeclarativeDebugService::idForObject(engine);
+ int objectId = QDeclarativeDebugService::idForObject(object);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
+ sendMessage(reply);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h
new file mode 100644
index 0000000000..e95676c4cb
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeenginedebug_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEENGINEDEBUG_P_H
+#define QDECLARATIVEENGINEDEBUG_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/qdeclarativedebugservice_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QWeakPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeWatcher;
+class QDataStream;
+class QDeclarativeState;
+
+class QDeclarativeEngineDebugServer : public QDeclarativeDebugService
+{
+ Q_OBJECT
+public:
+ QDeclarativeEngineDebugServer(QObject * = 0);
+
+ struct QDeclarativeObjectData {
+ QUrl url;
+ int lineNumber;
+ int columnNumber;
+ QString idString;
+ QString objectName;
+ QString objectType;
+ int objectId;
+ int contextId;
+ };
+
+ struct QDeclarativeObjectProperty {
+ enum Type { Unknown, Basic, Object, List, SignalProperty };
+ Type type;
+ QString name;
+ QVariant value;
+ QString valueTypeName;
+ QString binding;
+ bool hasNotifySignal;
+ };
+
+ void addEngine(QDeclarativeEngine *);
+ void remEngine(QDeclarativeEngine *);
+ void objectCreated(QDeclarativeEngine *, QObject *);
+
+ static QDeclarativeEngineDebugServer *instance();
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ void prepareDeferredObjects(QObject *);
+ void buildObjectList(QDataStream &, QDeclarativeContext *);
+ void buildObjectDump(QDataStream &, QObject *, bool, bool);
+ void buildStatesList(QDeclarativeContext *, bool);
+ void buildStatesList(QObject *obj);
+ QDeclarativeObjectData objectData(QObject *);
+ QDeclarativeObjectProperty propertyData(QObject *, int);
+ QVariant valueContents(const QVariant &defaultValue) const;
+ void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue);
+ void resetBinding(int objectId, const QString &propertyName);
+ void setMethodBody(int objectId, const QString &method, const QString &body);
+
+ QList<QDeclarativeEngine *> m_engines;
+ QDeclarativeWatcher *m_watch;
+ QList<QWeakPointer<QDeclarativeState> > m_allStates;
+};
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugServer::QDeclarativeObjectData &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QDeclarativeEngineDebugServer::QDeclarativeObjectData &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEENGINEDEBUG_P_H
+
diff --git a/src/declarative/qml/qdeclarativeerror.cpp b/src/declarative/qml/qdeclarativeerror.cpp
new file mode 100644
index 0000000000..90faba9bae
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeerror.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeerror.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativeError
+ \since 4.7
+ \brief The QDeclarativeError class encapsulates a QML error.
+
+ QDeclarativeError includes a textual description of the error, as well
+ as location information (the file, line, and column). The toString()
+ method creates a single-line, human-readable string containing all of
+ this information, for example:
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ \endcode
+
+ You can use qDebug() or qWarning() to output errors to the console. This method
+ will attempt to open the file indicated by the error
+ and include additional contextual information.
+ \code
+ file:///home/user/test.qml:7:8: Invalid property assignment: double expected
+ y: "hello"
+ ^
+ \endcode
+
+ \sa QDeclarativeView::errors(), QDeclarativeComponent::errors()
+*/
+class QDeclarativeErrorPrivate
+{
+public:
+ QDeclarativeErrorPrivate();
+
+ QUrl url;
+ QString description;
+ int line;
+ int column;
+};
+
+QDeclarativeErrorPrivate::QDeclarativeErrorPrivate()
+: line(-1), column(-1)
+{
+}
+
+/*!
+ Creates an empty error object.
+*/
+QDeclarativeError::QDeclarativeError()
+: d(0)
+{
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+QDeclarativeError::QDeclarativeError(const QDeclarativeError &other)
+: d(0)
+{
+ *this = other;
+}
+
+/*!
+ Assigns \a other to this error object.
+*/
+QDeclarativeError &QDeclarativeError::operator=(const QDeclarativeError &other)
+{
+ if (!other.d) {
+ delete d;
+ d = 0;
+ } else {
+ if (!d) d = new QDeclarativeErrorPrivate;
+ d->url = other.d->url;
+ d->description = other.d->description;
+ d->line = other.d->line;
+ d->column = other.d->column;
+ }
+ return *this;
+}
+
+/*!
+ \internal
+*/
+QDeclarativeError::~QDeclarativeError()
+{
+ delete d; d = 0;
+}
+
+/*!
+ Returns true if this error is valid, otherwise false.
+*/
+bool QDeclarativeError::isValid() const
+{
+ return d != 0;
+}
+
+/*!
+ Returns the url for the file that caused this error.
+*/
+QUrl QDeclarativeError::url() const
+{
+ if (d) return d->url;
+ else return QUrl();
+}
+
+/*!
+ Sets the \a url for the file that caused this error.
+*/
+void QDeclarativeError::setUrl(const QUrl &url)
+{
+ if (!d) d = new QDeclarativeErrorPrivate;
+ d->url = url;
+}
+
+/*!
+ Returns the error description.
+*/
+QString QDeclarativeError::description() const
+{
+ if (d) return d->description;
+ else return QString();
+}
+
+/*!
+ Sets the error \a description.
+*/
+void QDeclarativeError::setDescription(const QString &description)
+{
+ if (!d) d = new QDeclarativeErrorPrivate;
+ d->description = description;
+}
+
+/*!
+ Returns the error line number.
+*/
+int QDeclarativeError::line() const
+{
+ if (d) return d->line;
+ else return -1;
+}
+
+/*!
+ Sets the error \a line number.
+*/
+void QDeclarativeError::setLine(int line)
+{
+ if (!d) d = new QDeclarativeErrorPrivate;
+ d->line = line;
+}
+
+/*!
+ Returns the error column number.
+*/
+int QDeclarativeError::column() const
+{
+ if (d) return d->column;
+ else return -1;
+}
+
+/*!
+ Sets the error \a column number.
+*/
+void QDeclarativeError::setColumn(int column)
+{
+ if (!d) d = new QDeclarativeErrorPrivate;
+ d->column = column;
+}
+
+/*!
+ Returns the error as a human readable string.
+*/
+QString QDeclarativeError::toString() const
+{
+ QString rv;
+ if (url().isEmpty()) {
+ rv = QLatin1String("<Unknown File>");
+ } else if (line() != -1) {
+ rv = url().toString() + QLatin1Char(':') + QString::number(line());
+ if(column() != -1)
+ rv += QLatin1Char(':') + QString::number(column());
+ } else {
+ rv = url().toString();
+ }
+
+ rv += QLatin1String(": ") + description();
+
+ return rv;
+}
+
+/*!
+ \relates QDeclarativeError
+ \fn QDebug operator<<(QDebug debug, const QDeclarativeError &error)
+
+ Outputs a human readable version of \a error to \a debug.
+*/
+
+QDebug operator<<(QDebug debug, const QDeclarativeError &error)
+{
+ debug << qPrintable(error.toString());
+
+ QUrl url = error.url();
+
+ if (error.line() > 0 && url.scheme() == QLatin1String("file")) {
+ QString file = url.toLocalFile();
+ QFile f(file);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QTextStream stream(data, QIODevice::ReadOnly);
+#ifndef QT_NO_TEXTCODEC
+ stream.setCodec("UTF-8");
+#endif
+ const QString code = stream.readAll();
+ const QStringList lines = code.split(QLatin1Char('\n'));
+
+ if (lines.count() >= error.line()) {
+ const QString &line = lines.at(error.line() - 1);
+ debug << "\n " << qPrintable(line);
+
+ if(error.column() > 0) {
+ int column = qMax(0, error.column() - 1);
+ column = qMin(column, line.length());
+
+ QByteArray ind;
+ ind.reserve(column);
+ for (int i = 0; i < column; ++i) {
+ const QChar ch = line.at(i);
+ if (ch.isSpace())
+ ind.append(ch.unicode());
+ else
+ ind.append(' ');
+ }
+ ind.append('^');
+ debug << "\n " << ind.constData();
+ }
+ }
+ }
+ }
+ return debug;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeerror.h b/src/declarative/qml/qdeclarativeerror.h
new file mode 100644
index 0000000000..a85a1bf14f
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeerror.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 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 QDECLARATIVEERROR_H
+#define QDECLARATIVEERROR_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDebug;
+class QDeclarativeErrorPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeError
+{
+public:
+ QDeclarativeError();
+ QDeclarativeError(const QDeclarativeError &);
+ QDeclarativeError &operator=(const QDeclarativeError &);
+ ~QDeclarativeError();
+
+ bool isValid() const;
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ QString description() const;
+ void setDescription(const QString &);
+ int line() const;
+ void setLine(int);
+ int column() const;
+ void setColumn(int);
+
+ QString toString() const;
+private:
+ QDeclarativeErrorPrivate *d;
+};
+
+QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, const QDeclarativeError &error);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEERROR_H
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
new file mode 100644
index 0000000000..7a85adaa6e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -0,0 +1,875 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeexpression.h"
+#include "private/qdeclarativeexpression_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativerewrite_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativeglobalscriptclass_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptprogram.h>
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
+{
+ if (!e) return false;
+
+ if (e->inProgressCreations == 0) return false; // Not in construction
+
+ if (prevError) return true; // Already in error chain
+
+ prevError = &e->erroredBindings;
+ nextError = e->erroredBindings;
+ e->erroredBindings = this;
+ if (nextError) nextError->prevError = &nextError;
+
+ return true;
+}
+
+QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
+: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false),
+ guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
+{
+}
+
+QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
+{
+ if (guardList) { delete [] guardList; guardList = 0; }
+ if (dataRef) dataRef->release();
+ if (deleted) *deleted = true;
+}
+
+QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
+: expressionFunctionValid(true), line(-1)
+{
+}
+
+QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
+{
+}
+
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
+ QObject *me)
+{
+ expression = expr;
+
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+ expressionFunctionValid = false;
+}
+
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+ QObject *me)
+{
+ expression = func.toString();
+
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+
+ expressionFunction = func;
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
+}
+
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr,
+ QDeclarativeRefCount *rc,
+ QObject *me, const QString &srcUrl, int lineNumber)
+{
+ url = srcUrl;
+ line = lineNumber;
+
+ if (dataRef) dataRef->release();
+ dataRef = rc;
+ if (dataRef) dataRef->addref();
+
+ quint32 *exprData = (quint32 *)expr;
+ QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
+
+ expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
+
+ int progIdx = *(exprData);
+ bool isSharedProgram = progIdx & 0x80000000;
+ progIdx &= 0x7FFFFFFF;
+
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (isSharedProgram) {
+
+ if (!dd->cachedClosures.at(progIdx)) {
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ scriptContext->pushScope(ep->contextClass->newSharedContext());
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+ dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
+ scriptEngine->popContext();
+ }
+
+ expressionFunction = *dd->cachedClosures.at(progIdx);
+ expressionFunctionMode = SharedContext;
+ expressionFunctionValid = true;
+
+ } else {
+
+ if (!dd->cachedPrograms.at(progIdx)) {
+ dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
+ }
+
+ expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
+ &expressionContext);
+
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
+ }
+
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+}
+
+QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
+ const QString &program, const QString &fileName,
+ int lineNumber, QScriptValue *contextObject)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
+ if (contextObject) {
+ *contextObject = ep->contextClass->newContext(context, object);
+ scriptContext->pushScope(*contextObject);
+ } else {
+ scriptContext->pushScope(ep->contextClass->newContext(context, object));
+ }
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+ QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
+ ep->scriptEngine.popContext();
+ return rv;
+}
+
+QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
+ const QScriptProgram &program,
+ QScriptValue *contextObject)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
+ if (contextObject) {
+ *contextObject = ep->contextClass->newContext(context, object);
+ scriptContext->pushScope(*contextObject);
+ } else {
+ scriptContext->pushScope(ep->contextClass->newContext(context, object));
+ }
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+ QScriptValue rv = ep->scriptEngine.evaluate(program);
+ ep->scriptEngine.popContext();
+ return rv;
+}
+
+/*!
+ \class QDeclarativeExpression
+ \since 4.7
+ \brief The QDeclarativeExpression class evaluates JavaScript in a QML context.
+
+ For example, given a file \c main.qml like this:
+
+ \qml
+ import QtQuick 1.0
+
+ Item {
+ width: 200; height: 200
+ }
+ \endqml
+
+ The following code evaluates a JavaScript expression in the context of the
+ above QML:
+
+ \code
+ QDeclarativeEngine *engine = new QDeclarativeEngine;
+ QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
+
+ QObject *myObject = component.create();
+ QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2");
+ int result = expr->evaluate().toInt(); // result = 400
+ \endcode
+*/
+
+static int QDeclarativeExpression_notifyIdx = -1;
+
+/*!
+ Create an invalid QDeclarativeExpression.
+
+ As the expression will not have an associated QDeclarativeContext, this will be a
+ null expression object and its value will always be an invalid QVariant.
+ */
+QDeclarativeExpression::QDeclarativeExpression()
+: QObject(*new QDeclarativeExpressionPrivate, 0)
+{
+ Q_D(QDeclarativeExpression);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*! \internal */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
+ QDeclarativeRefCount *rc, QObject *me,
+ const QString &url, int lineNumber,
+ QDeclarativeExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, expr, rc, me, url, lineNumber);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*!
+ Create a QDeclarativeExpression object that is a child of \a parent.
+
+ The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext.
+ If specified, the \a scope object's properties will also be in scope during
+ the expression's execution.
+*/
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
+ QObject *scope,
+ const QString &expression,
+ QObject *parent)
+: QObject(*new QDeclarativeExpressionPrivate, parent)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(QDeclarativeContextData::get(ctxt), expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*!
+ \internal
+*/
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &expression)
+: QObject(*new QDeclarativeExpressionPrivate, 0)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*! \internal */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &expression, QDeclarativeExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, expression, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*! \internal */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
+ QDeclarativeExpressionPrivate &dd)
+: QObject(dd, 0)
+{
+ Q_D(QDeclarativeExpression);
+ d->init(ctxt, func, scope);
+
+ if (QDeclarativeExpression_notifyIdx == -1)
+ QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+ d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+}
+
+/*!
+ Destroy the QDeclarativeExpression instance.
+*/
+QDeclarativeExpression::~QDeclarativeExpression()
+{
+}
+
+/*!
+ Returns the QDeclarativeEngine this expression is associated with, or 0 if there
+ is no association or the QDeclarativeEngine has been destroyed.
+*/
+QDeclarativeEngine *QDeclarativeExpression::engine() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->context()?d->context()->engine:0;
+}
+
+/*!
+ Returns the QDeclarativeContext this expression is associated with, or 0 if there
+ is no association or the QDeclarativeContext has been destroyed.
+*/
+QDeclarativeContext *QDeclarativeExpression::context() const
+{
+ Q_D(const QDeclarativeExpression);
+ QDeclarativeContextData *data = d->context();
+ return data?data->asQDeclarativeContext():0;
+}
+
+/*!
+ Returns the expression string.
+*/
+QString QDeclarativeExpression::expression() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->expression;
+}
+
+/*!
+ Set the expression to \a expression.
+*/
+void QDeclarativeExpression::setExpression(const QString &expression)
+{
+ Q_D(QDeclarativeExpression);
+
+ d->resetNotifyOnChange();
+ d->expression = expression;
+ d->expressionFunctionValid = false;
+ d->expressionFunction = QScriptValue();
+}
+
+void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
+ QDeclarativeError &error)
+{
+ if (scriptEngine->hasUncaughtException() &&
+ scriptEngine->uncaughtException().isError()) {
+
+ QString fileName;
+ int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
+
+ QScriptValue exception = scriptEngine->uncaughtException();
+ QLatin1String fileNameProp("fileName");
+
+ if (!exception.property(fileNameProp).toString().isEmpty()){
+ fileName = exception.property(fileNameProp).toString();
+ } else {
+ fileName = QLatin1String("<Unknown File>");
+ }
+
+ error.setUrl(QUrl(fileName));
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+ error.setDescription(exception.toString());
+ } else {
+ error = QDeclarativeError();
+ }
+}
+
+bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
+{
+ return trackChange;
+}
+
+void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
+{
+ trackChange = notify;
+ if (!notify && guardList)
+ clearGuards();
+}
+
+void QDeclarativeQtScriptExpression::resetNotifyOnChange()
+{
+ clearGuards();
+}
+
+void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
+{
+ if (guardList) clearGuards();
+
+ if (!object || notifyIndex == -1) {
+ guardObject = 0;
+ notifyIndex = -1;
+ } else {
+ guardObject = object;
+ guardObjectNotifyIndex = notifyIndex;
+
+ }
+}
+
+void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags)
+{
+ evalFlags = flags;
+}
+
+QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const
+{
+ return evalFlags;
+}
+
+QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_ASSERT(context() && context()->engine);
+ Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
+
+ if (!expressionFunction.isValid()) {
+ if (isUndefined) *isUndefined = true;
+ return QScriptValue();
+ }
+
+ DeleteWatcher watcher(this);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
+
+ bool lastCaptureProperties = ep->captureProperties;
+ QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
+ ep->captureProperties = trackChange;
+ ep->capturedProperties.copyAndClear(lastCapturedProperties);
+
+ QScriptValue value = eval(secondaryScope, isUndefined);
+
+ if (!watcher.wasDeleted() && trackChange) {
+ if (ep->capturedProperties.count() == 0) {
+
+ if (guardList) clearGuards();
+
+ } else {
+
+ updateGuards(ep->capturedProperties);
+
+ }
+ }
+
+ lastCapturedProperties.copyAndClear(ep->capturedProperties);
+ ep->captureProperties = lastCaptureProperties;
+
+ return value;
+}
+
+QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_ASSERT(context() && context()->engine);
+
+ DeleteWatcher watcher(this);
+
+ QDeclarativeEngine *engine = context()->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ QDeclarativeContextData *oldSharedContext = 0;
+ QObject *oldSharedScope = 0;
+ QObject *oldOverride = 0;
+ bool isShared = (expressionFunctionMode == SharedContext);
+
+ if (isShared) {
+ oldSharedContext = ep->sharedContext;
+ oldSharedScope = ep->sharedScope;
+ ep->sharedContext = context();
+ ep->sharedScope = scopeObject;
+ } else {
+ oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
+ }
+
+ QScriptValue thisObject;
+ if (evalFlags & RequiresThisObject)
+ thisObject = ep->objectClass->newQObject(scopeObject);
+ QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
+
+ if (isShared) {
+ ep->sharedContext = oldSharedContext;
+ ep->sharedScope = oldSharedScope;
+ } else if (!watcher.wasDeleted()) {
+ ep->contextClass->setOverrideObject(expressionContext, oldOverride);
+ }
+
+ if (isUndefined)
+ *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+
+ // Handle exception
+ if (scriptEngine->hasUncaughtException()) {
+ if (!watcher.wasDeleted())
+ QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+
+ scriptEngine->clearExceptions();
+ return QScriptValue();
+ } else {
+ if (!watcher.wasDeleted())
+ error = QDeclarativeError();
+
+ return svalue;
+ }
+}
+
+void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
+{
+ Q_ASSERT(guardObject);
+ Q_ASSERT(guardObjectNotifyIndex != -1);
+
+ if (properties.count() != guardListLength) {
+ QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
+
+ for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii)
+ guardList[ii].copyAndClear(newGuardList[ii]);
+
+ delete [] guardList;
+ guardList = newGuardList;
+ guardListLength = properties.count();
+ }
+
+ bool outputWarningHeader = false;
+ bool noChanges = true;
+ for (int ii = 0; ii < properties.count(); ++ii) {
+ QDeclarativeNotifierEndpoint &guard = guardList[ii];
+ const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
+
+ guard.target = guardObject;
+ guard.targetMethod = guardObjectNotifyIndex;
+
+ if (property.notifier != 0) {
+
+ if (!noChanges && guard.isConnected(property.notifier)) {
+ // Nothing to do
+
+ } else {
+ noChanges = false;
+
+ bool existing = false;
+ for (int jj = 0; !existing && jj < ii; ++jj)
+ if (guardList[jj].isConnected(property.notifier))
+ existing = true;
+
+ if (existing) {
+ // duplicate
+ guard.disconnect();
+ } else {
+ guard.connect(property.notifier);
+ }
+ }
+
+
+ } else if (property.notifyIndex != -1) {
+
+ if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
+ // Nothing to do
+
+ } else {
+ noChanges = false;
+
+ bool existing = false;
+ for (int jj = 0; !existing && jj < ii; ++jj)
+ if (guardList[jj].isConnected(property.object, property.notifyIndex))
+ existing = true;
+
+ if (existing) {
+ // duplicate
+ guard.disconnect();
+ } else {
+ guard.connect(property.object, property.notifyIndex);
+ }
+ }
+
+ } else {
+ if (!outputWarningHeader) {
+ outputWarningHeader = true;
+ qWarning() << "QDeclarativeExpression: Expression" << expression
+ << "depends on non-NOTIFYable properties:";
+ }
+
+ const QMetaObject *metaObj = property.object->metaObject();
+ QMetaProperty metaProp = metaObj->property(property.coreIndex);
+
+ qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name();
+ }
+ }
+}
+
+QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+{
+ if (!expressionFunctionValid) {
+ QDeclarativeEngine *engine = context()->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
+ expressionContext = ep->contextClass->newContext(context(), scopeObject);
+ scriptContext->pushScope(expressionContext);
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+
+ QDeclarativeRewrite::RewriteBinding rewriteBinding;
+ rewriteBinding.setName(name);
+ bool ok = true;
+ const QString code = rewriteBinding(expression, &ok);
+ if (ok)
+ expressionFunction = scriptEngine->evaluate(code, url, line);
+
+ scriptEngine->popContext();
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
+ }
+
+ return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+}
+
+QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_Q(QDeclarativeExpression);
+
+ if (!context() || !context()->isValid()) {
+ qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
+ return QVariant();
+ }
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+
+ return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >());
+}
+
+/*!
+ Evaulates the expression, returning the result of the evaluation,
+ or an invalid QVariant if the expression is invalid or has an error.
+
+ \a valueIsUndefined is set to true if the expression resulted in an
+ undefined value.
+
+ \sa hasError(), error()
+*/
+QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined)
+{
+ Q_D(QDeclarativeExpression);
+ return d->value(0, valueIsUndefined);
+}
+
+/*!
+Returns true if the valueChanged() signal is emitted when the expression's evaluated
+value changes.
+*/
+bool QDeclarativeExpression::notifyOnValueChanged() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->notifyOnValueChange();
+}
+
+/*!
+ Sets whether the valueChanged() signal is emitted when the
+ expression's evaluated value changes.
+
+ If \a notifyOnChange is true, the QDeclarativeExpression will
+ monitor properties involved in the expression's evaluation, and emit
+ QDeclarativeExpression::valueChanged() if they have changed. This
+ allows an application to ensure that any value associated with the
+ result of the expression remains up to date.
+
+ If \a notifyOnChange is false (default), the QDeclarativeExpression
+ will not montitor properties involved in the expression's
+ evaluation, and QDeclarativeExpression::valueChanged() will never be
+ emitted. This is more efficient if an application wants a "one off"
+ evaluation of the expression.
+*/
+void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
+{
+ Q_D(QDeclarativeExpression);
+ d->setNotifyOnValueChange(notifyOnChange);
+}
+
+/*!
+ Returns the source file URL for this expression. The source location must
+ have been previously set by calling setSourceLocation().
+*/
+QString QDeclarativeExpression::sourceFile() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->url;
+}
+
+/*!
+ Returns the source file line number for this expression. The source location
+ must have been previously set by calling setSourceLocation().
+*/
+int QDeclarativeExpression::lineNumber() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->line;
+}
+
+/*!
+ Set the location of this expression to \a line of \a url. This information
+ is used by the script engine.
+*/
+void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
+{
+ Q_D(QDeclarativeExpression);
+ d->url = url;
+ d->line = line;
+}
+
+/*!
+ Returns the expression's scope object, if provided, otherwise 0.
+
+ In addition to data provided by the expression's QDeclarativeContext, the scope
+ object's properties are also in scope during the expression's evaluation.
+*/
+QObject *QDeclarativeExpression::scopeObject() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->scopeObject;
+}
+
+/*!
+ Returns true if the last call to evaluate() resulted in an error,
+ otherwise false.
+
+ \sa error(), clearError()
+*/
+bool QDeclarativeExpression::hasError() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->error.isValid();
+}
+
+/*!
+ Clear any expression errors. Calls to hasError() following this will
+ return false.
+
+ \sa hasError(), error()
+*/
+void QDeclarativeExpression::clearError()
+{
+ Q_D(QDeclarativeExpression);
+ d->error = QDeclarativeError();
+}
+
+/*!
+ Return any error from the last call to evaluate(). If there was no error,
+ this returns an invalid QDeclarativeError instance.
+
+ \sa hasError(), clearError()
+*/
+
+QDeclarativeError QDeclarativeExpression::error() const
+{
+ Q_D(const QDeclarativeExpression);
+ return d->error;
+}
+
+/*! \internal */
+void QDeclarativeExpressionPrivate::_q_notify()
+{
+ emitValueChanged();
+}
+
+void QDeclarativeQtScriptExpression::clearGuards()
+{
+ delete [] guardList;
+ guardList = 0;
+ guardListLength = 0;
+}
+
+/*!
+ \fn void QDeclarativeExpression::valueChanged()
+
+ Emitted each time the expression value changes from the last time it was
+ evaluated. The expression must have been evaluated at least once (by
+ calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
+*/
+
+void QDeclarativeExpressionPrivate::emitValueChanged()
+{
+ Q_Q(QDeclarativeExpression);
+ emit q->valueChanged();
+}
+
+QDeclarativeAbstractExpression::QDeclarativeAbstractExpression()
+: m_context(0), m_prevExpression(0), m_nextExpression(0)
+{
+}
+
+QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression()
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ }
+}
+
+QDeclarativeContextData *QDeclarativeAbstractExpression::context() const
+{
+ return m_context;
+}
+
+void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context)
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ m_prevExpression = 0;
+ m_nextExpression = 0;
+ }
+
+ m_context = context;
+
+ if (m_context) {
+ m_nextExpression = m_context->expressions;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = &m_nextExpression;
+ m_prevExpression = &context->expressions;
+ m_context->expressions = this;
+ }
+}
+
+void QDeclarativeAbstractExpression::refresh()
+{
+}
+
+bool QDeclarativeAbstractExpression::isValid() const
+{
+ return m_context != 0;
+}
+
+QT_END_NAMESPACE
+
+#include <moc_qdeclarativeexpression.cpp>
diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h
new file mode 100644
index 0000000000..d40094b669
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeexpression.h
@@ -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 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 QDECLARATIVEEXPRESSION_H
+#define QDECLARATIVEEXPRESSION_H
+
+#include <QtDeclarative/qdeclarativeerror.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QString;
+class QDeclarativeRefCount;
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeExpressionPrivate;
+class QDeclarativeContextData;
+class QScriptValue;
+class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeExpression();
+ QDeclarativeExpression(QDeclarativeContext *, QObject *, const QString &, QObject * = 0);
+ virtual ~QDeclarativeExpression();
+
+ QDeclarativeEngine *engine() const;
+ QDeclarativeContext *context() const;
+
+ QString expression() const;
+ void setExpression(const QString &);
+
+ bool notifyOnValueChanged() const;
+ void setNotifyOnValueChanged(bool);
+
+ QString sourceFile() const;
+ int lineNumber() const;
+ void setSourceLocation(const QString &fileName, int line);
+
+ QObject *scopeObject() const;
+
+ bool hasError() const;
+ void clearError();
+ QDeclarativeError error() const;
+
+ QVariant evaluate(bool *valueIsUndefined = 0);
+
+Q_SIGNALS:
+ void valueChanged();
+
+protected:
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &,
+ QDeclarativeExpressionPrivate &dd);
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QScriptValue &,
+ QDeclarativeExpressionPrivate &dd);
+ QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc,
+ QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd);
+
+private:
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &);
+
+ Q_DISABLE_COPY(QDeclarativeExpression)
+ Q_DECLARE_PRIVATE(QDeclarativeExpression)
+ Q_PRIVATE_SLOT(d_func(), void _q_notify())
+ friend class QDeclarativeDebugger;
+ friend class QDeclarativeContext;
+ friend class QDeclarativeVME;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEEXPRESSION_H
+
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
new file mode 100644
index 0000000000..51cae0f9d4
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEEXPRESSION_P_H
+#define QDECLARATIVEEXPRESSION_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 "qdeclarativeexpression.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+#include <QtScript/qscriptvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAbstractExpression
+{
+public:
+ QDeclarativeAbstractExpression();
+ virtual ~QDeclarativeAbstractExpression();
+
+ bool isValid() const;
+
+ QDeclarativeContextData *context() const;
+ void setContext(QDeclarativeContextData *);
+
+ virtual void refresh();
+
+private:
+ friend class QDeclarativeContext;
+ friend class QDeclarativeContextData;
+ friend class QDeclarativeContextPrivate;
+ QDeclarativeContextData *m_context;
+ QDeclarativeAbstractExpression **m_prevExpression;
+ QDeclarativeAbstractExpression *m_nextExpression;
+};
+
+class QDeclarativeDelayedError
+{
+public:
+ inline QDeclarativeDelayedError() : nextError(0), prevError(0) {}
+ inline ~QDeclarativeDelayedError() { removeError(); }
+
+ QDeclarativeError error;
+
+ bool addError(QDeclarativeEnginePrivate *);
+
+ inline void removeError() {
+ if (!prevError) return;
+ if (nextError) nextError->prevError = prevError;
+ *prevError = nextError;
+ nextError = 0;
+ prevError = 0;
+ }
+
+private:
+ QDeclarativeDelayedError *nextError;
+ QDeclarativeDelayedError **prevError;
+};
+
+class QDeclarativeQtScriptExpression : public QDeclarativeAbstractExpression,
+ public QDeclarativeDelayedError
+{
+public:
+ enum Mode { SharedContext, ExplicitContext };
+
+ enum EvaluateFlag { RequiresThisObject = 0x01 };
+ Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag)
+
+ QDeclarativeQtScriptExpression();
+ virtual ~QDeclarativeQtScriptExpression();
+
+ QDeclarativeRefCount *dataRef;
+
+ QString expression;
+
+ Mode expressionFunctionMode;
+ QScriptValue expressionFunction;
+
+ QScriptValue expressionContext; // Only used in ExplicitContext
+ QObject *scopeObject; // Only used in SharedContext
+
+ bool notifyOnValueChange() const;
+ void setNotifyOnValueChange(bool);
+ void resetNotifyOnChange();
+ void setNotifyObject(QObject *, int );
+
+ void setEvaluateFlags(EvaluateFlags flags);
+ EvaluateFlags evaluateFlags() const;
+
+ QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined);
+
+ class DeleteWatcher {
+ public:
+ inline DeleteWatcher(QDeclarativeQtScriptExpression *data);
+ inline ~DeleteWatcher();
+ inline bool wasDeleted() const;
+ private:
+ bool *m_wasDeleted;
+ bool m_wasDeletedStorage;
+ QDeclarativeQtScriptExpression *m_d;
+ };
+
+private:
+ void clearGuards();
+ QScriptValue eval(QObject *secondaryScope, bool *isUndefined);
+ void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
+
+ bool trackChange;
+
+ QDeclarativeNotifierEndpoint *guardList;
+ int guardListLength;
+
+ QObject *guardObject;
+ int guardObjectNotifyIndex;
+ bool *deleted;
+
+ EvaluateFlags evalFlags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeQtScriptExpression::EvaluateFlags)
+
+
+class QDeclarativeExpression;
+class QString;
+class QDeclarativeExpressionPrivate : public QObjectPrivate, public QDeclarativeQtScriptExpression
+{
+ Q_DECLARE_PUBLIC(QDeclarativeExpression)
+public:
+ QDeclarativeExpressionPrivate();
+ ~QDeclarativeExpressionPrivate();
+
+ void init(QDeclarativeContextData *, const QString &, QObject *);
+ void init(QDeclarativeContextData *, const QScriptValue &, QObject *);
+ void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int);
+
+ QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
+ QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) {
+ return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
+ }
+ static QDeclarativeExpression *get(QDeclarativeExpressionPrivate *expr) {
+ return expr->q_func();
+ }
+
+ void _q_notify();
+ virtual void emitValueChanged();
+
+ static void exceptionToError(QScriptEngine *, QDeclarativeError &);
+ static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, const QString &,
+ int, QScriptValue *);
+ static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &,
+ QScriptValue *);
+
+ bool expressionFunctionValid:1;
+
+ QString url; // This is a QString for a reason. QUrls are slooooooow...
+ int line;
+ QByteArray name; //function name, hint for the debugger
+};
+
+QDeclarativeQtScriptExpression::DeleteWatcher::DeleteWatcher(QDeclarativeQtScriptExpression *data)
+: m_wasDeletedStorage(false), m_d(data)
+{
+ if (!m_d->deleted)
+ m_d->deleted = &m_wasDeletedStorage;
+ m_wasDeleted = m_d->deleted;
+}
+
+QDeclarativeQtScriptExpression::DeleteWatcher::~DeleteWatcher()
+{
+ if (false == *m_wasDeleted && m_wasDeleted == m_d->deleted)
+ m_d->deleted = 0;
+}
+
+bool QDeclarativeQtScriptExpression::DeleteWatcher::wasDeleted() const
+{
+ return *m_wasDeleted;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEEXPRESSION_P_H
diff --git a/src/declarative/qml/qdeclarativeextensioninterface.h b/src/declarative/qml/qdeclarativeextensioninterface.h
new file mode 100644
index 0000000000..fdf76106aa
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeextensioninterface.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 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 QDECLARATIVEEXTENSIONINTERFACE_H
+#define QDECLARATIVEEXTENSIONINTERFACE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+
+struct Q_DECLARATIVE_EXPORT QDeclarativeExtensionInterface
+{
+ virtual ~QDeclarativeExtensionInterface() {}
+ virtual void registerTypes(const char *uri) = 0;
+ virtual void initializeEngine(QDeclarativeEngine *engine, const char *uri) = 0;
+};
+
+Q_DECLARE_INTERFACE(QDeclarativeExtensionInterface, "com.trolltech.Qt.QDeclarativeExtensionInterface/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEEXTENSIONINTERFACE_H
diff --git a/src/declarative/qml/qdeclarativeextensionplugin.cpp b/src/declarative/qml/qdeclarativeextensionplugin.cpp
new file mode 100644
index 0000000000..8e1af5dbf1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeextensionplugin.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeextensionplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 4.7
+ \class QDeclarativeExtensionPlugin
+ \brief The QDeclarativeExtensionPlugin class provides an abstract base for custom QML extension plugins.
+
+ \ingroup plugins
+
+ QDeclarativeExtensionPlugin is a plugin interface that makes it possible to
+ create QML extensions that can be loaded dynamically into QML applications.
+ These extensions allow custom QML types to be made available to the QML engine.
+
+ To write a QML extension plugin:
+
+ \list
+ \o Subclass QDeclarativeExtensionPlugin, implement registerTypes() method
+ to register types using qmlRegisterType(), and export the class using the Q_EXPORT_PLUGIN2() macro
+ \o Write an appropriate project file for the plugin
+ \o Create a \l{Writing a qmldir file}{qmldir file} to describe the plugin
+ \endlist
+
+ QML extension plugins can be used to provide either application-specific or
+ library-like plugins. Library plugins should limit themselves to registering types,
+ as any manipulation of the engine's root context may cause conflicts
+ or other issues in the library user's code.
+
+
+ \section1 An example
+
+ Suppose there is a new \c TimeModel C++ class that should be made available
+ as a new QML element. It provides the current time through \c hour and \c minute
+ properties, like this:
+
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp 0
+ \dots
+
+ To make this class available as a QML type, create a plugin that registers
+ this type with a specific \l {QML Modules}{module} using qmlRegisterType(). For this example the plugin
+ module will be named \c com.nokia.TimeExample (as defined in the project
+ file further below).
+
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp plugin
+ \codeline
+ \snippet examples/declarative/cppextensions/plugins/plugin.cpp export
+
+ This registers the \c TimeModel class with the 1.0 version of this
+ plugin library, as a QML type called \c Time. The Q_ASSERT statement
+ ensures the module is imported correctly by any QML components that use this plugin.
+
+ The project file defines the project as a plugin library and specifies
+ it should be built into the \c com/nokia/TimeExample directory:
+
+ \code
+ TEMPLATE = lib
+ CONFIG += qt plugin
+ QT += declarative
+
+ DESTDIR = com/nokia/TimeExample
+ TARGET = qmlqtimeexampleplugin
+ ...
+ \endcode
+
+ Finally, a \l{Writing a qmldir file}{qmldir file} is required in the \c com/nokia/TimeExample directory
+ that describes the plugin. This directory includes a \c Clock.qml file that
+ should be bundled with the plugin, so it needs to be specified in the \c qmldir
+ file:
+
+ \quotefile examples/declarative/cppextensions/plugins/com/nokia/TimeExample/qmldir
+
+ Once the project is built and installed, the new \c Time element can be
+ used by any QML component that imports the \c com.nokia.TimeExample module:
+
+ \snippet examples/declarative/cppextensions/plugins/plugins.qml 0
+
+ The full source code is available in the \l {declarative/cppextensions/plugins}{plugins example}.
+
+ The \l {Tutorial: Writing QML extensions with C++} also contains a chapter
+ on creating QML plugins.
+
+ \sa QDeclarativeEngine::importPlugin(), {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn void QDeclarativeExtensionPlugin::registerTypes(const char *uri)
+
+ Registers the QML types in the given \a uri. Subclasses should implement
+ this to call qmlRegisterType() for all types which are provided by the extension
+ plugin.
+
+ The \a uri is an identifier for the plugin generated by the QML engine
+ based on the name and path of the extension's plugin library.
+*/
+
+/*!
+ Constructs a QML extension plugin with the given \a parent.
+
+ Note that this constructor is invoked automatically by the
+ Q_EXPORT_PLUGIN2() macro, so there is no need for calling it
+ explicitly.
+*/
+QDeclarativeExtensionPlugin::QDeclarativeExtensionPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \internal
+ */
+QDeclarativeExtensionPlugin::~QDeclarativeExtensionPlugin()
+{
+}
+
+/*!
+ \fn void QDeclarativeExtensionPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+*/
+
+void QDeclarativeExtensionPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeextensionplugin.h b/src/declarative/qml/qdeclarativeextensionplugin.h
new file mode 100644
index 0000000000..4513ff0c6e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeextensionplugin.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEEXTENSIONPLUGIN_H
+#define QDECLARATIVEEXTENSIONPLUGIN_H
+
+#include <QtCore/qplugin.h>
+
+#include <QtDeclarative/qdeclarativeextensioninterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+
+class Q_DECLARATIVE_EXPORT QDeclarativeExtensionPlugin : public QObject, public QDeclarativeExtensionInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeExtensionInterface)
+public:
+ explicit QDeclarativeExtensionPlugin(QObject *parent = 0);
+ ~QDeclarativeExtensionPlugin();
+
+ virtual void registerTypes(const char *uri) = 0;
+ virtual void initializeEngine(QDeclarativeEngine *engine, const char *uri);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeExtensionPlugin)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEEXTENSIONPLUGIN_H
diff --git a/src/declarative/qml/qdeclarativefastproperties.cpp b/src/declarative/qml/qdeclarativefastproperties.cpp
new file mode 100644
index 0000000000..cf4f075997
--- /dev/null
+++ b/src/declarative/qml/qdeclarativefastproperties.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativefastproperties_p.h"
+
+#include <private/qdeclarativeitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Adding entries to the QDeclarativeFastProperties class allows the QML
+// binding optimizer to bypass Qt's meta system and read and, more
+// importantly, subscribe to properties directly. Any property that is
+// primarily read from bindings is a candidate for inclusion as a fast
+// property.
+
+static void QObject_objectName(QObject *object, void *output, QDeclarativeNotifierEndpoint *endpoint)
+{
+ if (endpoint)
+ endpoint->connect(QDeclarativeData::get(object, true)->objectNameNotifier());
+ *((QString *)output) = object->objectName();
+}
+
+QDeclarativeFastProperties::QDeclarativeFastProperties()
+{
+ add(&QDeclarativeItem::staticMetaObject, QDeclarativeItem::staticMetaObject.indexOfProperty("parent"),
+ QDeclarativeItemPrivate::parentProperty);
+ add(&QObject::staticMetaObject, QObject::staticMetaObject.indexOfProperty("objectName"),
+ QObject_objectName);
+}
+
+int QDeclarativeFastProperties::accessorIndexForProperty(const QMetaObject *metaObject, int propertyIndex)
+{
+ Q_ASSERT(metaObject);
+ Q_ASSERT(propertyIndex >= 0);
+
+ // Find the "real" metaObject
+ while (metaObject->propertyOffset() > propertyIndex)
+ metaObject = metaObject->superClass();
+
+ QHash<QPair<const QMetaObject *, int>, int>::Iterator iter =
+ m_index.find(qMakePair(metaObject, propertyIndex));
+ if (iter != m_index.end())
+ return *iter;
+ else
+ return -1;
+}
+
+void QDeclarativeFastProperties::add(const QMetaObject *metaObject, int propertyIndex, Accessor accessor)
+{
+ Q_ASSERT(metaObject);
+ Q_ASSERT(propertyIndex >= 0);
+
+ // Find the "real" metaObject
+ while (metaObject->propertyOffset() > propertyIndex)
+ metaObject = metaObject->superClass();
+
+ QPair<const QMetaObject *, int> data = qMakePair(metaObject, propertyIndex);
+ int accessorIndex = m_accessors.count();
+ m_accessors.append(accessor);
+ m_index.insert(data, accessorIndex);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativefastproperties_p.h b/src/declarative/qml/qdeclarativefastproperties_p.h
new file mode 100644
index 0000000000..211e082e4b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativefastproperties_p.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 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 QDECLARATIVEFASTPROPERTIES_P_H
+#define QDECLARATIVEFASTPROPERTIES_P_H
+
+#include <QtCore/qvector.h>
+#include <QtCore/qhash.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QDeclarativeNotifierEndpoint;
+class QDeclarativeFastProperties
+{
+public:
+ typedef void (*Accessor)(QObject *object, void *output, QDeclarativeNotifierEndpoint *endpoint);
+
+ QDeclarativeFastProperties();
+
+ Accessor accessor(int index) const { return m_accessors.at(index); }
+ int accessorIndexForProperty(const QMetaObject *, int);
+
+private:
+ void add(const QMetaObject *, int, Accessor);
+
+ QHash<QPair<const QMetaObject *, int>, int> m_index;
+ QVector<Accessor> m_accessors;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFASTPROPERTIES_P_H
diff --git a/src/declarative/qml/qdeclarativeglobal_p.h b/src/declarative/qml/qdeclarativeglobal_p.h
new file mode 100644
index 0000000000..6d195c73c0
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeglobal_p.h
@@ -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 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 QDECLARATIVEGLOBAL_H
+#define QDECLARATIVEGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+#define DEFINE_BOOL_CONFIG_OPTION(name, var) \
+ static bool name() \
+ { \
+ static enum { Yes, No, Unknown } status = Unknown; \
+ if (status == Unknown) { \
+ QByteArray v = qgetenv(#var); \
+ bool value = !v.isEmpty() && v != "0" && v != "false"; \
+ if (value) status = Yes; \
+ else status = No; \
+ } \
+ return status == Yes; \
+ }
+
+#ifdef Q_OS_SYMBIAN
+#define Q_DECLARATIVE_PRIVATE_EXPORT Q_AUTOTEST_EXPORT
+#else
+#define Q_DECLARATIVE_PRIVATE_EXPORT Q_DECLARATIVE_EXPORT
+#endif
+
+struct QDeclarativeGraphics_DerivedObject : public QObject
+{
+ void setParent_noEvent(QObject *parent) {
+ bool sce = d_ptr->sendChildEvents;
+ d_ptr->sendChildEvents = false;
+ setParent(parent);
+ d_ptr->sendChildEvents = sce;
+ }
+};
+
+/*!
+ Returns true if the case of \a fileName is equivalent to the file case of
+ \a fileName on disk, and false otherwise.
+
+ This is used to ensure that the behavior of QML on a case-insensitive file
+ system is the same as on a case-sensitive file system. This function
+ performs a "best effort" attempt to determine the real case of the file.
+ It may have false positives (say the case is correct when it isn't), but it
+ should never have a false negative (say the case is incorrect when it is
+ correct).
+*/
+bool QDeclarative_isFileCaseCorrect(const QString &fileName);
+
+/*!
+ Makes the \a object a child of \a parent. Note that when using this method,
+ neither \a parent nor the object's previous parent (if it had one) will
+ receive ChildRemoved or ChildAdded events.
+*/
+inline void QDeclarative_setParent_noEvent(QObject *object, QObject *parent)
+{
+ static_cast<QDeclarativeGraphics_DerivedObject *>(object)->setParent_noEvent(parent);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEGLOBAL_H
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
new file mode 100644
index 0000000000..4bdfdd9b9e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeglobalscriptclass_p.h"
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvector.h>
+#include <QtScript/qscriptstring.h>
+#include <QtScript/qscriptengine.h>
+#include <QtScript/qscriptvalueiterator.h>
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Used to prevent any writes to the global object.
+*/
+QDeclarativeGlobalScriptClass::QDeclarativeGlobalScriptClass(QScriptEngine *engine)
+: QScriptClass(engine)
+{
+ QString eval = QLatin1String("eval");
+ QString version = QLatin1String("version");
+
+ QScriptValue originalGlobalObject = engine->globalObject();
+
+ QScriptValue newGlobalObject = engine->newObject();
+
+ {
+ QScriptValueIterator iter(originalGlobalObject);
+ QVector<QString> names;
+ QVector<QScriptValue> values;
+ QVector<QScriptValue::PropertyFlags> flags;
+ while (iter.hasNext()) {
+ iter.next();
+
+ QString name = iter.name();
+
+ if (name == version)
+ continue;
+
+ if (name != eval) {
+ names.append(name);
+ values.append(iter.value());
+ flags.append(iter.flags() | QScriptValue::Undeletable);
+ }
+ newGlobalObject.setProperty(iter.scriptName(), iter.value());
+
+ m_illegalNames.insert(name);
+ }
+ m_staticGlobalObject = QScriptDeclarativeClass::newStaticScopeObject(
+ engine, names.size(), names.constData(), values.constData(), flags.constData());
+ }
+
+ newGlobalObject.setScriptClass(this);
+ engine->setGlobalObject(newGlobalObject);
+}
+
+QScriptClass::QueryFlags
+QDeclarativeGlobalScriptClass::queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(name);
+ Q_UNUSED(flags);
+ Q_UNUSED(id);
+ return HandlesWriteAccess;
+}
+
+void QDeclarativeGlobalScriptClass::setProperty(QScriptValue &object,
+ const QScriptString &name,
+ uint id, const QScriptValue &value)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(id);
+ Q_UNUSED(value);
+ QString error = QLatin1String("Invalid write to global property \"") +
+ name.toString() + QLatin1Char('\"');
+ engine()->currentContext()->throwError(error);
+}
+
+/* This method is for the use of tst_qdeclarativeecmascript::callQtInvokables() only */
+void QDeclarativeGlobalScriptClass::explicitSetProperty(const QStringList &names, const QList<QScriptValue> &values)
+{
+ Q_ASSERT(names.count() == values.count());
+ QScriptValue globalObject = engine()->globalObject();
+
+ QScriptValue v = engine()->newObject();
+
+ QScriptValueIterator iter(v);
+ while (iter.hasNext()) {
+ iter.next();
+ v.setProperty(iter.scriptName(), iter.value());
+ }
+
+ for (int ii = 0; ii < names.count(); ++ii) {
+ const QString &name = names.at(ii);
+ const QScriptValue &value = values.at(ii);
+ v.setProperty(name, value);
+ }
+
+ v.setScriptClass(this);
+
+ engine()->setGlobalObject(v);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
new file mode 100644
index 0000000000..01cfb6ecac
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeglobalscriptclass_p.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 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 QDECLARATIVEGLOBALSCRIPTCLASS_P_H
+#define QDECLARATIVEGLOBALSCRIPTCLASS_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 <QtScript/qscriptclass.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QDeclarativeGlobalScriptClass : public QScriptClass
+{
+public:
+ QDeclarativeGlobalScriptClass(QScriptEngine *);
+
+ virtual QueryFlags queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags, uint *id);
+
+ virtual void setProperty(QScriptValue &object, const QScriptString &name,
+ uint id, const QScriptValue &value);
+
+ void explicitSetProperty(const QStringList &, const QList<QScriptValue> &);
+
+ const QScriptValue &staticGlobalObject() const { return m_staticGlobalObject; }
+
+ const QSet<QString> &illegalNames() const { return m_illegalNames; }
+
+private:
+ QSet<QString> m_illegalNames;
+ QScriptValue m_staticGlobalObject;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEGLOBALSCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativeguard_p.h b/src/declarative/qml/qdeclarativeguard_p.h
new file mode 100644
index 0000000000..991c7810bc
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeguard_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt 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 QDECLARATIVEGUARD_P_H
+#define QDECLARATIVEGUARD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+template<class T>
+class QDeclarativeGuard
+{
+ QObject *o;
+ QDeclarativeGuard<QObject> *next;
+ QDeclarativeGuard<QObject> **prev;
+ friend class QDeclarativeData;
+public:
+ inline QDeclarativeGuard();
+ inline QDeclarativeGuard(T *);
+ inline QDeclarativeGuard(const QDeclarativeGuard<T> &);
+ inline virtual ~QDeclarativeGuard();
+
+ inline QDeclarativeGuard<T> &operator=(const QDeclarativeGuard<T> &o);
+ inline QDeclarativeGuard<T> &operator=(T *);
+
+ inline bool isNull() const
+ { return !o; }
+
+ inline T* operator->() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T& operator*() const
+ { return *static_cast<T*>(const_cast<QObject*>(o)); }
+ inline operator T*() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T* data() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+
+protected:
+ virtual void objectDestroyed(T *) {}
+
+private:
+ inline void addGuard();
+ inline void remGuard();
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeGuard<QObject>)
+
+#include "private/qdeclarativedata_p.h"
+
+QT_BEGIN_NAMESPACE
+
+template<class T>
+QDeclarativeGuard<T>::QDeclarativeGuard()
+: o(0), next(0), prev(0)
+{
+}
+
+template<class T>
+QDeclarativeGuard<T>::QDeclarativeGuard(T *g)
+: o(g), next(0), prev(0)
+{
+ if (o) addGuard();
+}
+
+template<class T>
+QDeclarativeGuard<T>::QDeclarativeGuard(const QDeclarativeGuard<T> &g)
+: o(g.o), next(0), prev(0)
+{
+ if (o) addGuard();
+}
+
+template<class T>
+QDeclarativeGuard<T>::~QDeclarativeGuard()
+{
+ if (prev) remGuard();
+ o = 0;
+}
+
+template<class T>
+QDeclarativeGuard<T> &QDeclarativeGuard<T>::operator=(const QDeclarativeGuard<T> &g)
+{
+ if (g.o != o) {
+ if (prev) remGuard();
+ o = g.o;
+ if (o) addGuard();
+ }
+ return *this;
+}
+
+template<class T>
+QDeclarativeGuard<T> &QDeclarativeGuard<T>::operator=(T *g)
+{
+ if (g != o) {
+ if (prev) remGuard();
+ o = g;
+ if (o) addGuard();
+ }
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEGUARD_P_H
diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp
new file mode 100644
index 0000000000..f111c201fa
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeimageprovider.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeimageprovider.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeImageProviderPrivate
+{
+public:
+ QDeclarativeImageProvider::ImageType type;
+};
+
+/*!
+ \class QDeclarativeImageProvider
+ \since 4.7
+ \brief The QDeclarativeImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
+
+ QDeclarativeImageProvider is used to provide advanced image loading features
+ in QML applications. It allows images in QML to be:
+
+ \list
+ \o Loaded using QPixmaps rather than actual image files
+ \o Loaded asynchronously in a separate thread, if imageType() is \l{QDeclarativeImageProvider::ImageType}{ImageType::Image}
+ \endlist
+
+ To specify that an image should be loaded by an image provider, use the
+ \bold {"image:"} scheme for the URL source of the image, followed by the
+ identifiers of the image provider and the requested image. For example:
+
+ \qml
+ Image { source: "image://myimageprovider/image.png" }
+ \endqml
+
+ This specifies that the image should be loaded by the image provider named
+ "myimageprovider", and the image to be loaded is named "image.png". The QML engine
+ invokes the appropriate image provider according to the providers that have
+ been registered through QDeclarativeEngine::addImageProvider().
+
+ Note that the identifiers are case-insensitive, but the rest of the URL will be passed on with
+ preserved case. For example, the below snippet would still specify that the image is loaded by the
+ image provider named "myimageprovider", but it would request a different image than the above snippet
+ ("Image.png" instead of "image.png").
+ \qml
+ Image { source: "image://MyImageProvider/Image.png" }
+ \endqml
+
+ If you want the rest of the URL to be case insensitive, you will have to take care
+ of that yourself inside your image provider.
+
+ \section2 An example
+
+ Here are two images. Their \c source values indicate they should be loaded by
+ an image provider named "colors", and the images to be loaded are "yellow"
+ and "red", respectively:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0
+
+ When these images are loaded by QML, it looks for a matching image provider
+ and calls its requestImage() or requestPixmap() method (depending on its
+ imageType()) to load the image. The method is called with the \c id
+ parameter set to "yellow" for the first image, and "red" for the second.
+
+ Here is an image provider implementation that can load the images
+ requested by the above QML. This implementation dynamically
+ generates QPixmap images that are filled with the requested color:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0
+ \codeline
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 1
+
+ To make this provider accessible to QML, it is registered with the QML engine
+ with a "colors" identifier:
+
+ \code
+ int main(int argc, char *argv[])
+ {
+ ...
+
+ QDeclarativeEngine engine;
+ engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider);
+
+ ...
+ }
+ \endcode
+
+ Now the images can be successfully loaded in QML:
+
+ \image imageprovider.png
+
+ A complete example is available in Qt's
+ \l {declarative/cppextensions/imageprovider}{examples/declarative/cppextensions/imageprovider}
+ directory. Note the example registers the provider via a \l{QDeclarativeExtensionPlugin}{plugin}
+ instead of registering it in the application \c main() function as shown above.
+
+
+ \section2 Asynchronous image loading
+
+ Image providers that support QImage loading automatically include support
+ for asychronous loading of images. To enable asynchronous loading for an
+ \l Image source, set \l Image::asynchronous to \c true. When this is enabled,
+ the image request to the provider is run in a low priority thread,
+ allowing image loading to be executed in the background, and reducing the
+ performance impact on the user interface.
+
+ Asynchronous loading is not supported for image providers that provide
+ QPixmap rather than QImage values, as pixmaps can only be created in the
+ main thread. In this case, if \l {Image::}{asynchronous} is set to
+ \c true, the value is ignored and the image is loaded
+ synchronously.
+
+ \sa QDeclarativeEngine::addImageProvider()
+*/
+
+/*!
+ \enum QDeclarativeImageProvider::ImageType
+
+ Defines the type of image supported by this image provider.
+
+ \value Image The Image Provider provides QImage images. The
+ 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.
+*/
+
+/*!
+ Creates an image provider that will provide images of the given \a type.
+*/
+QDeclarativeImageProvider::QDeclarativeImageProvider(ImageType type)
+ : d(new QDeclarativeImageProviderPrivate)
+{
+ d->type = type;
+}
+
+/*!
+ Destroys the QDeclarativeImageProvider
+
+ \note The destructor of your derived class need to be thread safe.
+*/
+QDeclarativeImageProvider::~QDeclarativeImageProvider()
+{
+ delete d;
+}
+
+/*!
+ Returns the image type supported by this provider.
+*/
+QDeclarativeImageProvider::ImageType QDeclarativeImageProvider::imageType() const
+{
+ return d->type;
+}
+
+/*!
+ Implement this method to return the image with \a id. The default
+ implementation returns an empty image.
+
+ 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.
+*/
+QImage QDeclarativeImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Image)
+ qWarning("ImageProvider supports Image type but has not implemented requestImage()");
+ return QImage();
+}
+
+/*!
+ Implement this method to return the pixmap with \a id. The default
+ implementation returns an empty pixmap.
+
+ 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.
+*/
+QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Pixmap)
+ qWarning("ImageProvider supports Pixmap type but has not implemented requestPixmap()");
+ return QPixmap();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h
new file mode 100644
index 0000000000..7f13fda85b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeimageprovider.h
@@ -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 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 QDECLARATIVEIMAGEPROVIDER_H
+#define QDECLARATIVEIMAGEPROVIDER_H
+
+#include <QtGui/qimage.h>
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeImageProviderPrivate;
+
+class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider
+{
+public:
+ enum ImageType {
+ Image,
+ Pixmap
+ };
+
+ QDeclarativeImageProvider(ImageType type);
+ virtual ~QDeclarativeImageProvider();
+
+ ImageType imageType() const;
+
+ virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+
+private:
+ QDeclarativeImageProviderPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEIMAGEPROVIDER
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp
new file mode 100644
index 0000000000..e8d593fd1a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeimport.cpp
@@ -0,0 +1,1079 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeimport_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qpluginloader.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtDeclarative/qdeclarativeextensioninterface.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativetypenamecache_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+#ifdef Q_OS_SYMBIAN
+#include "private/qcore_symbian_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
+
+static bool greaterThan(const QString &s1, const QString &s2)
+{
+ return s1 > s2;
+}
+
+typedef QMap<QString, QString> StringStringMap;
+Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
+
+class QDeclarativeImportedNamespace
+{
+public:
+ QStringList uris;
+ QStringList urls;
+ QList<int> majversions;
+ QList<int> minversions;
+ QList<bool> isLibrary;
+ QList<QDeclarativeDirComponents> qmlDirComponents;
+
+
+ bool find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
+ 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);
+};
+
+class QDeclarativeImportsPrivate {
+public:
+ QDeclarativeImportsPrivate();
+ ~QDeclarativeImportsPrivate();
+
+ bool importExtension(const QString &absoluteFilePath, const QString &uri,
+ QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components,
+ QString *errorString);
+
+ 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);
+ bool find(const QByteArray& type, int *vmajor, int *vminor,
+ QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
+
+ QDeclarativeImportedNamespace *findNamespace(const QString& type);
+
+ QUrl base;
+ int ref;
+
+ QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
+ QDeclarativeImportedNamespace unqualifiedset;
+ QHash<QString,QDeclarativeImportedNamespace* > set;
+};
+
+/*!
+\class QDeclarativeImports
+\brief The QDeclarativeImports class encapsulates one QML document's import statements.
+\internal
+*/
+QDeclarativeImports::QDeclarativeImports(const QDeclarativeImports &copy)
+: d(copy.d)
+{
+ ++d->ref;
+}
+
+QDeclarativeImports &
+QDeclarativeImports::operator =(const QDeclarativeImports &copy)
+{
+ ++copy.d->ref;
+ if (--d->ref == 0)
+ delete d;
+ d = copy.d;
+ return *this;
+}
+
+QDeclarativeImports::QDeclarativeImports()
+: d(new QDeclarativeImportsPrivate)
+{
+}
+
+QDeclarativeImports::~QDeclarativeImports()
+{
+ if (--d->ref == 0)
+ delete d;
+}
+
+/*!
+ Sets the base URL to be used for all relative file imports added.
+*/
+void QDeclarativeImports::setBaseUrl(const QUrl& url)
+{
+ d->base = url;
+}
+
+/*!
+ Returns the base URL to be used for all relative file imports added.
+*/
+QUrl QDeclarativeImports::baseUrl() const
+{
+ return d->base;
+}
+
+static QDeclarativeTypeNameCache *
+cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set,
+ QDeclarativeTypeNameCache *cache)
+{
+ if (!cache)
+ cache = new QDeclarativeTypeNameCache(engine);
+
+ QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
+
+ for (int ii = 0; ii < set.uris.count(); ++ii) {
+ QByteArray base = set.uris.at(ii).toUtf8() + '/';
+ int major = set.majversions.at(ii);
+ int minor = set.minversions.at(ii);
+
+ foreach (QDeclarativeType *type, types) {
+ if (type->qmlTypeName().startsWith(base) &&
+ type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
+ type->availableInVersion(major,minor))
+ {
+ QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length()));
+
+ cache->add(name, type);
+ }
+ }
+ }
+
+ return cache;
+}
+
+void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const
+{
+ const QDeclarativeImportedNamespace &set = d->unqualifiedset;
+
+ for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin();
+ iter != d->set.end(); ++iter) {
+
+ QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
+ if (d) {
+ if (!d->typeNamespace)
+ cacheForNamespace(engine, *(*iter), d->typeNamespace);
+ } else {
+ QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
+ cache->add(iter.key(), nc);
+ nc->release();
+ }
+ }
+
+ cacheForNamespace(engine, set, cache);
+}
+
+/*!
+ \internal
+
+ The given (namespace qualified) \a type is resolved to either
+ \list
+ \o a QDeclarativeImportedNamespace stored at \a ns_return,
+ \o a QDeclarativeType stored at \a type_return, or
+ \o a component located at \a url_return.
+ \endlist
+
+ If any return pointer is 0, the corresponding search is not done.
+
+ \sa addImport()
+*/
+bool QDeclarativeImports::resolveType(const QByteArray& type,
+ QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
+ QDeclarativeImportedNamespace** ns_return, QString *errorString) const
+{
+ QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
+ if (ns) {
+ if (ns_return)
+ *ns_return = ns;
+ return true;
+ }
+ if (type_return || url_return) {
+ if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
+ if (qmlImportTrace()) {
+ if (type_return && *type_return && url_return && !url_return->isEmpty())
+ qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << (*type_return)->typeName() << " " << *url_return;
+ if (type_return && *type_return)
+ qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << (*type_return)->typeName();
+ if (url_return && !url_return->isEmpty())
+ qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: "
+ << type << " => " << *url_return;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Searching \e only in the namespace \a ns (previously returned in a call to
+ resolveType(), \a type is found and returned to either
+ a QDeclarativeType stored at \a type_return, or
+ a component located at \a url_return.
+
+ If either return pointer is 0, the corresponding search is not done.
+*/
+bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QByteArray& type,
+ QDeclarativeType** type_return, QUrl* url_return,
+ int *vmaj, int *vmin) const
+{
+ return ns->find(type,vmaj,vmin,type_return,url_return);
+}
+
+bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
+ QDeclarativeType** type_return, QUrl* url_return,
+ QUrl *base, bool *typeRecursionDetected)
+{
+ int vmaj = majversions.at(i);
+ int vmin = minversions.at(i);
+
+ QByteArray qt = uris.at(i).toUtf8();
+ qt += '/';
+ qt += type;
+
+ QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
+ if (t) {
+ if (vmajor) *vmajor = vmaj;
+ if (vminor) *vminor = vmin;
+ if (type_return)
+ *type_return = t;
+ return true;
+ }
+
+ QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
+ QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
+
+ bool typeWasDeclaredInQmldir = false;
+ if (!qmldircomponents.isEmpty()) {
+ const QString typeName = QString::fromUtf8(type);
+ foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
+ if (c.typeName == typeName) {
+ typeWasDeclaredInQmldir = true;
+
+ // importing version -1 means import ALL versions
+ if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) {
+ QUrl candidate = url.resolved(QUrl(c.fileName));
+ if (c.internal && base) {
+ if (base->resolved(QUrl(c.fileName)) != candidate)
+ continue; // failed attempt to access an internal type
+ }
+ if (base && *base == candidate) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
+ if (url_return)
+ *url_return = candidate;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (!typeWasDeclaredInQmldir && !isLibrary.at(i)) {
+ // XXX search non-files too! (eg. zip files, see QT-524)
+ QFileInfo f(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url));
+ if (f.exists()) {
+ if (base && *base == url) { // no recursion
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ } else {
+ if (url_return)
+ *url_return = url;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+QDeclarativeImportsPrivate::QDeclarativeImportsPrivate()
+: ref(1)
+{
+}
+
+QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
+{
+ foreach (QDeclarativeImportedNamespace* s, set.values())
+ delete s;
+}
+
+bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
+ QDeclarativeImportDatabase *database,
+ QDeclarativeDirComponents* components, QString *errorString)
+{
+ 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);
+ return false;
+ } else if (file.open(QFile::ReadOnly)) {
+ filecontent = QString::fromUtf8(file.readAll());
+ if (qmlImportTrace())
+ 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);
+ return false;
+ }
+ QDir dir = QFileInfo(file).dir();
+
+ QDeclarativeDirParser qmldirParser;
+ qmldirParser.setSource(filecontent);
+ qmldirParser.parse();
+
+ if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
+ qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
+
+
+ foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) {
+
+ QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name);
+#if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN)
+ if (resolvedFilePath.isEmpty()) {
+ // In case of libinfixed build, attempt to load libinfixed version, too.
+ QString infixedPluginName = plugin.name + QLatin1String(QT_LIBINFIX);
+ resolvedFilePath = database->resolvePlugin(dir, plugin.path, infixedPluginName);
+ }
+#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);
+ return false;
+ }
+ } else {
+ if (errorString)
+ *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
+ return false;
+ }
+ }
+ }
+
+ if (components)
+ *components = qmldirParser.components();
+
+ return true;
+}
+
+QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database)
+{
+ QString dir = dir_arg;
+ if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\')))
+ dir.chop(1);
+
+ QStringList paths = database->fileImportPath;
+ qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents.
+
+ QString stableRelativePath = dir;
+ foreach(const QString &path, paths) {
+ if (dir.startsWith(path)) {
+ stableRelativePath = dir.mid(path.length()+1);
+ break;
+ }
+ }
+
+ stableRelativePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ // remove optional versioning in dot notation from uri
+ int lastSlash = stableRelativePath.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash >= 0) {
+ int versionDot = stableRelativePath.indexOf(QLatin1Char('.'), lastSlash);
+ if (versionDot >= 0)
+ stableRelativePath = stableRelativePath.left(versionDot);
+ }
+
+ stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.'));
+ return stableRelativePath;
+}
+
+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)
+{
+ QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
+ QString uri = uri_arg;
+ QDeclarativeImportedNamespace *s;
+ if (prefix.isEmpty()) {
+ s = &unqualifiedset;
+ } else {
+ s = set.value(prefix);
+ if (!s)
+ set.insert(prefix,(s=new QDeclarativeImportedNamespace));
+ }
+
+ QString url = uri;
+ bool versionFound = false;
+ if (importType == QDeclarativeScriptParser::Import::Library) {
+ url.replace(QLatin1Char('.'), QLatin1Char('/'));
+ bool found = false;
+ QString dir;
+
+
+ // step 1: search for extension with fully encoded version number
+ if (vmaj >= 0 && vmin >= 0) {
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+QLatin1Char('/')+url;
+
+ QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
+
+ if (fi.isFile()) {
+ found = true;
+
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ return false;
+ break;
+ }
+ }
+ }
+ // step 2: search for extension with encoded version major
+ if (vmaj >= 0 && vmin >= 0) {
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+QLatin1Char('/')+url;
+
+ QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
+
+ if (fi.isFile()) {
+ found = true;
+
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ return false;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ // step 3: search for extension without version number
+
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+QLatin1Char('/')+url;
+
+ QFileInfo fi(dir+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
+
+ if (fi.isFile()) {
+ found = true;
+
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+ return false;
+ break;
+ }
+ }
+ }
+
+ if (QDeclarativeMetaType::isModule(uri.toUtf8(), vmaj, vmin))
+ versionFound = true;
+
+ if (!versionFound && qmldircomponents.isEmpty()) {
+ if (errorString) {
+ bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
+ if (anyversion)
+ *errorString = 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);
+ }
+ return false;
+ }
+ } else {
+
+ if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) {
+ QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir")));
+ QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl);
+ if (!localFileOrQrc.isEmpty()) {
+ 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);
+ 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))
+ return false;
+ }
+ } else {
+ if (prefix.isEmpty()) {
+ // directory must at least exist for valid import
+ QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
+ QFileInfo dirinfo(localFileOrQrc);
+ if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
+ if (errorString) {
+ if (localFileOrQrc.isEmpty())
+ *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
+ else
+ *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
+ }
+ return false;
+ }
+ }
+ }
+ }
+
+ url = base.resolved(QUrl(url)).toString();
+ if (url.endsWith(QLatin1Char('/')))
+ url.chop(1);
+ }
+
+ if (!versionFound && vmaj > -1 && vmin > -1 && !qmldircomponents.isEmpty()) {
+ QList<QDeclarativeDirParser::Component>::ConstIterator it = qmldircomponents.begin();
+ int lowest_maj = INT_MAX;
+ int lowest_min = INT_MAX;
+ int highest_maj = INT_MIN;
+ int highest_min = INT_MIN;
+ for (; it != qmldircomponents.end(); ++it) {
+ if (it->majorVersion > highest_maj || (it->majorVersion == highest_maj && it->minorVersion > highest_min)) {
+ highest_maj = it->majorVersion;
+ highest_min = it->minorVersion;
+ }
+ if (it->majorVersion < lowest_maj || (it->majorVersion == lowest_maj && it->minorVersion < lowest_min)) {
+ lowest_maj = it->majorVersion;
+ lowest_min = it->minorVersion;
+ }
+ }
+ 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);
+ return false;
+ }
+ }
+
+ s->uris.prepend(uri);
+ s->urls.prepend(url);
+ s->majversions.prepend(vmaj);
+ s->minversions.prepend(vmin);
+ s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library);
+ s->qmlDirComponents.prepend(qmldircomponents);
+ return true;
+}
+
+bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+ QUrl* url_return, QString *errorString)
+{
+ QDeclarativeImportedNamespace *s = 0;
+ int slash = type.indexOf('/');
+ if (slash >= 0) {
+ 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);
+ return false;
+ }
+ int nslash = type.indexOf('/',slash+1);
+ if (nslash > 0) {
+ if (errorString)
+ *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
+ return false;
+ }
+ } else {
+ s = &unqualifiedset;
+ }
+ 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))
+ return true;
+ if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
+ // qualified, and only 1 url
+ *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const QString& type)
+{
+ return set.value(type);
+}
+
+bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+ QUrl* url_return, QUrl *base, QString *errorString)
+{
+ bool typeRecursionDetected = false;
+ for (int i=0; i<urls.count(); ++i) {
+ if (find_helper(i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
+ if (qmlCheckTypes()) {
+ // 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) {
+ QString u1 = urls.at(i);
+ QString u2 = urls.at(j);
+ if (base) {
+ QString b = base->toString();
+ int slash = b.lastIndexOf(QLatin1Char('/'));
+ if (slash >= 0) {
+ b = b.left(slash+1);
+ QString l = b.left(slash);
+ if (u1.startsWith(b))
+ u1 = u1.mid(b.count());
+ else if (u1 == l)
+ u1 = QDeclarativeImportDatabase::tr("local directory");
+ if (u2.startsWith(b))
+ u2 = u2.mid(b.count());
+ else if (u2 == l)
+ u2 = QDeclarativeImportDatabase::tr("local directory");
+ }
+ }
+
+ 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));
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ if (errorString) {
+ if (typeRecursionDetected)
+ *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
+ else
+ *errorString = QDeclarativeImportDatabase::tr("is not a type");
+ }
+ return false;
+}
+
+/*!
+\class QDeclarativeImportDatabase
+\brief The QDeclarativeImportDatabase class manages the QML imports for a QDeclarativeEngine.
+\internal
+*/
+QDeclarativeImportDatabase::QDeclarativeImportDatabase(QDeclarativeEngine *e)
+: engine(e)
+{
+ filePluginPath << QLatin1String(".");
+
+ // Search order is applicationDirPath(), $QML_IMPORT_PATH, QLibraryInfo::ImportsPath
+
+#ifndef QT_NO_SETTINGS
+ QString installImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath);
+
+#if defined(Q_OS_SYMBIAN)
+ // Append imports path for all available drives in Symbian
+ if (installImportsPath.at(1) != QChar(QLatin1Char(':'))) {
+ QString tempPath = installImportsPath;
+ if (tempPath.at(tempPath.length() - 1) != QDir::separator()) {
+ tempPath += QDir::separator();
+ }
+ RFs& fs = qt_s60GetRFs();
+ TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData()));
+ TFindFile finder(fs);
+ TInt err = finder.FindByDir(tempPathPtr, tempPathPtr);
+ while (err == KErrNone) {
+ QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()),
+ finder.File().Length());
+ foundDir = QDir(foundDir).canonicalPath();
+ addImportPath(foundDir);
+ err = finder.Find();
+ }
+ } else {
+ addImportPath(installImportsPath);
+ }
+#else
+ addImportPath(installImportsPath);
+#endif
+
+#endif // QT_NO_SETTINGS
+
+ // env import paths
+ QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
+ if (!envImportPath.isEmpty()) {
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ QLatin1Char pathSep(';');
+#else
+ QLatin1Char pathSep(':');
+#endif
+ QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts);
+ for (int ii = paths.count() - 1; ii >= 0; --ii)
+ addImportPath(paths.at(ii));
+ }
+
+ addImportPath(QCoreApplication::applicationDirPath());
+}
+
+QDeclarativeImportDatabase::~QDeclarativeImportDatabase()
+{
+}
+
+/*!
+ \internal
+
+ Adds information to \a imports such that subsequent calls to resolveType()
+ will resolve types qualified by \a prefix by considering types found at the given \a uri.
+
+ The uri is either a directory (if importType is FileImport), or a URI resolved using paths
+ added via addImportPath() (if importType is LibraryImport).
+
+ The \a prefix may be empty, in which case the import location is considered for
+ unqualified types.
+
+ The base URL must already have been set with Import::setBaseUrl().
+*/
+bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
+ const QString& uri, const QString& prefix, int vmaj, int vmin,
+ QDeclarativeScriptParser::Import::Type importType,
+ const QDeclarativeDirComponents &qmldircomponentsnetwork,
+ QString *errorString)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: "
+ << uri << " " << vmaj << '.' << vmin << " "
+ << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File")
+ << " as " << prefix;
+
+ return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
+}
+
+/*!
+ \internal
+
+ Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix.
+ The \a prefix must contain the dot.
+
+ \a qmldirPath is the location of the qmldir file.
+ */
+QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName, const QStringList &suffixes,
+ const QString &prefix)
+{
+ QStringList searchPaths = filePluginPath;
+ bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
+ if (!qmldirPluginPathIsRelative)
+ searchPaths.prepend(qmldirPluginPath);
+
+ foreach (const QString &pluginPath, searchPaths) {
+
+ QString resolvedPath;
+
+ if (pluginPath == QLatin1String(".")) {
+ if (qmldirPluginPathIsRelative)
+ resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath);
+ else
+ resolvedPath = qmldirPath.absolutePath();
+ } else {
+ resolvedPath = pluginPath;
+ }
+
+ // hack for resources, should probably go away
+ if (resolvedPath.startsWith(QLatin1Char(':')))
+ resolvedPath = QCoreApplication::applicationDirPath();
+
+ QDir dir(resolvedPath);
+ foreach (const QString &suffix, suffixes) {
+ QString pluginFileName = prefix;
+
+ pluginFileName += baseName;
+ pluginFileName += suffix;
+
+ QFileInfo fileInfo(dir, pluginFileName);
+
+ if (fileInfo.exists())
+ return fileInfo.absoluteFilePath();
+ }
+ }
+
+ if (qmlImportTrace())
+ qDebug() << "QDeclarativeImportDatabase::resolvePlugin: Could not resolve plugin" << baseName
+ << "in" << qmldirPath.absolutePath();
+
+ return QString();
+}
+
+/*!
+ \internal
+
+ Returns the result of the merge of \a baseName with \a dir and the platform suffix.
+
+ \table
+ \header \i Platform \i Valid suffixes
+ \row \i Windows \i \c .dll
+ \row \i Unix/Linux \i \c .so
+ \row \i AIX \i \c .a
+ \row \i HP-UX \i \c .sl, \c .so (HP-UXi)
+ \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so
+ \row \i Symbian \i \c .dll
+ \endtable
+
+ Version number on unix are ignored.
+*/
+QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName)
+{
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+ QStringList()
+# ifdef QT_DEBUG
+ << QLatin1String("d.dll") // try a qmake-style debug build first
+# endif
+ << QLatin1String(".dll"));
+#elif defined(Q_OS_SYMBIAN)
+ return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+ QStringList()
+ << QLatin1String(".dll")
+ << QLatin1String(".qtplugin"));
+#else
+
+# if defined(Q_OS_DARWIN)
+
+ return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+ QStringList()
+# ifdef QT_DEBUG
+ << QLatin1String("_debug.dylib") // try a qmake-style debug build first
+ << QLatin1String(".dylib")
+# else
+ << QLatin1String(".dylib")
+ << QLatin1String("_debug.dylib") // try a qmake-style debug build after
+# endif
+ << QLatin1String(".so")
+ << QLatin1String(".bundle"),
+ QLatin1String("lib"));
+# else // Generic Unix
+ QStringList validSuffixList;
+
+# if defined(Q_OS_HPUX)
+/*
+ See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF":
+ "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit),
+ the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix."
+ */
+ validSuffixList << QLatin1String(".sl");
+# if defined __ia64
+ validSuffixList << QLatin1String(".so");
+# endif
+# elif defined(Q_OS_AIX)
+ validSuffixList << QLatin1String(".a") << QLatin1String(".so");
+# elif defined(Q_OS_UNIX)
+ validSuffixList << QLatin1String(".so");
+# endif
+
+ // Examples of valid library names:
+ // libfoo.so
+
+ return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
+# endif
+
+#endif
+}
+
+/*!
+ \internal
+*/
+QStringList QDeclarativeImportDatabase::pluginPathList() const
+{
+ return filePluginPath;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeImportDatabase::setPluginPathList(const QStringList &paths)
+{
+ filePluginPath = paths;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeImportDatabase::addPluginPath(const QString& path)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QDeclarativeImportDatabase::addPluginPath: " << path;
+
+ QUrl url = QUrl(path);
+ if (url.isRelative() || url.scheme() == QLatin1String("file")
+ || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ QDir dir = QDir(path);
+ filePluginPath.prepend(dir.canonicalPath());
+ } else {
+ filePluginPath.prepend(path);
+ }
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeImportDatabase::addImportPath(const QString& path)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QDeclarativeImportDatabase::addImportPath: " << path;
+
+ if (path.isEmpty())
+ return;
+
+ QUrl url = QUrl(path);
+ QString cPath;
+
+ if (url.isRelative() || url.scheme() == QLatin1String("file")
+ || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ QDir dir = QDir(path);
+ cPath = dir.canonicalPath();
+ } else {
+ cPath = path;
+ cPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ }
+
+ if (!cPath.isEmpty()
+ && !fileImportPath.contains(cPath))
+ fileImportPath.prepend(cPath);
+}
+
+/*!
+ \internal
+*/
+QStringList QDeclarativeImportDatabase::importPathList() const
+{
+ return fileImportPath;
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
+{
+ fileImportPath = paths;
+}
+
+/*!
+ \internal
+*/
+bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+{
+ if (qmlImportTrace())
+ qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
+
+#ifndef QT_NO_LIBRARY
+ QFileInfo fileInfo(filePath);
+ const QString absoluteFilePath = fileInfo.absoluteFilePath();
+
+ bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
+ bool typesRegistered = qmlEnginePluginsWithRegisteredTypes()->contains(absoluteFilePath);
+
+ if (typesRegistered) {
+ Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath) == uri,
+ "QDeclarativeImportDatabase::importExtension",
+ "Internal error: Plugin imported previously with different uri");
+ }
+
+ if (!engineInitialized || !typesRegistered) {
+ if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
+ if (errorString)
+ *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
+ return false;
+ }
+ QPluginLoader loader(absoluteFilePath);
+
+ if (!loader.load()) {
+ if (errorString)
+ *errorString = loader.errorString();
+ return false;
+ }
+
+ if (QDeclarativeExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(loader.instance())) {
+
+ const QByteArray bytes = uri.toUtf8();
+ const char *moduleId = bytes.constData();
+ if (!typesRegistered) {
+
+ // ### this code should probably be protected with a mutex.
+ qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
+ iface->registerTypes(moduleId);
+ }
+ if (!engineInitialized) {
+ // things on the engine (eg. adding new global objects) have to be done for every engine.
+
+ // protect against double initialization
+ initializedPlugins.insert(absoluteFilePath);
+ iface->initializeEngine(engine, moduleId);
+ }
+ } else {
+ if (errorString)
+ *errorString = loader.errorString();
+ return false;
+ }
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h
new file mode 100644
index 0000000000..1c910fd5bf
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeimport_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEIMPORT_P_H
+#define QDECLARATIVEIMPORT_P_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qset.h>
+#include <private/qdeclarativedirparser_p.h>
+#include <private/qdeclarativescriptparser_p.h>
+#include <private/qdeclarativemetatype_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeTypeNameCache;
+class QDeclarativeEngine;
+class QDir;
+class QDeclarativeImportedNamespace;
+class QDeclarativeImportsPrivate;
+class QDeclarativeImportDatabase;
+
+class QDeclarativeImports
+{
+public:
+ QDeclarativeImports();
+ QDeclarativeImports(const QDeclarativeImports &);
+ ~QDeclarativeImports();
+ QDeclarativeImports &operator=(const QDeclarativeImports &);
+
+ void setBaseUrl(const QUrl &url);
+ QUrl baseUrl() const;
+
+ bool resolveType(const QByteArray& type,
+ QDeclarativeType** type_return, QUrl* url_return,
+ int *version_major, int *version_minor,
+ QDeclarativeImportedNamespace** ns_return,
+ QString *errorString = 0) const;
+ bool resolveType(QDeclarativeImportedNamespace*,
+ const QByteArray& type,
+ QDeclarativeType** type_return, QUrl* url_return,
+ int *version_major, int *version_minor) const;
+
+ bool addImport(QDeclarativeImportDatabase *,
+ const QString& uri, const QString& prefix, int vmaj, int vmin,
+ QDeclarativeScriptParser::Import::Type importType,
+ const QDeclarativeDirComponents &qmldircomponentsnetwork,
+ QString *errorString);
+
+ void populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *) const;
+
+private:
+ friend class QDeclarativeImportDatabase;
+ QDeclarativeImportsPrivate *d;
+};
+
+class QDeclarativeImportDatabase
+{
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativeImportDatabase)
+public:
+ QDeclarativeImportDatabase(QDeclarativeEngine *);
+ ~QDeclarativeImportDatabase();
+
+ bool importPlugin(const QString &filePath, const QString &uri, QString *errorString);
+
+ QStringList importPathList() const;
+ void setImportPathList(const QStringList &paths);
+ void addImportPath(const QString& dir);
+
+ QStringList pluginPathList() const;
+ void setPluginPathList(const QStringList &paths);
+ void addPluginPath(const QString& path);
+
+private:
+ friend class QDeclarativeImportsPrivate;
+ QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName, const QStringList &suffixes,
+ const QString &prefix = QString());
+ QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
+ const QString &baseName);
+
+
+ QStringList filePluginPath;
+ QStringList fileImportPath;
+
+ QSet<QString> initializedPlugins;
+ QDeclarativeEngine *engine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEIMPORT_P_H
+
diff --git a/src/declarative/qml/qdeclarativeinclude.cpp b/src/declarative/qml/qdeclarativeinclude.cpp
new file mode 100644
index 0000000000..7102209126
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinclude.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeinclude_p.h"
+
+#include <QtScript/qscriptengine.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qfile.h>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativeglobalscriptclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeInclude::QDeclarativeInclude(const QUrl &url,
+ QDeclarativeEngine *engine,
+ QScriptContext *ctxt)
+: QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
+
+ m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
+ m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
+
+ m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager();
+
+ m_result = resultValue(m_scriptEngine);
+
+ QNetworkRequest request;
+ request.setUrl(url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+}
+
+QDeclarativeInclude::~QDeclarativeInclude()
+{
+ delete m_reply;
+}
+
+QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status)
+{
+ QScriptValue result = engine->newObject();
+ result.setProperty(QLatin1String("OK"), QScriptValue(engine, Ok));
+ result.setProperty(QLatin1String("LOADING"), QScriptValue(engine, Loading));
+ result.setProperty(QLatin1String("NETWORK_ERROR"), QScriptValue(engine, NetworkError));
+ result.setProperty(QLatin1String("EXCEPTION"), QScriptValue(engine, Exception));
+
+ result.setProperty(QLatin1String("status"), QScriptValue(engine, status));
+ return result;
+}
+
+QScriptValue QDeclarativeInclude::result() const
+{
+ return m_result;
+}
+
+void QDeclarativeInclude::setCallback(const QScriptValue &c)
+{
+ m_callback = c;
+}
+
+QScriptValue QDeclarativeInclude::callback() const
+{
+ return m_callback;
+}
+
+#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
+void QDeclarativeInclude::finished()
+{
+ m_redirectCount++;
+
+ if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ m_url = m_url.resolved(redirect.toUrl());
+ delete m_reply;
+
+ QNetworkRequest request;
+ request.setUrl(m_url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ return;
+ }
+ }
+
+ if (m_reply->error() == QNetworkReply::NoError) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine);
+
+ QByteArray data = m_reply->readAll();
+
+ QString code = QString::fromUtf8(data);
+
+ QString urlString = m_url.toString();
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(m_scriptEngine);
+ scriptContext->pushScope(ep->contextClass->newUrlContext(m_context, 0, urlString));
+ scriptContext->pushScope(m_scope[0]);
+
+ scriptContext->pushScope(m_scope[1]);
+ scriptContext->setActivationObject(m_scope[1]);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ m_scriptEngine->evaluate(code, urlString, 1);
+
+ m_scriptEngine->popContext();
+
+ if (m_scriptEngine->hasUncaughtException()) {
+ m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Exception));
+ m_result.setProperty(QLatin1String("exception"), m_scriptEngine->uncaughtException());
+ m_scriptEngine->clearExceptions();
+ } else {
+ m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok));
+ }
+ } else {
+ m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError));
+ }
+
+ callback(m_scriptEngine, m_callback, m_result);
+
+ disconnect();
+ deleteLater();
+}
+
+void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status)
+{
+ if (callback.isValid()) {
+ QScriptValue args = engine->newArray(1);
+ args.setProperty(0, status);
+ callback.call(QScriptValue(), args);
+ }
+}
+
+/*
+ Documented in qdeclarativeengine.cpp
+*/
+QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (ctxt->argumentCount() == 0)
+ return engine->undefinedValue();
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ QUrl contextUrl = ep->contextClass->urlFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
+ if (contextUrl.isEmpty())
+ return ctxt->throwError(QLatin1String("Qt.include(): Can only be called from JavaScript files"));
+
+ QString urlString = ctxt->argument(0).toString();
+ QUrl url(urlString);
+ if (url.isRelative()) {
+ url = QUrl(contextUrl).resolved(url);
+ urlString = url.toString();
+ }
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+
+ QScriptValue func = ctxt->argument(1);
+ if (!func.isFunction())
+ func = QScriptValue();
+
+ QScriptValue result;
+ if (localFile.isEmpty()) {
+ QDeclarativeInclude *i =
+ new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt);
+
+ if (func.isValid())
+ i->setCallback(func);
+
+ result = i->result();
+ } else {
+
+ QFile f(localFile);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+
+ QDeclarativeContextData *context =
+ ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
+ scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString));
+ scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+ QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
+ scriptContext->pushScope(scope);
+ scriptContext->setActivationObject(scope);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ engine->evaluate(code, urlString, 1);
+
+ engine->popContext();
+
+ if (engine->hasUncaughtException()) {
+ result = resultValue(engine, Exception);
+ result.setProperty(QLatin1String("exception"), engine->uncaughtException());
+ engine->clearExceptions();
+ } else {
+ result = resultValue(engine, Ok);
+ }
+ callback(engine, func, result);
+ } else {
+ result = resultValue(engine, NetworkError);
+ callback(engine, func, result);
+ }
+ }
+
+ return result;
+}
+
+QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (ctxt->argumentCount() == 0)
+ return engine->undefinedValue();
+
+ QString urlString = ctxt->argument(0).toString();
+ QUrl url(ctxt->argument(0).toString());
+ if (url.isRelative()) {
+ QString contextUrl = QScriptDeclarativeClass::scopeChainValue(ctxt, -3).data().toString();
+ Q_ASSERT(!contextUrl.isEmpty());
+
+ url = QUrl(contextUrl).resolved(url);
+ urlString = url.toString();
+ }
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+
+ QScriptValue func = ctxt->argument(1);
+ if (!func.isFunction())
+ func = QScriptValue();
+
+ QScriptValue result;
+ if (!localFile.isEmpty()) {
+
+ QFile f(localFile);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+
+ QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
+ QScriptValue urlContext = engine->newObject();
+ urlContext.setData(QScriptValue(engine, urlString));
+ scriptContext->pushScope(urlContext);
+
+ QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
+ scriptContext->pushScope(scope);
+ scriptContext->setActivationObject(scope);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ engine->evaluate(code, urlString, 1);
+
+ engine->popContext();
+
+ if (engine->hasUncaughtException()) {
+ result = resultValue(engine, Exception);
+ result.setProperty(QLatin1String("exception"), engine->uncaughtException());
+ engine->clearExceptions();
+ } else {
+ result = resultValue(engine, Ok);
+ }
+ callback(engine, func, result);
+ } else {
+ result = resultValue(engine, NetworkError);
+ callback(engine, func, result);
+ }
+ }
+
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinclude_p.h b/src/declarative/qml/qdeclarativeinclude_p.h
new file mode 100644
index 0000000000..e56de79058
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinclude_p.h
@@ -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 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 QDECLARATIVEINCLUDE_P_H
+#define QDECLARATIVEINCLUDE_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/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtScript/qscriptvalue.h>
+
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QScriptContext;
+class QScriptEngine;
+class QNetworkAccessManager;
+class QNetworkReply;
+class QDeclarativeInclude : public QObject
+{
+ Q_OBJECT
+public:
+ enum Status {
+ Ok = 0,
+ Loading = 1,
+ NetworkError = 2,
+ Exception = 3
+ };
+
+ QDeclarativeInclude(const QUrl &, QDeclarativeEngine *, QScriptContext *ctxt);
+ ~QDeclarativeInclude();
+
+ void setCallback(const QScriptValue &);
+ QScriptValue callback() const;
+
+ QScriptValue result() const;
+
+ static QScriptValue resultValue(QScriptEngine *, Status status = Loading);
+ static void callback(QScriptEngine *, QScriptValue &callback, QScriptValue &status);
+
+ static QScriptValue include(QScriptContext *ctxt, QScriptEngine *engine);
+ static QScriptValue worker_include(QScriptContext *ctxt, QScriptEngine *engine);
+
+public slots:
+ void finished();
+
+private:
+ QDeclarativeEngine *m_engine;
+ QScriptEngine *m_scriptEngine;
+ QNetworkAccessManager *m_network;
+ QDeclarativeGuard<QNetworkReply> m_reply;
+
+ QUrl m_url;
+ int m_redirectCount;
+ QScriptValue m_callback;
+ QScriptValue m_result;
+ QDeclarativeGuardedContextData m_context;
+ QScriptValue m_scope[2];
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEINCLUDE_P_H
+
diff --git a/src/declarative/qml/qdeclarativeinfo.cpp b/src/declarative/qml/qdeclarativeinfo.cpp
new file mode 100644
index 0000000000..7c8f73bc61
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinfo.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 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 "qdeclarativeinfo.h"
+
+#include "private/qdeclarativedata_p.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "private/qdeclarativeengine_p.h"
+
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \fn QDeclarativeInfo qmlInfo(const QObject *object)
+ \relates QDeclarativeEngine
+
+ Prints warning messages that include the file and line number for the
+ specified QML \a object.
+
+ When QML types display warning messages, it improves traceability
+ if they include the QML file and line number on which the
+ particular instance was instantiated.
+
+ To include the file and line number, an object must be passed. If
+ the file and line number is not available for that instance
+ (either it was not instantiated by the QML engine or location
+ information is disabled), "unknown location" will be used instead.
+
+ For example,
+
+ \code
+ qmlInfo(object) << tr("component property is a write-once property");
+ \endcode
+
+ prints
+
+ \code
+ QML MyCustomType (unknown location): component property is a write-once property
+ \endcode
+*/
+
+class QDeclarativeInfoPrivate
+{
+public:
+ QDeclarativeInfoPrivate() : ref (1), object(0) {}
+
+ int ref;
+ const QObject *object;
+ QString buffer;
+ QList<QDeclarativeError> errors;
+};
+
+QDeclarativeInfo::QDeclarativeInfo(QDeclarativeInfoPrivate *p)
+: QDebug(&p->buffer), d(p)
+{
+ nospace();
+}
+
+QDeclarativeInfo::QDeclarativeInfo(const QDeclarativeInfo &other)
+: QDebug(other), d(other.d)
+{
+ d->ref++;
+}
+
+QDeclarativeInfo::~QDeclarativeInfo()
+{
+ if (0 == --d->ref) {
+ QList<QDeclarativeError> errors = d->errors;
+
+ QDeclarativeEngine *engine = 0;
+
+ if (!d->buffer.isEmpty()) {
+ QDeclarativeError error;
+
+ QObject *object = const_cast<QObject *>(d->object);
+
+ if (object) {
+ engine = qmlEngine(d->object);
+ QString typeName;
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
+ if (type) {
+ typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ typeName = typeName.mid(lastSlash+1);
+ } else {
+ typeName = QString::fromUtf8(object->metaObject()->className());
+ int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
+ if (marker != -1)
+ typeName = typeName.left(marker);
+ }
+
+ d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ error.setUrl(ddata->outerContext->url);
+ error.setLine(ddata->lineNumber);
+ error.setColumn(ddata->columnNumber);
+ }
+ }
+
+ error.setDescription(d->buffer);
+
+ errors.prepend(error);
+ }
+
+ QDeclarativeEnginePrivate::warning(engine, errors);
+
+ delete d;
+ }
+}
+
+QDeclarativeInfo qmlInfo(const QObject *me)
+{
+ QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate;
+ d->object = me;
+ return QDeclarativeInfo(d);
+}
+
+QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error)
+{
+ QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate;
+ d->object = me;
+ d->errors << error;
+ return QDeclarativeInfo(d);
+}
+
+QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors)
+{
+ QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate;
+ d->object = me;
+ d->errors = errors;
+ return QDeclarativeInfo(d);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinfo.h b/src/declarative/qml/qdeclarativeinfo.h
new file mode 100644
index 0000000000..1a65bff090
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinfo.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 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 QDECLARATIVEINFO_H
+#define QDECLARATIVEINFO_H
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qurl.h>
+#include <QtDeclarative/qdeclarativeerror.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeInfoPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeInfo : public QDebug
+{
+public:
+ QDeclarativeInfo(const QDeclarativeInfo &);
+ ~QDeclarativeInfo();
+
+ inline QDeclarativeInfo &operator<<(QChar t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(QBool t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(bool t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(char t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(signed short t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(unsigned short t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(signed int t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(unsigned int t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(signed long t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(unsigned long t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(qint64 t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(quint64 t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(float t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(double t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; }
+ inline QDeclarativeInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QDeclarativeInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; }
+ inline QDeclarativeInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; }
+ inline QDeclarativeInfo &operator<<(QTextStreamFunction f) { QDebug::operator<<(f); return *this; }
+ inline QDeclarativeInfo &operator<<(QTextStreamManipulator m) { QDebug::operator<<(m); return *this; }
+#ifndef QT_NO_DEBUG_STREAM
+ inline QDeclarativeInfo &operator<<(const QUrl &t) { static_cast<QDebug &>(*this) << t; return *this; }
+#endif
+
+private:
+ friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me);
+ friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error);
+ friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors);
+
+ QDeclarativeInfo(QDeclarativeInfoPrivate *);
+ QDeclarativeInfoPrivate *d;
+};
+
+Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me);
+Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error);
+Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEINFO_H
diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp
new file mode 100644
index 0000000000..0c99cefb04
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinstruction.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeinstruction_p.h"
+
+#include "private/qdeclarativecompiler_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx)
+{
+#ifdef QT_NO_DEBUG_STREAM
+ Q_UNUSED(instr)
+ Q_UNUSED(idx)
+#else
+ QByteArray lineNumber = QByteArray::number(instr->line);
+ if (instr->line == (unsigned short)-1)
+ lineNumber = "NA";
+ const char *line = lineNumber.constData();
+
+ switch(instr->type) {
+ case QDeclarativeInstruction::Init:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding;
+ break;
+ case QDeclarativeInstruction::CreateObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t" << instr->create.bindingBits << "\t\t" << types.at(instr->create.type).className;
+ break;
+ case QDeclarativeInstruction::CreateSimpleObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize;
+ break;
+ case QDeclarativeInstruction::SetId:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value);
+ break;
+ case QDeclarativeInstruction::SetDefault:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "SET_DEFAULT";
+ break;
+ case QDeclarativeInstruction::CreateComponent:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count;
+ break;
+ case QDeclarativeInstruction::StoreMetaObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data;
+ break;
+
+ case QDeclarativeInstruction::StoreFloat:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value;
+ break;
+ case QDeclarativeInstruction::StoreDouble:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ break;
+ case QDeclarativeInstruction::StoreInteger:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ break;
+ case QDeclarativeInstruction::StoreBool:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ break;
+ 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::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;
+ case QDeclarativeInstruction::StoreColor:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16);
+ break;
+ case QDeclarativeInstruction::StoreDate:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value;
+ break;
+ case QDeclarativeInstruction::StoreTime:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreDateTime:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex;
+ break;
+ case QDeclarativeInstruction::StorePoint:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ break;
+ case QDeclarativeInstruction::StorePointF:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreSize:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreSizeF:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreRect:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreRectF:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreVector3D:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.valueIndex;
+ break;
+ case QDeclarativeInstruction::StoreVariant:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value);
+ break;
+ case QDeclarativeInstruction::StoreVariantInteger:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value;
+ break;
+ case QDeclarativeInstruction::StoreVariantDouble:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value;
+ break;
+ case QDeclarativeInstruction::StoreVariantBool:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value;
+ break;
+ case QDeclarativeInstruction::StoreObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex;
+ break;
+ case QDeclarativeInstruction::StoreVariantObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex;
+ break;
+ case QDeclarativeInstruction::StoreInterface:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex;
+ break;
+
+ case QDeclarativeInstruction::StoreSignal:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value);
+ break;
+ case QDeclarativeInstruction::StoreImportedScript:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value;
+ break;
+ case QDeclarativeInstruction::StoreScriptString:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope;
+ break;
+
+ case QDeclarativeInstruction::AssignSignalObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal);
+ break;
+ case QDeclarativeInstruction::AssignCustomType:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex;
+ break;
+
+ case QDeclarativeInstruction::StoreBinding:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QDeclarativeInstruction::StoreBindingOnAlias:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QDeclarativeInstruction::StoreCompiledBinding:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ break;
+ case QDeclarativeInstruction::StoreValueSource:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue;
+ break;
+ case QDeclarativeInstruction::StoreValueInterceptor:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue;
+ break;
+
+ case QDeclarativeInstruction::BeginObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue;
+ break;
+ case QDeclarativeInstruction::StoreObjectQList:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT_QLIST";
+ break;
+ case QDeclarativeInstruction::AssignObjectList:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_OBJECT_LIST";
+ break;
+ case QDeclarativeInstruction::FetchAttached:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id;
+ break;
+ case QDeclarativeInstruction::FetchQList:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property;
+ break;
+ case QDeclarativeInstruction::FetchObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property;
+ break;
+ case QDeclarativeInstruction::FetchValueType:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList;
+ break;
+ case QDeclarativeInstruction::PopFetchedObject:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP";
+ break;
+ case QDeclarativeInstruction::PopQList:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_QLIST";
+ break;
+ case QDeclarativeInstruction::PopValueType:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type;
+ break;
+ case QDeclarativeInstruction::Defer:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount;
+ break;
+ default:
+ qWarning().nospace() << idx << "\t\t" << line << "\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instr->type;
+ break;
+ }
+#endif // QT_NO_DEBUG_STREAM
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h
new file mode 100644
index 0000000000..20be889252
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeinstruction_p.h
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEINSTRUCTION_P_H
+#define QDECLARATIVEINSTRUCTION_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 QDeclarativeCompiledData;
+class Q_AUTOTEST_EXPORT QDeclarativeInstruction
+{
+public:
+ enum Type {
+ //
+ // Object Creation
+ //
+ // CreateObject - Create a new object instance and push it on the
+ // object stack
+ // SetId - Set the id of the object on the top of the object stack
+ // SetDefault - Sets the instance on the top of the object stack to
+ // be the context's default object.
+ // StoreMetaObject - Assign the dynamic metaobject to object on the
+ // top of the stack.
+ Init, /* init */
+ CreateObject, /* create */
+ CreateSimpleObject, /* createSimple */
+ SetId, /* setId */
+ SetDefault,
+ CreateComponent, /* createComponent */
+ StoreMetaObject, /* storeMeta */
+
+ //
+ // Precomputed single assignment
+ //
+ // StoreFloat - Store a float in a core property
+ // StoreDouble - Store a double in a core property
+ // 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
+ // StoreUrl - Store a QUrl in a core property
+ // StoreColor - Store a QColor in a core property
+ // StoreDate - Store a QDate in a core property
+ // StoreTime - Store a QTime in a core property
+ // StoreDateTime - Store a QDateTime in a core property
+ // StoreVariant - Store a QVariant in a core property
+ // StoreObject - Pop the object on the top of the object stack and
+ // store it in a core property
+ StoreFloat, /* storeFloat */
+ StoreDouble, /* storeDouble */
+ StoreInteger, /* storeInteger */
+ StoreBool, /* storeBool */
+ StoreString, /* storeString */
+ StoreUrl, /* storeUrl */
+ StoreColor, /* storeColor */
+ StoreDate, /* storeDate */
+ StoreTime, /* storeTime */
+ StoreDateTime, /* storeDateTime */
+ StorePoint, /* storeRealPair */
+ StorePointF, /* storeRealPair */
+ StoreSize, /* storeRealPair */
+ StoreSizeF, /* storeRealPair */
+ StoreRect, /* storeRect */
+ StoreRectF, /* storeRect */
+ StoreVector3D, /* storeVector3D */
+ StoreVariant, /* storeString */
+ StoreVariantInteger, /* storeInteger */
+ StoreVariantDouble, /* storeDouble */
+ StoreVariantBool, /* storeBool */
+ StoreObject, /* storeObject */
+ StoreVariantObject, /* storeObject */
+ StoreInterface, /* storeObject */
+
+ StoreSignal, /* storeSignal */
+ StoreImportedScript, /* storeScript */
+ StoreScriptString, /* storeScriptString */
+
+ //
+ // Unresolved single assignment
+ //
+ AssignSignalObject, /* assignSignalObject */
+ AssignCustomType, /* assignCustomType */
+
+ StoreBinding, /* assignBinding */
+ StoreBindingOnAlias, /* assignBinding */
+ StoreCompiledBinding, /* assignBinding */
+ StoreValueSource, /* assignValueSource */
+ StoreValueInterceptor, /* assignValueInterceptor */
+
+ BeginObject, /* begin */
+
+ StoreObjectQList, /* NA */
+ AssignObjectList, /* NA */
+
+ FetchAttached, /* fetchAttached */
+ FetchQList, /* fetch */
+ FetchObject, /* fetch */
+ FetchValueType, /* fetchValue */
+
+ //
+ // Stack manipulation
+ //
+ // PopFetchedObject - Remove an object from the object stack
+ // PopQList - Remove a list from the list stack
+ PopFetchedObject,
+ PopQList,
+ PopValueType, /* fetchValue */
+
+ //
+ // Deferred creation
+ //
+ Defer /* defer */
+ };
+ QDeclarativeInstruction()
+ : line(0) {}
+
+ Type type;
+ unsigned short line;
+
+ struct InitInstruction {
+ int bindingsSize;
+ int parserStatusSize;
+ int contextCache;
+ int compiledBinding;
+ };
+ struct CreateInstruction {
+ int type;
+ int data;
+ int bindingBits;
+ ushort column;
+ };
+ struct CreateSimpleInstruction {
+ void (*create)(void *);
+ int typeSize;
+ int type;
+ ushort column;
+ };
+ struct StoreMetaInstruction {
+ int data;
+ int aliasData;
+ int propertyCache;
+ };
+ struct SetIdInstruction {
+ int value;
+ int index;
+ };
+ struct AssignValueSourceInstruction {
+ int property;
+ int owner;
+ int castValue;
+ };
+ struct AssignValueInterceptorInstruction {
+ int property;
+ int owner;
+ int castValue;
+ };
+ struct AssignBindingInstruction {
+ unsigned int property;
+ int value;
+ short context;
+ short owner;
+ };
+ struct FetchInstruction {
+ int property;
+ };
+ struct FetchValueInstruction {
+ int property;
+ int type;
+ quint32 bindingSkipList;
+ };
+ struct FetchQmlListInstruction {
+ int property;
+ int type;
+ };
+ struct BeginInstruction {
+ int castValue;
+ };
+ struct StoreFloatInstruction {
+ int propertyIndex;
+ float value;
+ };
+ struct StoreDoubleInstruction {
+ int propertyIndex;
+ double value;
+ };
+ struct StoreIntegerInstruction {
+ int propertyIndex;
+ int value;
+ };
+ struct StoreBoolInstruction {
+ int propertyIndex;
+ bool value;
+ };
+ struct StoreStringInstruction {
+ int propertyIndex;
+ int value;
+ };
+ struct StoreScriptStringInstruction {
+ int propertyIndex;
+ int value;
+ int scope;
+ };
+ struct StoreScriptInstruction {
+ int value;
+ };
+ struct StoreUrlInstruction {
+ int propertyIndex;
+ int value;
+ };
+ struct StoreColorInstruction {
+ int propertyIndex;
+ unsigned int value;
+ };
+ struct StoreDateInstruction {
+ int propertyIndex;
+ int value;
+ };
+ struct StoreTimeInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreDateTimeInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreRealPairInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreRectInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreVector3DInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreObjectInstruction {
+ int propertyIndex;
+ };
+ struct AssignCustomTypeInstruction {
+ int propertyIndex;
+ int valueIndex;
+ };
+ struct StoreSignalInstruction {
+ int signalIndex;
+ int value;
+ short context;
+ int name;
+ };
+ struct AssignSignalObjectInstruction {
+ int signal;
+ };
+ struct CreateComponentInstruction {
+ int count;
+ ushort column;
+ int endLine;
+ int metaObject;
+ };
+ struct FetchAttachedInstruction {
+ int id;
+ };
+ struct DeferInstruction {
+ int deferCount;
+ };
+
+ union {
+ InitInstruction init;
+ CreateInstruction create;
+ CreateSimpleInstruction createSimple;
+ StoreMetaInstruction storeMeta;
+ SetIdInstruction setId;
+ AssignValueSourceInstruction assignValueSource;
+ AssignValueInterceptorInstruction assignValueInterceptor;
+ AssignBindingInstruction assignBinding;
+ FetchInstruction fetch;
+ FetchValueInstruction fetchValue;
+ FetchQmlListInstruction fetchQmlList;
+ BeginInstruction begin;
+ StoreFloatInstruction storeFloat;
+ StoreDoubleInstruction storeDouble;
+ StoreIntegerInstruction storeInteger;
+ StoreBoolInstruction storeBool;
+ StoreStringInstruction storeString;
+ StoreScriptStringInstruction storeScriptString;
+ StoreScriptInstruction storeScript;
+ StoreUrlInstruction storeUrl;
+ StoreColorInstruction storeColor;
+ StoreDateInstruction storeDate;
+ StoreTimeInstruction storeTime;
+ StoreDateTimeInstruction storeDateTime;
+ StoreRealPairInstruction storeRealPair;
+ StoreRectInstruction storeRect;
+ StoreVector3DInstruction storeVector3D;
+ StoreObjectInstruction storeObject;
+ AssignCustomTypeInstruction assignCustomType;
+ StoreSignalInstruction storeSignal;
+ AssignSignalObjectInstruction assignSignalObject;
+ CreateComponentInstruction createComponent;
+ FetchAttachedInstruction fetchAttached;
+ DeferInstruction defer;
+ };
+
+ void dump(QDeclarativeCompiledData *);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEINSTRUCTION_P_H
diff --git a/src/declarative/qml/qdeclarativeintegercache.cpp b/src/declarative/qml/qdeclarativeintegercache.cpp
new file mode 100644
index 0000000000..cbeb16842f
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeintegercache.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeintegercache_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativemetatype_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeIntegerCache::QDeclarativeIntegerCache(QDeclarativeEngine *e)
+: QDeclarativeCleanup(e), engine(e)
+{
+}
+
+QDeclarativeIntegerCache::~QDeclarativeIntegerCache()
+{
+ clear();
+}
+
+void QDeclarativeIntegerCache::clear()
+{
+ qDeleteAll(stringCache);
+ stringCache.clear();
+ identifierCache.clear();
+ engine = 0;
+}
+
+QString QDeclarativeIntegerCache::findId(int value) const
+{
+ for (StringCache::ConstIterator iter = stringCache.begin();
+ iter != stringCache.end(); ++iter) {
+ if (iter.value() && iter.value()->value == value)
+ return iter.key();
+ }
+ return QString();
+}
+
+void QDeclarativeIntegerCache::add(const QString &id, int value)
+{
+ Q_ASSERT(!stringCache.contains(id));
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+
+ // ### use contextClass
+ Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value);
+
+ stringCache.insert(id, d);
+ identifierCache.insert(d->identifier, d);
+}
+
+int QDeclarativeIntegerCache::value(const QString &id)
+{
+ Data *d = stringCache.value(id);
+ return d?d->value:-1;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeintegercache_p.h b/src/declarative/qml/qdeclarativeintegercache_p.h
new file mode 100644
index 0000000000..686880e0d7
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeintegercache_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEINTEGERCACHE_P_H
+#define QDECLARATIVEINTEGERCACHE_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/qdeclarativerefcount_p.h"
+#include "private/qdeclarativecleanup_p.h"
+
+#include <QtCore/qhash.h>
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeType;
+class QDeclarativeEngine;
+class QDeclarativeIntegerCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+{
+public:
+ QDeclarativeIntegerCache(QDeclarativeEngine *);
+ virtual ~QDeclarativeIntegerCache();
+
+ inline int count() const;
+ void add(const QString &, int);
+ int value(const QString &);
+ QString findId(int value) const;
+ inline int value(const QScriptDeclarativeClass::Identifier &id) const;
+
+protected:
+ virtual void clear();
+
+private:
+ struct Data : public QScriptDeclarativeClass::PersistentIdentifier {
+ Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v)
+ : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {}
+
+ int value;
+ };
+
+ typedef QHash<QString, Data *> StringCache;
+ typedef QHash<QScriptDeclarativeClass::Identifier, Data *> IdentifierCache;
+
+ StringCache stringCache;
+ IdentifierCache identifierCache;
+ QDeclarativeEngine *engine;
+};
+
+int QDeclarativeIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const
+{
+ Data *d = identifierCache.value(id);
+ return d?d->value:-1;
+}
+
+int QDeclarativeIntegerCache::count() const
+{
+ return stringCache.count();
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEINTEGERCACHE_P_H
+
diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp
new file mode 100644
index 0000000000..346fee5ce8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativelist.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** 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 "qdeclarativelist.h"
+#include "private/qdeclarativelist_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeListReferencePrivate::QDeclarativeListReferencePrivate()
+: propertyType(-1), refCount(1)
+{
+}
+
+QDeclarativeListReference QDeclarativeListReferencePrivate::init(const QDeclarativeListProperty<QObject> &prop, int propType, QDeclarativeEngine *engine)
+{
+ QDeclarativeListReference rv;
+
+ if (!prop.object) return rv;
+
+ QDeclarativeEnginePrivate *p = engine?QDeclarativeEnginePrivate::get(engine):0;
+
+ int listType = p?p->listType(propType):QDeclarativeMetaType::listType(propType);
+ if (listType == -1) return rv;
+
+ rv.d = new QDeclarativeListReferencePrivate;
+ rv.d->object = prop.object;
+ rv.d->elementType = p?p->rawMetaObjectForType(listType):QDeclarativeMetaType::qmlType(listType)->baseMetaObject();
+ rv.d->property = prop;
+ rv.d->propertyType = propType;
+
+ return rv;
+}
+
+void QDeclarativeListReferencePrivate::addref()
+{
+ Q_ASSERT(refCount > 0);
+ ++refCount;
+}
+
+void QDeclarativeListReferencePrivate::release()
+{
+ Q_ASSERT(refCount > 0);
+ --refCount;
+ if (!refCount)
+ delete this;
+}
+
+/*!
+\class QDeclarativeListReference
+\since 4.7
+\module QtDeclarative
+\brief The QDeclarativeListReference class allows the manipulation of QDeclarativeListProperty properties.
+
+QDeclarativeListReference allows C++ programs to read from, and assign values to a QML list property in a
+simple and type safe way. A QDeclarativeListReference can be created by passing an object and property
+name or through a QDeclarativeProperty instance. These two are equivalant:
+
+\code
+QDeclarativeListReference ref1(object, "children");
+
+QDeclarativeProperty ref2(object, "children");
+QDeclarativeListReference ref2 = qvariant_cast<QDeclarativeListReference>(ref2.read());
+\endcode
+
+Not all QML list properties support all operations. A set of methods, canAppend(), canAt(), canClear() and
+canCount() allow programs to query whether an operation is supported on a given property.
+
+QML list properties are typesafe. Only QObject's that derive from the correct base class can be assigned to
+the list. The listElementType() method can be used to query the QMetaObject of the QObject type supported.
+Attempting to add objects of the incorrect type to a list property will fail.
+
+Like with normal lists, when accessing a list element by index, it is the callers responsibility to ensure
+that it does not request an out of range element using the count() method before calling at().
+*/
+
+/*!
+Constructs an invalid instance.
+*/
+QDeclarativeListReference::QDeclarativeListReference()
+: d(0)
+{
+}
+
+/*!
+Constructs a QDeclarativeListReference for \a object's \a property. If \a property is not a list
+property, an invalid QDeclarativeListReference is created. If \a object is destroyed after
+the reference is constructed, it will automatically become invalid. That is, it is safe to hold
+QDeclarativeListReference instances even after \a object is deleted.
+
+Passing \a engine is required to access some QML created list properties. If in doubt, and an engine
+is available, pass it.
+*/
+QDeclarativeListReference::QDeclarativeListReference(QObject *object, const char *property, QDeclarativeEngine *engine)
+: d(0)
+{
+ if (!object || !property) return;
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *data =
+ QDeclarativePropertyCache::property(engine, object, QLatin1String(property), local);
+
+ if (!data || !(data->flags & QDeclarativePropertyCache::Data::IsQList)) return;
+
+ QDeclarativeEnginePrivate *p = engine?QDeclarativeEnginePrivate::get(engine):0;
+
+ int listType = p?p->listType(data->propType):QDeclarativeMetaType::listType(data->propType);
+ if (listType == -1) return;
+
+ d = new QDeclarativeListReferencePrivate;
+ d->object = object;
+ d->elementType = p?p->rawMetaObjectForType(listType):QDeclarativeMetaType::qmlType(listType)->baseMetaObject();
+ d->propertyType = data->propType;
+
+ void *args[] = { &d->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args);
+}
+
+/*! \internal */
+QDeclarativeListReference::QDeclarativeListReference(const QDeclarativeListReference &o)
+: d(o.d)
+{
+ if (d) d->addref();
+}
+
+/*! \internal */
+QDeclarativeListReference &QDeclarativeListReference::operator=(const QDeclarativeListReference &o)
+{
+ if (o.d) o.d->addref();
+ if (d) d->release();
+ d = o.d;
+ return *this;
+}
+
+/*! \internal */
+QDeclarativeListReference::~QDeclarativeListReference()
+{
+ if (d) d->release();
+}
+
+/*!
+Returns true if the instance refers to a valid list property, otherwise false.
+*/
+bool QDeclarativeListReference::isValid() const
+{
+ return d && d->object;
+}
+
+/*!
+Returns the list property's object. Returns 0 if the reference is invalid.
+*/
+QObject *QDeclarativeListReference::object() const
+{
+ if (isValid()) return d->object;
+ else return 0;
+}
+
+/*!
+Returns the QMetaObject for the elements stored in the list property. Returns 0 if the reference
+is invalid.
+
+The QMetaObject can be used ahead of time to determine whether a given instance can be added
+to a list.
+*/
+const QMetaObject *QDeclarativeListReference::listElementType() const
+{
+ if (isValid()) return d->elementType;
+ else return 0;
+}
+
+/*!
+Returns true if the list property can be appended to, otherwise false. Returns false if the
+reference is invalid.
+
+\sa append()
+*/
+bool QDeclarativeListReference::canAppend() const
+{
+ return (isValid() && d->property.append);
+}
+
+/*!
+Returns true if the list property can queried by index, otherwise false. Returns false if the
+reference is invalid.
+
+\sa at()
+*/
+bool QDeclarativeListReference::canAt() const
+{
+ return (isValid() && d->property.at);
+}
+
+/*!
+Returns true if the list property can be cleared, otherwise false. Returns false if the
+reference is invalid.
+
+\sa clear()
+*/
+bool QDeclarativeListReference::canClear() const
+{
+ return (isValid() && d->property.clear);
+}
+
+/*!
+Returns true if the list property can be queried for its element count, otherwise false.
+Returns false if the reference is invalid.
+
+\sa count()
+*/
+bool QDeclarativeListReference::canCount() const
+{
+ return (isValid() && d->property.count);
+}
+
+/*!
+Appends \a object to the list. Returns true if the operation succeeded, otherwise false.
+
+\sa canAppend()
+*/
+bool QDeclarativeListReference::append(QObject *object) const
+{
+ if (!canAppend()) return false;
+
+ if (object && !QDeclarativePropertyPrivate::canConvert(object->metaObject(), d->elementType))
+ return false;
+
+ d->property.append(&d->property, object);
+
+ return true;
+}
+
+/*!
+Returns the list element at \a index, or 0 if the operation failed.
+
+\sa canAt()
+*/
+QObject *QDeclarativeListReference::at(int index) const
+{
+ if (!canAt()) return 0;
+
+ return d->property.at(&d->property, index);
+}
+
+/*!
+Clears the list. Returns true if the operation succeeded, otherwise false.
+
+\sa canClear()
+*/
+bool QDeclarativeListReference::clear() const
+{
+ if (!canClear()) return false;
+
+ d->property.clear(&d->property);
+
+ return true;
+}
+
+/*!
+Returns the number of objects in the list, or 0 if the operation failed.
+*/
+int QDeclarativeListReference::count() const
+{
+ if (!canCount()) return 0;
+
+ return d->property.count(&d->property);
+}
+
+/*!
+\class QDeclarativeListProperty
+\since 4.7
+\brief The QDeclarativeListProperty class allows applications to expose list-like
+properties to QML.
+
+QML has many list properties, where more than one object value can be assigned.
+The use of a list property from QML looks like this:
+
+\code
+FruitBasket {
+ fruit: [
+ Apple {},
+ Orange{},
+ Banana{}
+ ]
+}
+\endcode
+
+The QDeclarativeListProperty encapsulates a group of function pointers that represet the
+set of actions QML can perform on the list - adding items, retrieving items and
+clearing the list. In the future, additional operations may be supported. All
+list properties must implement the append operation, but the rest are optional.
+
+To provide a list property, a C++ class must implement the operation callbacks,
+and then return an appropriate QDeclarativeListProperty value from the property getter.
+List properties should have no setter. In the example above, the Q_PROPERTY()
+declarative will look like this:
+
+\code
+Q_PROPERTY(QDeclarativeListProperty<Fruit> fruit READ fruit);
+\endcode
+
+QML list properties are typesafe - in this case \c {Fruit} is a QObject type that
+\c {Apple}, \c {Orange} and \c {Banana} all derive from.
+
+\note QDeclarativeListProperty can only be used for lists of QObject-derived object pointers.
+
+\sa {Object and List Property Types}
+
+*/
+
+/*!
+\fn QDeclarativeListProperty::QDeclarativeListProperty()
+\internal
+*/
+
+/*!
+\fn QDeclarativeListProperty::QDeclarativeListProperty(QObject *object, QList<T *> &list)
+
+Convenience constructor for making a QDeclarativeListProperty value from an existing
+QList \a list. The \a list reference must remain valid for as long as \a object
+exists. \a object must be provided.
+
+Generally this constructor should not be used in production code, as a
+writable QList violates QML's memory management rules. However, this constructor
+can very useful while prototyping.
+*/
+
+/*!
+\fn QDeclarativeListProperty::QDeclarativeListProperty(QObject *object, void *data, AppendFunction append,
+ CountFunction count = 0, AtFunction at = 0,
+ ClearFunction clear = 0)
+
+Construct a QDeclarativeListProperty from a set of operation functions. An opaque \a data handle
+may be passed which can be accessed from within the operation functions. The list property
+remains valid while \a object exists.
+
+The \a append operation is compulsory and must be provided, while the \a count, \a at and
+\a clear methods are optional.
+*/
+
+/*!
+\typedef QDeclarativeListProperty::AppendFunction
+
+Synonym for \c {void (*)(QDeclarativeListProperty<T> *property, T *value)}.
+
+Append the \a value to the list \a property.
+*/
+
+/*!
+\typedef QDeclarativeListProperty::CountFunction
+
+Synonym for \c {int (*)(QDeclarativeListProperty<T> *property)}.
+
+Return the number of elements in the list \a property.
+*/
+
+/*!
+\fn bool QDeclarativeListProperty::operator==(const QDeclarativeListProperty &other) const
+
+Returns true if this QDeclarativeListProperty is equal to \a other, otherwise false.
+*/
+
+/*!
+\typedef QDeclarativeListProperty::AtFunction
+
+Synonym for \c {T *(*)(QDeclarativeListProperty<T> *property, int index)}.
+
+Return the element at position \a index in the list \a property.
+*/
+
+/*!
+\typedef QDeclarativeListProperty::ClearFunction
+
+Synonym for \c {void (*)(QDeclarativeListProperty<T> *property)}.
+
+Clear the list \a property.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativelist.h b/src/declarative/qml/qdeclarativelist.h
new file mode 100644
index 0000000000..b13fe42c55
--- /dev/null
+++ b/src/declarative/qml/qdeclarativelist.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVELIST_H
+#define QDECLARATIVELIST_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QObject;
+struct QMetaObject;
+
+#ifndef QDECLARATIVELISTPROPERTY
+#define QDECLARATIVELISTPROPERTY
+template<typename T>
+class QDeclarativeListProperty {
+public:
+ typedef void (*AppendFunction)(QDeclarativeListProperty<T> *, T*);
+ typedef int (*CountFunction)(QDeclarativeListProperty<T> *);
+ typedef T *(*AtFunction)(QDeclarativeListProperty<T> *, int);
+ typedef void (*ClearFunction)(QDeclarativeListProperty<T> *);
+
+ QDeclarativeListProperty()
+ : object(0), data(0), append(0), count(0), at(0), clear(0), dummy1(0), dummy2(0) {}
+ QDeclarativeListProperty(QObject *o, QList<T *> &list)
+ : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
+ clear(qlist_clear), dummy1(0), dummy2(0) {}
+ QDeclarativeListProperty(QObject *o, void *d, AppendFunction a, CountFunction c = 0, AtFunction t = 0,
+ ClearFunction r = 0)
+ : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(0), dummy2(0) {}
+
+ bool operator==(const QDeclarativeListProperty &o) const {
+ return object == o.object &&
+ data == o.data &&
+ append == o.append &&
+ count == o.count &&
+ at == o.at &&
+ clear == o.clear;
+ }
+
+ QObject *object;
+ void *data;
+
+ AppendFunction append;
+
+ CountFunction count;
+ AtFunction at;
+
+ ClearFunction clear;
+
+ void *dummy1;
+ void *dummy2;
+
+private:
+ static void qlist_append(QDeclarativeListProperty *p, T *v) {
+ reinterpret_cast<QList<T *> *>(p->data)->append(v);
+ }
+ static int qlist_count(QDeclarativeListProperty *p) {
+ return reinterpret_cast<QList<T *> *>(p->data)->count();
+ }
+ static T *qlist_at(QDeclarativeListProperty *p, int idx) {
+ return reinterpret_cast<QList<T *> *>(p->data)->at(idx);
+ }
+ static void qlist_clear(QDeclarativeListProperty *p) {
+ return reinterpret_cast<QList<T *> *>(p->data)->clear();
+ }
+};
+#endif
+
+class QDeclarativeEngine;
+class QDeclarativeListReferencePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeListReference
+{
+public:
+ QDeclarativeListReference();
+ QDeclarativeListReference(QObject *, const char *property, QDeclarativeEngine * = 0);
+ QDeclarativeListReference(const QDeclarativeListReference &);
+ QDeclarativeListReference &operator=(const QDeclarativeListReference &);
+ ~QDeclarativeListReference();
+
+ bool isValid() const;
+
+ QObject *object() const;
+ const QMetaObject *listElementType() const;
+
+ bool canAppend() const;
+ bool canAt() const;
+ bool canClear() const;
+ bool canCount() const;
+
+ bool append(QObject *) const;
+ QObject *at(int) const;
+ bool clear() const;
+ int count() const;
+
+private:
+ friend class QDeclarativeListReferencePrivate;
+ QDeclarativeListReferencePrivate* d;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeListReference)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELIST_H
diff --git a/src/declarative/qml/qdeclarativelist_p.h b/src/declarative/qml/qdeclarativelist_p.h
new file mode 100644
index 0000000000..b17f84ab15
--- /dev/null
+++ b/src/declarative/qml/qdeclarativelist_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 QDECLARATIVELIST_P_H
+#define QDECLARATIVELIST_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 "qdeclarativelist.h"
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeListReferencePrivate
+{
+public:
+ QDeclarativeListReferencePrivate();
+
+ static QDeclarativeListReference init(const QDeclarativeListProperty<QObject> &, int, QDeclarativeEngine *);
+
+ QDeclarativeGuard<QObject> object;
+ const QMetaObject *elementType;
+ QDeclarativeListProperty<QObject> property;
+ int propertyType;
+
+ void addref();
+ void release();
+ int refCount;
+
+ static inline QDeclarativeListReferencePrivate *get(QDeclarativeListReference *ref) {
+ return ref->d;
+ }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVELIST_P_H
diff --git a/src/declarative/qml/qdeclarativelistscriptclass.cpp b/src/declarative/qml/qdeclarativelistscriptclass.cpp
new file mode 100644
index 0000000000..ace777e6ff
--- /dev/null
+++ b/src/declarative/qml/qdeclarativelistscriptclass.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 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/qdeclarativelistscriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeguard_p.h"
+#include "private/qdeclarativelist_p.h"
+
+QT_BEGIN_NAMESPACE
+
+struct ListData : public QScriptDeclarativeClass::Object {
+ QDeclarativeGuard<QObject> object;
+ QDeclarativeListProperty<QObject> property;
+ int propertyType;
+};
+
+QDeclarativeListScriptClass::QDeclarativeListScriptClass(QDeclarativeEngine *e)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(e)), engine(e)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ Q_UNUSED(scriptEngine);
+
+ m_lengthId = createPersistentIdentifier(QLatin1String("length"));
+}
+
+QDeclarativeListScriptClass::~QDeclarativeListScriptClass()
+{
+}
+
+QScriptValue QDeclarativeListScriptClass::newList(QObject *object, int propId, int propType)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (!object || propId == -1)
+ return scriptEngine->nullValue();
+
+ ListData *data = new ListData;
+ data->object = object;
+ data->propertyType = propType;
+ void *args[] = { &data->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
+
+ return newObject(scriptEngine, this, data);
+}
+
+QScriptValue QDeclarativeListScriptClass::newList(const QDeclarativeListProperty<QObject> &prop, int propType)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ ListData *data = new ListData;
+ data->object = prop.object;
+ data->property = prop;
+ data->propertyType = propType;
+
+ return newObject(scriptEngine, this, data);
+}
+
+QScriptClass::QueryFlags
+QDeclarativeListScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(flags);
+ if (name == m_lengthId.identifier)
+ return QScriptClass::HandlesReadAccess;
+
+ bool ok = false;
+ quint32 idx = toArrayIndex(name, &ok);
+
+ if (ok) {
+ lastIndex = idx;
+ return QScriptClass::HandlesReadAccess;
+ } else {
+ return 0;
+ }
+}
+
+QDeclarativeListScriptClass::Value QDeclarativeListScriptClass::property(Object *obj, const Identifier &name)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+
+ ListData *data = (ListData *)obj;
+ if (!data->object)
+ return Value();
+
+ quint32 count = data->property.count?data->property.count(&data->property):0;
+
+ if (name == m_lengthId.identifier)
+ return Value(scriptEngine, count);
+ else if (lastIndex < count && data->property.at)
+ return Value(scriptEngine, enginePriv->objectClass->newQObject(data->property.at(&data->property, lastIndex)));
+ else
+ return Value();
+}
+
+QVariant QDeclarativeListScriptClass::toVariant(Object *obj, bool *ok)
+{
+ ListData *data = (ListData *)obj;
+
+ if (!data->object) {
+ if (ok) *ok = false;
+ return QVariant();
+ }
+
+ return QVariant::fromValue(QDeclarativeListReferencePrivate::init(data->property, data->propertyType, engine));
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativelistscriptclass_p.h b/src/declarative/qml/qdeclarativelistscriptclass_p.h
new file mode 100644
index 0000000000..005380b92c
--- /dev/null
+++ b/src/declarative/qml/qdeclarativelistscriptclass_p.h
@@ -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 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 QDECLARATIVELISTSCRIPTCLASS_P_H
+#define QDECLARATIVELISTSCRIPTCLASS_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/qscriptdeclarativeclass_p.h>
+#include "qdeclarativelist.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeListScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeListScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeListScriptClass();
+
+ QScriptValue newList(QObject *, int, int);
+ QScriptValue newList(const QDeclarativeListProperty<QObject> &, int);
+
+protected:
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual QVariant toVariant(Object *, bool *ok);
+
+private:
+ PersistentIdentifier m_lengthId;
+ QDeclarativeEngine *engine;
+
+ quint32 lastIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVELISTSCRIPTCLASS_P_H
+
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
new file mode 100644
index 0000000000..bf1f699c72
--- /dev/null
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -0,0 +1,1536 @@
+/****************************************************************************
+**
+** Copyright (C) 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 <QtDeclarative/qdeclarativeprivate.h>
+#include "private/qdeclarativemetatype_p.h"
+
+#include "private/qdeclarativeproxymetaobject_p.h"
+#include "private/qdeclarativecustomparser_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qbitarray.h>
+#include <QtCore/qreadwritelock.h>
+#include <qmetatype.h>
+#include <qobjectdefs.h>
+#include <qdatetime.h>
+#include <qbytearray.h>
+#include <qreadwritelock.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvector.h>
+#include <qlocale.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtScript/qscriptvalue.h>
+
+#include <ctype.h>
+
+#ifdef QT_BOOTSTRAPPED
+# ifndef QT_NO_GEOM_VARIANT
+# define QT_NO_GEOM_VARIANT
+# endif
+#else
+# include <qbitarray.h>
+# include <qurl.h>
+# include <qvariant.h>
+#endif
+
+#ifndef QT_NO_GEOM_VARIANT
+# include <qsize.h>
+# include <qpoint.h>
+# include <qrect.h>
+# include <qline.h>
+# include <qvector3d.h>
+#endif
+#define NS(x) QT_PREPEND_NAMESPACE(x)
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeMetaTypeData
+{
+ ~QDeclarativeMetaTypeData();
+ QList<QDeclarativeType *> types;
+ typedef QHash<int, QDeclarativeType *> Ids;
+ Ids idToType;
+ typedef QHash<QByteArray, QDeclarativeType *> Names;
+ Names nameToType;
+ typedef QHash<const QMetaObject *, QDeclarativeType *> MetaObjects;
+ MetaObjects metaObjectToType;
+ typedef QHash<int, QDeclarativeMetaType::StringConverter> StringConverters;
+ StringConverters stringConverters;
+
+ struct ModuleInfo {
+ ModuleInfo(int major, int minor)
+ : vmajor_min(major), vminor_min(minor), vmajor_max(major), vminor_max(minor) {}
+ ModuleInfo(int major_min, int minor_min, int major_max, int minor_max)
+ : vmajor_min(major_min), vminor_min(minor_min), vmajor_max(major_max), vminor_max(minor_max) {}
+ int vmajor_min, vminor_min;
+ int vmajor_max, vminor_max;
+ };
+ typedef QHash<QByteArray, ModuleInfo> ModuleInfoHash;
+ ModuleInfoHash modules;
+
+ QBitArray objects;
+ QBitArray interfaces;
+ QBitArray lists;
+
+ QList<QDeclarativePrivate::AutoParentFunction> parentFunctions;
+};
+Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData)
+Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+
+QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData()
+{
+ for (int i = 0; i < types.count(); ++i)
+ delete types.at(i);
+}
+
+class QDeclarativeTypePrivate
+{
+public:
+ QDeclarativeTypePrivate();
+
+ void init() const;
+
+ bool m_isInterface : 1;
+ const char *m_iid;
+ QByteArray m_module;
+ QByteArray m_name;
+ int m_version_maj;
+ int m_version_min;
+ int m_typeId; int m_listId;
+ int m_revision;
+ mutable bool m_containsRevisionedAttributes;
+ mutable QDeclarativeType *m_superType;
+
+ int m_allocationSize;
+ void (*m_newFunc)(void *);
+ QString m_noCreationReason;
+
+ const QMetaObject *m_baseMetaObject;
+ QDeclarativeAttachedPropertiesFunc m_attachedPropertiesFunc;
+ const QMetaObject *m_attachedPropertiesType;
+ int m_attachedPropertiesId;
+ int m_parserStatusCast;
+ int m_propertyValueSourceCast;
+ int m_propertyValueInterceptorCast;
+ QObject *(*m_extFunc)(QObject *);
+ const QMetaObject *m_extMetaObject;
+ int m_index;
+ QDeclarativeCustomParser *m_customParser;
+ mutable volatile bool m_isSetup:1;
+ mutable bool m_haveSuperType : 1;
+ mutable QList<QDeclarativeProxyMetaObject::ProxyData> m_metaObjects;
+
+ static QHash<const QMetaObject *, int> m_attachedPropertyIds;
+};
+
+QHash<const QMetaObject *, int> QDeclarativeTypePrivate::m_attachedPropertyIds;
+
+QDeclarativeTypePrivate::QDeclarativeTypePrivate()
+: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false),
+ m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
+ m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
+ m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
+ m_isSetup(false), m_haveSuperType(false)
+{
+}
+
+
+QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::RegisterInterface &interface)
+: d(new QDeclarativeTypePrivate)
+{
+ d->m_isInterface = true;
+ d->m_iid = interface.iid;
+ d->m_typeId = interface.typeId;
+ d->m_listId = interface.listId;
+ d->m_newFunc = 0;
+ d->m_index = index;
+ d->m_isSetup = true;
+ d->m_version_maj = 0;
+ d->m_version_min = 0;
+}
+
+QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::RegisterType &type)
+: d(new QDeclarativeTypePrivate)
+{
+ QByteArray name = type.uri;
+ if (type.uri) name += '/';
+ name += type.elementName;
+
+ d->m_module = type.uri;
+ d->m_name = name;
+ d->m_version_maj = type.versionMajor;
+ d->m_version_min = type.versionMinor;
+ if (type.version >= 1) // revisions added in version 1
+ d->m_revision = type.revision;
+ d->m_typeId = type.typeId;
+ d->m_listId = type.listId;
+ d->m_allocationSize = type.objectSize;
+ d->m_newFunc = type.create;
+ d->m_noCreationReason = type.noCreationReason;
+ d->m_baseMetaObject = type.metaObject;
+ d->m_attachedPropertiesFunc = type.attachedPropertiesFunction;
+ d->m_attachedPropertiesType = type.attachedPropertiesMetaObject;
+ if (d->m_attachedPropertiesType) {
+ QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject);
+ if (iter == d->m_attachedPropertyIds.end())
+ iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index);
+ d->m_attachedPropertiesId = *iter;
+ } else {
+ d->m_attachedPropertiesId = -1;
+ }
+ d->m_parserStatusCast = type.parserStatusCast;
+ d->m_propertyValueSourceCast = type.valueSourceCast;
+ d->m_propertyValueInterceptorCast = type.valueInterceptorCast;
+ d->m_extFunc = type.extensionObjectCreate;
+ d->m_index = index;
+ d->m_customParser = type.customParser;
+
+ if (type.extensionMetaObject)
+ d->m_extMetaObject = type.extensionMetaObject;
+}
+
+QDeclarativeType::~QDeclarativeType()
+{
+ delete d->m_customParser;
+ delete d;
+}
+
+QByteArray QDeclarativeType::module() const
+{
+ return d->m_module;
+}
+
+int QDeclarativeType::majorVersion() const
+{
+ return d->m_version_maj;
+}
+
+int QDeclarativeType::minorVersion() const
+{
+ return d->m_version_min;
+}
+
+bool QDeclarativeType::availableInVersion(int vmajor, int vminor) const
+{
+ return vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min);
+}
+
+bool QDeclarativeType::availableInVersion(const QByteArray &module, int vmajor, int vminor) const
+{
+ return module == d->m_module && (vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min));
+}
+
+// returns the nearest _registered_ super class
+QDeclarativeType *QDeclarativeType::superType() const
+{
+ if (!d->m_haveSuperType) {
+ const QMetaObject *mo = d->m_baseMetaObject->superClass();
+ while (mo && !d->m_superType) {
+ d->m_superType = QDeclarativeMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
+ mo = mo->superClass();
+ }
+ d->m_haveSuperType = true;
+ }
+
+ return d->m_superType;
+}
+
+static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+{
+ // Clone Q_CLASSINFO
+ for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
+ QMetaClassInfo info = mo->classInfo(ii);
+
+ int otherIndex = ignoreEnd->indexOfClassInfo(info.name());
+ if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
+ // Skip
+ } else {
+ builder.addClassInfo(info.name(), info.value());
+ }
+ }
+
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
+
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
+ }
+
+ // Clone Q_METHODS
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
+
+ // More complex - need to search name
+ QByteArray name = method.signature();
+ int parenIdx = name.indexOf('(');
+ if (parenIdx != -1) name = name.left(parenIdx);
+
+
+ bool found = false;
+
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
+ ++ii) {
+
+ QMetaMethod other = ignoreEnd->method(ii);
+ QByteArray othername = other.signature();
+ int parenIdx = othername.indexOf('(');
+ if (parenIdx != -1) othername = othername.left(parenIdx);
+
+ found = name == othername;
+ }
+
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
+
+ // Clone Q_ENUMS
+ for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = mo->enumerator(ii);
+
+ int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name());
+ if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
+ // Skip
+ } else {
+ builder.addEnumerator(enumerator);
+ }
+ }
+}
+
+void QDeclarativeTypePrivate::init() const
+{
+ if (m_isSetup) return;
+
+ QWriteLocker lock(metaTypeDataLock());
+ if (m_isSetup)
+ return;
+
+ // Setup extended meta object
+ // XXX - very inefficient
+ const QMetaObject *mo = m_baseMetaObject;
+ if (m_extFunc) {
+ QMetaObject *mmo = new QMetaObject;
+ *mmo = *m_extMetaObject;
+ mmo->d.superdata = mo;
+ QDeclarativeProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 };
+ m_metaObjects << data;
+ }
+
+ mo = mo->d.superdata;
+ while(mo) {
+ QDeclarativeType *t = metaTypeData()->metaObjectToType.value(mo);
+ if (t) {
+ if (t->d->m_extFunc) {
+ QMetaObjectBuilder builder;
+ clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = m_baseMetaObject;
+ if (!m_metaObjects.isEmpty())
+ m_metaObjects.last().metaObject->d.superdata = mmo;
+ QDeclarativeProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 };
+ m_metaObjects << data;
+ }
+ }
+ mo = mo->d.superdata;
+ }
+
+ for (int ii = 0; ii < m_metaObjects.count(); ++ii) {
+ m_metaObjects[ii].propertyOffset =
+ m_metaObjects.at(ii).metaObject->propertyOffset();
+ m_metaObjects[ii].methodOffset =
+ m_metaObjects.at(ii).metaObject->methodOffset();
+ }
+
+ // Check for revisioned details
+ {
+ const QMetaObject *mo = 0;
+ if (m_metaObjects.isEmpty())
+ mo = m_baseMetaObject;
+ else
+ mo = m_metaObjects.first().metaObject;
+
+ for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
+ if (mo->property(ii).revision() != 0)
+ m_containsRevisionedAttributes = true;
+ }
+
+ for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
+ if (mo->method(ii).revision() != 0)
+ m_containsRevisionedAttributes = true;
+ }
+ }
+
+ m_isSetup = true;
+ lock.unlock();
+}
+
+QByteArray QDeclarativeType::typeName() const
+{
+ if (d->m_baseMetaObject)
+ return d->m_baseMetaObject->className();
+ else
+ return QByteArray();
+}
+
+QByteArray QDeclarativeType::qmlTypeName() const
+{
+ return d->m_name;
+}
+
+QObject *QDeclarativeType::create() const
+{
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->m_allocationSize);
+ d->m_newFunc(rv);
+
+ if (rv && !d->m_metaObjects.isEmpty())
+ (void *)new QDeclarativeProxyMetaObject(rv, &d->m_metaObjects);
+
+ return rv;
+}
+
+void QDeclarativeType::create(QObject **out, void **memory, size_t additionalMemory) const
+{
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory);
+ d->m_newFunc(rv);
+
+ if (rv && !d->m_metaObjects.isEmpty())
+ (void *)new QDeclarativeProxyMetaObject(rv, &d->m_metaObjects);
+
+ *out = rv;
+ *memory = ((char *)rv) + d->m_allocationSize;
+}
+
+QDeclarativeCustomParser *QDeclarativeType::customParser() const
+{
+ return d->m_customParser;
+}
+
+QDeclarativeType::CreateFunc QDeclarativeType::createFunction() const
+{
+ return d->m_newFunc;
+}
+
+QString QDeclarativeType::noCreationReason() const
+{
+ return d->m_noCreationReason;
+}
+
+int QDeclarativeType::createSize() const
+{
+ return d->m_allocationSize;
+}
+
+bool QDeclarativeType::isCreatable() const
+{
+ return d->m_newFunc != 0;
+}
+
+bool QDeclarativeType::isExtendedType() const
+{
+ d->init();
+
+ return !d->m_metaObjects.isEmpty();
+}
+
+bool QDeclarativeType::isInterface() const
+{
+ return d->m_isInterface;
+}
+
+int QDeclarativeType::typeId() const
+{
+ return d->m_typeId;
+}
+
+int QDeclarativeType::qListTypeId() const
+{
+ return d->m_listId;
+}
+
+const QMetaObject *QDeclarativeType::metaObject() const
+{
+ d->init();
+
+ if (d->m_metaObjects.isEmpty())
+ return d->m_baseMetaObject;
+ else
+ return d->m_metaObjects.first().metaObject;
+
+}
+
+const QMetaObject *QDeclarativeType::baseMetaObject() const
+{
+ return d->m_baseMetaObject;
+}
+
+bool QDeclarativeType::containsRevisionedAttributes() const
+{
+ d->init();
+
+ return d->m_containsRevisionedAttributes;
+}
+
+int QDeclarativeType::metaObjectRevision() const
+{
+ return d->m_revision;
+}
+
+QDeclarativeAttachedPropertiesFunc QDeclarativeType::attachedPropertiesFunction() const
+{
+ return d->m_attachedPropertiesFunc;
+}
+
+const QMetaObject *QDeclarativeType::attachedPropertiesType() const
+{
+ return d->m_attachedPropertiesType;
+}
+
+/*
+This is the id passed to qmlAttachedPropertiesById(). This is different from the index
+for the case that a single class is registered under two or more names (eg. Item in
+Qt 4.7 and QtQuick 1.0).
+*/
+int QDeclarativeType::attachedPropertiesId() const
+{
+ return d->m_attachedPropertiesId;
+}
+
+int QDeclarativeType::parserStatusCast() const
+{
+ return d->m_parserStatusCast;
+}
+
+int QDeclarativeType::propertyValueSourceCast() const
+{
+ return d->m_propertyValueSourceCast;
+}
+
+int QDeclarativeType::propertyValueInterceptorCast() const
+{
+ return d->m_propertyValueInterceptorCast;
+}
+
+const char *QDeclarativeType::interfaceIId() const
+{
+ return d->m_iid;
+}
+
+int QDeclarativeType::index() const
+{
+ return d->m_index;
+}
+
+int registerAutoParentFunction(QDeclarativePrivate::RegisterAutoParent &autoparent)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ data->parentFunctions.append(autoparent.function);
+
+ return data->parentFunctions.count() - 1;
+}
+
+int registerInterface(const QDeclarativePrivate::RegisterInterface &interface)
+{
+ if (interface.version > 0)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
+ QWriteLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ int index = data->types.count();
+
+ QDeclarativeType *type = new QDeclarativeType(index, interface);
+
+ data->types.append(type);
+ data->idToType.insert(type->typeId(), type);
+ data->idToType.insert(type->qListTypeId(), type);
+ // XXX No insertMulti, so no multi-version interfaces?
+ if (!type->qmlTypeName().isEmpty())
+ data->nameToType.insert(type->qmlTypeName(), type);
+
+ if (data->interfaces.size() <= interface.typeId)
+ data->interfaces.resize(interface.typeId + 16);
+ if (data->lists.size() <= interface.listId)
+ data->lists.resize(interface.listId + 16);
+ data->interfaces.setBit(interface.typeId, true);
+ data->lists.setBit(interface.listId, true);
+
+ return index;
+}
+
+int registerType(const QDeclarativePrivate::RegisterType &type)
+{
+ if (type.elementName) {
+ for (int ii = 0; type.elementName[ii]; ++ii) {
+ if (!isalnum(type.elementName[ii])) {
+ qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
+ return -1;
+ }
+ }
+ }
+
+ QWriteLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ int index = data->types.count();
+
+ QDeclarativeType *dtype = new QDeclarativeType(index, type);
+
+ data->types.append(dtype);
+ data->idToType.insert(dtype->typeId(), dtype);
+ if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
+
+ if (!dtype->qmlTypeName().isEmpty())
+ data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
+
+ data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+
+ if (data->objects.size() <= type.typeId)
+ data->objects.resize(type.typeId + 16);
+ if (data->lists.size() <= type.listId)
+ data->lists.resize(type.listId + 16);
+ data->objects.setBit(type.typeId, true);
+ if (type.listId) data->lists.setBit(type.listId, true);
+
+ if (type.uri) {
+ QByteArray mod(type.uri);
+ QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(mod);
+ if (it == data->modules.end()) {
+ // New module
+ data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo(type.versionMajor,type.versionMinor));
+ } else if ((*it).vmajor_max < type.versionMajor || ((*it).vmajor_max == type.versionMajor && (*it).vminor_max < type.versionMinor)) {
+ // Newer module
+ data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo((*it).vmajor_min, (*it).vminor_min, type.versionMajor, type.versionMinor));
+ } else if ((*it).vmajor_min > type.versionMajor || ((*it).vmajor_min == type.versionMajor && (*it).vminor_min > type.versionMinor)) {
+ // Older module
+ data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo(type.versionMajor, type.versionMinor, (*it).vmajor_min, (*it).vminor_min));
+ }
+ }
+
+ return index;
+}
+
+/*
+This method is "over generalized" to allow us to (potentially) register more types of things in
+the future without adding exported symbols.
+*/
+int QDeclarativePrivate::qmlregister(RegistrationType type, void *data)
+{
+ if (type == TypeRegistration) {
+ return registerType(*reinterpret_cast<RegisterType *>(data));
+ } else if (type == InterfaceRegistration) {
+ return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
+ } else if (type == AutoParentRegistration) {
+ return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(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.
+
+ 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.
+
+ Passing -1 for both \a versionMajor \a versionMinor will return true if any version is installed.
+*/
+bool QDeclarativeMetaType::isModule(const QByteArray &module, int versionMajor, int versionMinor)
+{
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(module);
+ return 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))));
+}
+
+QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunctions()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return data->parentFunctions;
+}
+
+QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok)
+{
+ if (!isQObject(v.userType())) {
+ if (ok) *ok = false;
+ return 0;
+ }
+
+ if (ok) *ok = true;
+
+ return *(QObject **)v.constData();
+}
+
+bool QDeclarativeMetaType::isQObject(int userType)
+{
+ if (userType == QMetaType::QObjectStar)
+ return true;
+
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
+}
+
+/*
+ Returns the item type for a list of type \a id.
+ */
+int QDeclarativeMetaType::listType(int id)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QDeclarativeType *type = data->idToType.value(id);
+ if (type && type->qListTypeId() == id)
+ return type->typeId();
+ else
+ return 0;
+}
+
+int QDeclarativeMetaType::attachedPropertiesFuncId(const QMetaObject *mo)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeType *type = data->metaObjectToType.value(mo);
+ if (type && type->attachedPropertiesFunction())
+ return type->attachedPropertiesId();
+ else
+ return -1;
+}
+
+QDeclarativeAttachedPropertiesFunc QDeclarativeMetaType::attachedPropertiesFuncById(int id)
+{
+ if (id < 0)
+ return 0;
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return data->types.at(id)->attachedPropertiesFunction();
+}
+
+QMetaProperty QDeclarativeMetaType::defaultProperty(const QMetaObject *metaObject)
+{
+ int idx = metaObject->indexOfClassInfo("DefaultProperty");
+ if (-1 == idx)
+ return QMetaProperty();
+
+ QMetaClassInfo info = metaObject->classInfo(idx);
+ if (!info.value())
+ return QMetaProperty();
+
+ idx = metaObject->indexOfProperty(info.value());
+ if (-1 == idx)
+ return QMetaProperty();
+
+ return metaObject->property(idx);
+}
+
+QMetaProperty QDeclarativeMetaType::defaultProperty(QObject *obj)
+{
+ if (!obj)
+ return QMetaProperty();
+
+ const QMetaObject *metaObject = obj->metaObject();
+ return defaultProperty(metaObject);
+}
+
+QMetaMethod QDeclarativeMetaType::defaultMethod(const QMetaObject *metaObject)
+{
+ int idx = metaObject->indexOfClassInfo("DefaultMethod");
+ if (-1 == idx)
+ return QMetaMethod();
+
+ QMetaClassInfo info = metaObject->classInfo(idx);
+ if (!info.value())
+ return QMetaMethod();
+
+ idx = metaObject->indexOfMethod(info.value());
+ if (-1 == idx)
+ return QMetaMethod();
+
+ return metaObject->method(idx);
+}
+
+QMetaMethod QDeclarativeMetaType::defaultMethod(QObject *obj)
+{
+ if (!obj)
+ return QMetaMethod();
+
+ const QMetaObject *metaObject = obj->metaObject();
+ return defaultMethod(metaObject);
+}
+
+QDeclarativeMetaType::TypeCategory QDeclarativeMetaType::typeCategory(int userType)
+{
+ if (userType < 0)
+ return Unknown;
+ if (userType == QMetaType::QObjectStar)
+ return Object;
+
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ if (userType < data->objects.size() && data->objects.testBit(userType))
+ return Object;
+ else if (userType < data->lists.size() && data->lists.testBit(userType))
+ return List;
+ else
+ return Unknown;
+}
+
+bool QDeclarativeMetaType::isInterface(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
+}
+
+const char *QDeclarativeMetaType::interfaceIId(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ QDeclarativeType *type = data->idToType.value(userType);
+ lock.unlock();
+ if (type && type->isInterface() && type->typeId() == userType)
+ return type->interfaceIId();
+ else
+ return 0;
+}
+
+bool QDeclarativeMetaType::isList(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
+}
+
+/*!
+ A custom string convertor allows you to specify a function pointer that
+ returns a variant of \a type. For example, if you have written your own icon
+ class that you want to support as an object property assignable in QML:
+
+ \code
+ int type = qRegisterMetaType<SuperIcon>("SuperIcon");
+ QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
+ \endcode
+
+ The function pointer must be of the form:
+ \code
+ QVariant (*StringConverter)(const QString &);
+ \endcode
+ */
+void QDeclarativeMetaType::registerCustomStringConverter(int type, StringConverter converter)
+{
+ QWriteLocker lock(metaTypeDataLock());
+
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ if (data->stringConverters.contains(type))
+ return;
+ data->stringConverters.insert(type, converter);
+}
+
+/*!
+ Return the custom string converter for \a type, previously installed through
+ registerCustomStringConverter()
+ */
+QDeclarativeMetaType::StringConverter QDeclarativeMetaType::customStringConverter(int type)
+{
+ QReadLocker lock(metaTypeDataLock());
+
+ QDeclarativeMetaTypeData *data = metaTypeData();
+ return data->stringConverters.value(type);
+}
+
+/*!
+ Returns the type (if any) of URI-qualified named \a name in version specified
+ by \a version_major and \a version_minor.
+*/
+QDeclarativeType *QDeclarativeMetaType::qmlType(const QByteArray &name, int version_major, int version_minor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QList<QDeclarativeType*> types = data->nameToType.values(name);
+ foreach (QDeclarativeType *t, types) {
+ // XXX version_major<0 just a kludge for QDeclarativePropertyPrivate::initProperty
+ if (version_major<0 || t->availableInVersion(version_major,version_minor))
+ return t;
+ }
+ return 0;
+}
+
+/*!
+ Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
+ type is registered.
+*/
+QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ return data->metaObjectToType.value(metaObject);
+}
+
+/*!
+ Returns the type (if any) that corresponds to the \a metaObject in version specified
+ by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
+ type is registered.
+*/
+QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject);
+ while (it != data->metaObjectToType.end() && it.key() == metaObject) {
+ QDeclarativeType *t = *it;
+ if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
+ return t;
+ ++it;
+ }
+
+ return 0;
+}
+
+/*!
+ Returns the type (if any) that corresponds to the QVariant::Type \a userType.
+ Returns null if no type is registered.
+*/
+QDeclarativeType *QDeclarativeMetaType::qmlType(int userType)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ QDeclarativeType *type = data->idToType.value(userType);
+ if (type && type->typeId() == userType)
+ return type;
+ else
+ return 0;
+}
+
+/*!
+ Returns the list of registered QML type names.
+*/
+QList<QByteArray> QDeclarativeMetaType::qmlTypeNames()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ return data->nameToType.keys();
+}
+
+/*!
+ Returns the list of registered QML types.
+*/
+QList<QDeclarativeType*> QDeclarativeMetaType::qmlTypes()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QDeclarativeMetaTypeData *data = metaTypeData();
+
+ return data->nameToType.values();
+}
+
+QT_END_NAMESPACE
+
+#include <QtGui/qfont.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qbrush.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qpolygon.h>
+#include <QtGui/qregion.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qcursor.h>
+#include <QtGui/qsizepolicy.h>
+#include <QtGui/qkeysequence.h>
+#include <QtGui/qpen.h>
+
+//#include <QtGui/qtextlength.h>
+#include <QtGui/qtextformat.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qtransform.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qquaternion.h>
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+QT_BEGIN_NAMESPACE
+
+bool QDeclarativeMetaType::canCopy(int type)
+{
+ switch(type) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ case QMetaType::Long:
+ case QMetaType::Int:
+ case QMetaType::Short:
+ case QMetaType::Char:
+ case QMetaType::ULong:
+ case QMetaType::UInt:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QMetaType::Bool:
+ case QMetaType::Float:
+ case QMetaType::Double:
+ case QMetaType::QChar:
+ case QMetaType::QVariantMap:
+ case QMetaType::QVariantHash:
+ case QMetaType::QVariantList:
+ case QMetaType::QByteArray:
+ case QMetaType::QString:
+ case QMetaType::QStringList:
+ case QMetaType::QBitArray:
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ case QMetaType::QDateTime:
+ case QMetaType::QUrl:
+ case QMetaType::QLocale:
+ case QMetaType::QRect:
+ case QMetaType::QRectF:
+ case QMetaType::QSize:
+ case QMetaType::QSizeF:
+ case QMetaType::QLine:
+ case QMetaType::QLineF:
+ case QMetaType::QPoint:
+ case QMetaType::QPointF:
+ case QMetaType::QVector3D:
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+#endif
+ case QMetaType::Void:
+#ifdef QT3_SUPPORT
+ case QMetaType::QColorGroup:
+#endif
+ case QMetaType::QFont:
+ case QMetaType::QPixmap:
+ case QMetaType::QBrush:
+ case QMetaType::QColor:
+ case QMetaType::QPalette:
+ case QMetaType::QIcon:
+ case QMetaType::QImage:
+ case QMetaType::QPolygon:
+ case QMetaType::QRegion:
+ case QMetaType::QBitmap:
+#ifndef QT_NO_CURSOR
+ case QMetaType::QCursor:
+#endif
+ case QMetaType::QSizePolicy:
+ case QMetaType::QKeySequence:
+ case QMetaType::QPen:
+ case QMetaType::QTextLength:
+ case QMetaType::QTextFormat:
+ case QMetaType::QMatrix:
+ case QMetaType::QTransform:
+ case QMetaType::QMatrix4x4:
+ case QMetaType::QVector2D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion:
+ return true;
+
+ default:
+ if (type == qMetaTypeId<QVariant>() ||
+ type == qMetaTypeId<QScriptValue>() ||
+ typeCategory(type) != Unknown) {
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+/*!
+ Copies \a copy into \a data, assuming they both are of type \a type. If
+ \a copy is zero, a default type is copied. Returns true if the copy was
+ successful and false if not.
+
+ \note This should move into QMetaType once complete
+
+*/
+bool QDeclarativeMetaType::copy(int type, void *data, const void *copy)
+{
+ if (copy) {
+ switch(type) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ *static_cast<void **>(data) = *static_cast<void* const *>(copy);
+ return true;
+ case QMetaType::Long:
+ *static_cast<long *>(data) = *static_cast<const long*>(copy);
+ return true;
+ case QMetaType::Int:
+ *static_cast<int *>(data) = *static_cast<const int*>(copy);
+ return true;
+ case QMetaType::Short:
+ *static_cast<short *>(data) = *static_cast<const short*>(copy);
+ return true;
+ case QMetaType::Char:
+ *static_cast<char *>(data) = *static_cast<const char*>(copy);
+ return true;
+ case QMetaType::ULong:
+ *static_cast<ulong *>(data) = *static_cast<const ulong*>(copy);
+ return true;
+ case QMetaType::UInt:
+ *static_cast<uint *>(data) = *static_cast<const uint*>(copy);
+ return true;
+ case QMetaType::LongLong:
+ *static_cast<qlonglong *>(data) = *static_cast<const qlonglong*>(copy);
+ return true;
+ case QMetaType::ULongLong:
+ *static_cast<qulonglong *>(data) = *static_cast<const qulonglong*>(copy);
+ return true;
+ case QMetaType::UShort:
+ *static_cast<ushort *>(data) = *static_cast<const ushort*>(copy);
+ return true;
+ case QMetaType::UChar:
+ *static_cast<uchar *>(data) = *static_cast<const uchar*>(copy);
+ return true;
+ case QMetaType::Bool:
+ *static_cast<bool *>(data) = *static_cast<const bool*>(copy);
+ return true;
+ case QMetaType::Float:
+ *static_cast<float *>(data) = *static_cast<const float*>(copy);
+ return true;
+ case QMetaType::Double:
+ *static_cast<double *>(data) = *static_cast<const double*>(copy);
+ return true;
+ case QMetaType::QChar:
+ *static_cast<NS(QChar) *>(data) = *static_cast<const NS(QChar)*>(copy);
+ return true;
+ case QMetaType::QVariantMap:
+ *static_cast<NS(QVariantMap) *>(data) = *static_cast<const NS(QVariantMap)*>(copy);
+ return true;
+ case QMetaType::QVariantHash:
+ *static_cast<NS(QVariantHash) *>(data) = *static_cast<const NS(QVariantHash)*>(copy);
+ return true;
+ case QMetaType::QVariantList:
+ *static_cast<NS(QVariantList) *>(data) = *static_cast<const NS(QVariantList)*>(copy);
+ return true;
+ case QMetaType::QByteArray:
+ *static_cast<NS(QByteArray) *>(data) = *static_cast<const NS(QByteArray)*>(copy);
+ return true;
+ case QMetaType::QString:
+ *static_cast<NS(QString) *>(data) = *static_cast<const NS(QString)*>(copy);
+ return true;
+ case QMetaType::QStringList:
+ *static_cast<NS(QStringList) *>(data) = *static_cast<const NS(QStringList)*>(copy);
+ return true;
+ case QMetaType::QBitArray:
+ *static_cast<NS(QBitArray) *>(data) = *static_cast<const NS(QBitArray)*>(copy);
+ return true;
+ case QMetaType::QDate:
+ *static_cast<NS(QDate) *>(data) = *static_cast<const NS(QDate)*>(copy);
+ return true;
+ case QMetaType::QTime:
+ *static_cast<NS(QTime) *>(data) = *static_cast<const NS(QTime)*>(copy);
+ return true;
+ case QMetaType::QDateTime:
+ *static_cast<NS(QDateTime) *>(data) = *static_cast<const NS(QDateTime)*>(copy);
+ return true;
+ case QMetaType::QUrl:
+ *static_cast<NS(QUrl) *>(data) = *static_cast<const NS(QUrl)*>(copy);
+ return true;
+ case QMetaType::QLocale:
+ *static_cast<NS(QLocale) *>(data) = *static_cast<const NS(QLocale)*>(copy);
+ return true;
+ case QMetaType::QRect:
+ *static_cast<NS(QRect) *>(data) = *static_cast<const NS(QRect)*>(copy);
+ return true;
+ case QMetaType::QRectF:
+ *static_cast<NS(QRectF) *>(data) = *static_cast<const NS(QRectF)*>(copy);
+ return true;
+ case QMetaType::QSize:
+ *static_cast<NS(QSize) *>(data) = *static_cast<const NS(QSize)*>(copy);
+ return true;
+ case QMetaType::QSizeF:
+ *static_cast<NS(QSizeF) *>(data) = *static_cast<const NS(QSizeF)*>(copy);
+ return true;
+ case QMetaType::QLine:
+ *static_cast<NS(QLine) *>(data) = *static_cast<const NS(QLine)*>(copy);
+ return true;
+ case QMetaType::QLineF:
+ *static_cast<NS(QLineF) *>(data) = *static_cast<const NS(QLineF)*>(copy);
+ return true;
+ case QMetaType::QPoint:
+ *static_cast<NS(QPoint) *>(data) = *static_cast<const NS(QPoint)*>(copy);
+ return true;
+ case QMetaType::QPointF:
+ *static_cast<NS(QPointF) *>(data) = *static_cast<const NS(QPointF)*>(copy);
+ return true;
+ case QMetaType::QVector3D:
+ *static_cast<NS(QVector3D) *>(data) = *static_cast<const NS(QVector3D)*>(copy);
+ return true;
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ *static_cast<NS(QRegExp) *>(data) = *static_cast<const NS(QRegExp)*>(copy);
+ return true;
+#endif
+ case QMetaType::Void:
+ return true;
+
+
+#ifdef QT3_SUPPORT
+ case QMetaType::QColorGroup:
+ *static_cast<NS(QColorGroup) *>(data) = *static_cast<const NS(QColorGroup)*>(copy);
+ return true;
+#endif
+
+ case QMetaType::QFont:
+ *static_cast<NS(QFont) *>(data) = *static_cast<const NS(QFont)*>(copy);
+ return true;
+ case QMetaType::QPixmap:
+ *static_cast<NS(QPixmap) *>(data) = *static_cast<const NS(QPixmap)*>(copy);
+ return true;
+ case QMetaType::QBrush:
+ *static_cast<NS(QBrush) *>(data) = *static_cast<const NS(QBrush)*>(copy);
+ return true;
+ case QMetaType::QColor:
+ *static_cast<NS(QColor) *>(data) = *static_cast<const NS(QColor)*>(copy);
+ return true;
+ case QMetaType::QPalette:
+ *static_cast<NS(QPalette) *>(data) = *static_cast<const NS(QPalette)*>(copy);
+ return true;
+ case QMetaType::QIcon:
+ *static_cast<NS(QIcon) *>(data) = *static_cast<const NS(QIcon)*>(copy);
+ return true;
+ case QMetaType::QImage:
+ *static_cast<NS(QImage) *>(data) = *static_cast<const NS(QImage)*>(copy);
+ return true;
+ case QMetaType::QPolygon:
+ *static_cast<NS(QPolygon) *>(data) = *static_cast<const NS(QPolygon)*>(copy);
+ return true;
+ case QMetaType::QRegion:
+ *static_cast<NS(QRegion) *>(data) = *static_cast<const NS(QRegion)*>(copy);
+ return true;
+ case QMetaType::QBitmap:
+ *static_cast<NS(QBitmap) *>(data) = *static_cast<const NS(QBitmap)*>(copy);
+ return true;
+#ifndef QT_NO_CURSOR
+ case QMetaType::QCursor:
+ *static_cast<NS(QCursor) *>(data) = *static_cast<const NS(QCursor)*>(copy);
+ return true;
+#endif
+ case QMetaType::QSizePolicy:
+ *static_cast<NS(QSizePolicy) *>(data) = *static_cast<const NS(QSizePolicy)*>(copy);
+ return true;
+ case QMetaType::QKeySequence:
+ *static_cast<NS(QKeySequence) *>(data) = *static_cast<const NS(QKeySequence)*>(copy);
+ return true;
+ case QMetaType::QPen:
+ *static_cast<NS(QPen) *>(data) = *static_cast<const NS(QPen)*>(copy);
+ return true;
+ case QMetaType::QTextLength:
+ *static_cast<NS(QTextLength) *>(data) = *static_cast<const NS(QTextLength)*>(copy);
+ return true;
+ case QMetaType::QTextFormat:
+ *static_cast<NS(QTextFormat) *>(data) = *static_cast<const NS(QTextFormat)*>(copy);
+ return true;
+ case QMetaType::QMatrix:
+ *static_cast<NS(QMatrix) *>(data) = *static_cast<const NS(QMatrix)*>(copy);
+ return true;
+ case QMetaType::QTransform:
+ *static_cast<NS(QTransform) *>(data) = *static_cast<const NS(QTransform)*>(copy);
+ return true;
+ case QMetaType::QMatrix4x4:
+ *static_cast<NS(QMatrix4x4) *>(data) = *static_cast<const NS(QMatrix4x4)*>(copy);
+ return true;
+ case QMetaType::QVector2D:
+ *static_cast<NS(QVector2D) *>(data) = *static_cast<const NS(QVector2D)*>(copy);
+ return true;
+ case QMetaType::QVector4D:
+ *static_cast<NS(QVector4D) *>(data) = *static_cast<const NS(QVector4D)*>(copy);
+ return true;
+ case QMetaType::QQuaternion:
+ *static_cast<NS(QQuaternion) *>(data) = *static_cast<const NS(QQuaternion)*>(copy);
+ return true;
+
+ default:
+ if (type == qMetaTypeId<QVariant>()) {
+ *static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy);
+ return true;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy);
+ return true;
+ } else if (typeCategory(type) != Unknown) {
+ *static_cast<void **>(data) = *static_cast<void* const *>(copy);
+ return true;
+ }
+ break;
+ }
+ } else {
+ switch(type) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ *static_cast<void **>(data) = 0;
+ return true;
+ case QMetaType::Long:
+ *static_cast<long *>(data) = long(0);
+ return true;
+ case QMetaType::Int:
+ *static_cast<int *>(data) = int(0);
+ return true;
+ case QMetaType::Short:
+ *static_cast<short *>(data) = short(0);
+ return true;
+ case QMetaType::Char:
+ *static_cast<char *>(data) = char(0);
+ return true;
+ case QMetaType::ULong:
+ *static_cast<ulong *>(data) = ulong(0);
+ return true;
+ case QMetaType::UInt:
+ *static_cast<uint *>(data) = uint(0);
+ return true;
+ case QMetaType::LongLong:
+ *static_cast<qlonglong *>(data) = qlonglong(0);
+ return true;
+ case QMetaType::ULongLong:
+ *static_cast<qulonglong *>(data) = qulonglong(0);
+ return true;
+ case QMetaType::UShort:
+ *static_cast<ushort *>(data) = ushort(0);
+ return true;
+ case QMetaType::UChar:
+ *static_cast<uchar *>(data) = uchar(0);
+ return true;
+ case QMetaType::Bool:
+ *static_cast<bool *>(data) = bool(false);
+ return true;
+ case QMetaType::Float:
+ *static_cast<float *>(data) = float(0);
+ return true;
+ case QMetaType::Double:
+ *static_cast<double *>(data) = double(0);
+ return true;
+ case QMetaType::QChar:
+ *static_cast<NS(QChar) *>(data) = NS(QChar)();
+ return true;
+ case QMetaType::QVariantMap:
+ *static_cast<NS(QVariantMap) *>(data) = NS(QVariantMap)();
+ return true;
+ case QMetaType::QVariantHash:
+ *static_cast<NS(QVariantHash) *>(data) = NS(QVariantHash)();
+ return true;
+ case QMetaType::QVariantList:
+ *static_cast<NS(QVariantList) *>(data) = NS(QVariantList)();
+ return true;
+ case QMetaType::QByteArray:
+ *static_cast<NS(QByteArray) *>(data) = NS(QByteArray)();
+ return true;
+ case QMetaType::QString:
+ *static_cast<NS(QString) *>(data) = NS(QString)();
+ return true;
+ case QMetaType::QStringList:
+ *static_cast<NS(QStringList) *>(data) = NS(QStringList)();
+ return true;
+ case QMetaType::QBitArray:
+ *static_cast<NS(QBitArray) *>(data) = NS(QBitArray)();
+ return true;
+ case QMetaType::QDate:
+ *static_cast<NS(QDate) *>(data) = NS(QDate)();
+ return true;
+ case QMetaType::QTime:
+ *static_cast<NS(QTime) *>(data) = NS(QTime)();
+ return true;
+ case QMetaType::QDateTime:
+ *static_cast<NS(QDateTime) *>(data) = NS(QDateTime)();
+ return true;
+ case QMetaType::QUrl:
+ *static_cast<NS(QUrl) *>(data) = NS(QUrl)();
+ return true;
+ case QMetaType::QLocale:
+ *static_cast<NS(QLocale) *>(data) = NS(QLocale)();
+ return true;
+ case QMetaType::QRect:
+ *static_cast<NS(QRect) *>(data) = NS(QRect)();
+ return true;
+ case QMetaType::QRectF:
+ *static_cast<NS(QRectF) *>(data) = NS(QRectF)();
+ return true;
+ case QMetaType::QSize:
+ *static_cast<NS(QSize) *>(data) = NS(QSize)();
+ return true;
+ case QMetaType::QSizeF:
+ *static_cast<NS(QSizeF) *>(data) = NS(QSizeF)();
+ return true;
+ case QMetaType::QLine:
+ *static_cast<NS(QLine) *>(data) = NS(QLine)();
+ return true;
+ case QMetaType::QLineF:
+ *static_cast<NS(QLineF) *>(data) = NS(QLineF)();
+ return true;
+ case QMetaType::QPoint:
+ *static_cast<NS(QPoint) *>(data) = NS(QPoint)();
+ return true;
+ case QMetaType::QPointF:
+ *static_cast<NS(QPointF) *>(data) = NS(QPointF)();
+ return true;
+ case QMetaType::QVector3D:
+ *static_cast<NS(QVector3D) *>(data) = NS(QVector3D)();
+ return true;
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ *static_cast<NS(QRegExp) *>(data) = NS(QRegExp)();
+ return true;
+#endif
+ case QMetaType::Void:
+ return true;
+
+#ifdef QT3_SUPPORT
+ case QMetaType::QColorGroup:
+ *static_cast<NS(QColorGroup) *>(data) = NS(QColorGroup)();
+ return true;
+#endif
+
+ case QMetaType::QFont:
+ *static_cast<NS(QFont) *>(data) = NS(QFont)();
+ return true;
+ case QMetaType::QPixmap:
+ *static_cast<NS(QPixmap) *>(data) = NS(QPixmap)();
+ return true;
+ case QMetaType::QBrush:
+ *static_cast<NS(QBrush) *>(data) = NS(QBrush)();
+ return true;
+ case QMetaType::QColor:
+ *static_cast<NS(QColor) *>(data) = NS(QColor)();
+ return true;
+ case QMetaType::QPalette:
+ *static_cast<NS(QPalette) *>(data) = NS(QPalette)();
+ return true;
+ case QMetaType::QIcon:
+ *static_cast<NS(QIcon) *>(data) = NS(QIcon)();
+ return true;
+ case QMetaType::QImage:
+ *static_cast<NS(QImage) *>(data) = NS(QImage)();
+ return true;
+ case QMetaType::QPolygon:
+ *static_cast<NS(QPolygon) *>(data) = NS(QPolygon)();
+ return true;
+ case QMetaType::QRegion:
+ *static_cast<NS(QRegion) *>(data) = NS(QRegion)();
+ return true;
+ case QMetaType::QBitmap:
+ *static_cast<NS(QBitmap) *>(data) = NS(QBitmap)();
+ return true;
+#ifndef QT_NO_CURSOR
+ case QMetaType::QCursor:
+ *static_cast<NS(QCursor) *>(data) = NS(QCursor)();
+ return true;
+#endif
+ case QMetaType::QSizePolicy:
+ *static_cast<NS(QSizePolicy) *>(data) = NS(QSizePolicy)();
+ return true;
+ case QMetaType::QKeySequence:
+ *static_cast<NS(QKeySequence) *>(data) = NS(QKeySequence)();
+ return true;
+ case QMetaType::QPen:
+ *static_cast<NS(QPen) *>(data) = NS(QPen)();
+ return true;
+ case QMetaType::QTextLength:
+ *static_cast<NS(QTextLength) *>(data) = NS(QTextLength)();
+ return true;
+ case QMetaType::QTextFormat:
+ *static_cast<NS(QTextFormat) *>(data) = NS(QTextFormat)();
+ return true;
+ case QMetaType::QMatrix:
+ *static_cast<NS(QMatrix) *>(data) = NS(QMatrix)();
+ return true;
+ case QMetaType::QTransform:
+ *static_cast<NS(QTransform) *>(data) = NS(QTransform)();
+ return true;
+ case QMetaType::QMatrix4x4:
+ *static_cast<NS(QMatrix4x4) *>(data) = NS(QMatrix4x4)();
+ return true;
+ case QMetaType::QVector2D:
+ *static_cast<NS(QVector2D) *>(data) = NS(QVector2D)();
+ return true;
+ case QMetaType::QVector4D:
+ *static_cast<NS(QVector4D) *>(data) = NS(QVector4D)();
+ return true;
+ case QMetaType::QQuaternion:
+ *static_cast<NS(QQuaternion) *>(data) = NS(QQuaternion)();
+ return true;
+ default:
+ if (type == qMetaTypeId<QVariant>()) {
+ *static_cast<NS(QVariant) *>(data) = NS(QVariant)();
+ return true;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)();
+ return true;
+ } else if (typeCategory(type) != Unknown) {
+ *static_cast<void **>(data) = 0;
+ return true;
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h
new file mode 100644
index 0000000000..aab1c31ef5
--- /dev/null
+++ b/src/declarative/qml/qdeclarativemetatype_p.h
@@ -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 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 QDECLARATIVEMETATYPE_P_H
+#define QDECLARATIVEMETATYPE_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/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qbitarray.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeType;
+class QDeclarativeCustomParser;
+class QDeclarativeTypePrivate;
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeMetaType
+{
+public:
+ static bool canCopy(int type);
+ static bool copy(int type, void *data, const void *copy = 0);
+
+ static QList<QByteArray> qmlTypeNames();
+ static QList<QDeclarativeType*> qmlTypes();
+
+ static QDeclarativeType *qmlType(const QByteArray &, int, int);
+ static QDeclarativeType *qmlType(const QMetaObject *);
+ static QDeclarativeType *qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor);
+ static QDeclarativeType *qmlType(int);
+
+ static QMetaProperty defaultProperty(const QMetaObject *);
+ static QMetaProperty defaultProperty(QObject *);
+ static QMetaMethod defaultMethod(const QMetaObject *);
+ static QMetaMethod defaultMethod(QObject *);
+
+ static bool isQObject(int);
+ static QObject *toQObject(const QVariant &, bool *ok = 0);
+
+ static int listType(int);
+ static int attachedPropertiesFuncId(const QMetaObject *);
+ static QDeclarativeAttachedPropertiesFunc attachedPropertiesFuncById(int);
+
+ enum TypeCategory { Unknown, Object, List };
+ static TypeCategory typeCategory(int);
+
+ static bool isInterface(int);
+ static const char *interfaceIId(int);
+ static bool isList(int);
+
+ typedef QVariant (*StringConverter)(const QString &);
+ static void registerCustomStringConverter(int, StringConverter);
+ static StringConverter customStringConverter(int);
+
+ static bool isModule(const QByteArray &module, int versionMajor, int versionMinor);
+
+ static QList<QDeclarativePrivate::AutoParentFunction> parentFunctions();
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType
+{
+public:
+ QByteArray typeName() const;
+ QByteArray qmlTypeName() const;
+
+ QByteArray module() const;
+ int majorVersion() const;
+ int minorVersion() const;
+
+ bool availableInVersion(int vmajor, int vminor) const;
+ bool availableInVersion(const QByteArray &module, int vmajor, int vminor) const;
+
+ QObject *create() const;
+ void create(QObject **, void **, size_t) const;
+
+ typedef void (*CreateFunc)(void *);
+ CreateFunc createFunction() const;
+ int createSize() const;
+
+ QDeclarativeCustomParser *customParser() const;
+
+ bool isCreatable() const;
+ bool isExtendedType() const;
+ QString noCreationReason() const;
+
+ bool isInterface() const;
+ int typeId() const;
+ int qListTypeId() const;
+
+ const QMetaObject *metaObject() const;
+ const QMetaObject *baseMetaObject() const;
+ int metaObjectRevision() const;
+ bool containsRevisionedAttributes() const;
+
+ QDeclarativeAttachedPropertiesFunc attachedPropertiesFunction() const;
+ const QMetaObject *attachedPropertiesType() const;
+ int attachedPropertiesId() const;
+
+ int parserStatusCast() const;
+ QVariant fromObject(QObject *) const;
+ const char *interfaceIId() const;
+ int propertyValueSourceCast() const;
+ int propertyValueInterceptorCast() const;
+
+ int index() const;
+
+private:
+ QDeclarativeType *superType() const;
+ friend class QDeclarativeTypePrivate;
+ friend struct QDeclarativeMetaTypeData;
+ friend int registerType(const QDeclarativePrivate::RegisterType &);
+ friend int registerInterface(const QDeclarativePrivate::RegisterInterface &);
+ QDeclarativeType(int, const QDeclarativePrivate::RegisterInterface &);
+ QDeclarativeType(int, const QDeclarativePrivate::RegisterType &);
+ ~QDeclarativeType();
+
+ QDeclarativeTypePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEMETATYPE_P_H
+
diff --git a/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp
new file mode 100644
index 0000000000..3782ad0dec
--- /dev/null
+++ b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp
@@ -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 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 "qdeclarativenetworkaccessmanagerfactory.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativeNetworkAccessManagerFactory
+ \since 4.7
+ \brief The QDeclarativeNetworkAccessManagerFactory class creates QNetworkAccessManager instances for a QML engine.
+
+ A QML engine uses QNetworkAccessManager for all network access.
+ By implementing a factory, it is possible to provide the QML engine
+ with custom QNetworkAccessManager instances with specialized caching,
+ proxy and cookies support.
+
+ To implement a factory, subclass QDeclarativeNetworkAccessManagerFactory and
+ implement the virtual create() method, then assign it to the relevant QML
+ engine using QDeclarativeEngine::setNetworkAccessManagerFactory().
+
+ Note the QML engine may create QNetworkAccessManager instances
+ from multiple threads. Because of this, the implementation of the create()
+ method must be \l{Reentrancy and Thread-Safety}{reentrant}. In addition,
+ the developer should be careful if the signals of the object to be
+ returned from create() are connected to the slots of an object that may
+ be created in a different thread:
+
+ \list
+ \o The QML engine internally handles all requests, and cleans up any
+ QNetworkReply objects it creates. Receiving the
+ QNetworkAccessManager::finished() signal in another thread may not
+ provide the receiver with a valid reply object if it has already
+ been deleted.
+ \o Authentication details provided to QNetworkAccessManager::authenticationRequired()
+ must be provided immediately, so this signal cannot be connected as a
+ Qt::QueuedConnection (or as the default Qt::AutoConnection from another
+ thread).
+ \endlist
+
+ For more information about signals and threads, see
+ \l {Threads and QObjects} and \l {Signals and Slots Across Threads}.
+
+ \sa {declarative/cppextensions/networkaccessmanagerfactory}{NetworkAccessManagerFactory example}
+*/
+
+/*!
+ Destroys the factory. The default implementation does nothing.
+ */
+QDeclarativeNetworkAccessManagerFactory::~QDeclarativeNetworkAccessManagerFactory()
+{
+}
+
+/*!
+ \fn QNetworkAccessManager *QDeclarativeNetworkAccessManagerFactory::create(QObject *parent)
+
+ Creates and returns a network access manager with the specified \a parent.
+ This method must return a new QNetworkAccessManager instance each time
+ it is called.
+
+ Note: this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h
new file mode 100644
index 0000000000..ff2de70d24
--- /dev/null
+++ b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVENETWORKACCESSMANAGERFACTORY_H
+#define QDECLARATIVENETWORKACCESSMANAGERFACTORY_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QNetworkAccessManager;
+class Q_DECLARATIVE_EXPORT QDeclarativeNetworkAccessManagerFactory
+{
+public:
+ virtual ~QDeclarativeNetworkAccessManagerFactory();
+ virtual QNetworkAccessManager *create(QObject *parent) = 0;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVENETWORKACCESSMANAGERFACTORY_H
diff --git a/src/declarative/qml/qdeclarativenotifier.cpp b/src/declarative/qml/qdeclarativenotifier.cpp
new file mode 100644
index 0000000000..2cad118d17
--- /dev/null
+++ b/src/declarative/qml/qdeclarativenotifier.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativenotifier_p.h"
+#include "private/qdeclarativeproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDeclarativeNotifier::emitNotify(QDeclarativeNotifierEndpoint *endpoint)
+{
+ QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier();
+
+ QDeclarativeNotifierEndpoint **oldDisconnected = n->disconnected;
+ n->disconnected = &endpoint;
+
+ if (n->next)
+ emitNotify(n->next);
+
+ if (endpoint) {
+ void *args[] = { 0 };
+
+ QMetaObject::metacall(endpoint->target, QMetaObject::InvokeMetaMethod,
+ endpoint->targetMethod, args);
+
+ if (endpoint)
+ endpoint->asNotifier()->disconnected = oldDisconnected;
+ }
+
+ if (oldDisconnected) *oldDisconnected = endpoint;
+}
+
+void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal)
+{
+ Signal *s = toSignal();
+
+ if (s->source == source && s->sourceSignal == sourceSignal)
+ return;
+
+ disconnect();
+
+ QDeclarativePropertyPrivate::connect(source, sourceSignal, target, targetMethod);
+
+ s->source = source;
+ s->sourceSignal = sourceSignal;
+}
+
+void QDeclarativeNotifierEndpoint::copyAndClear(QDeclarativeNotifierEndpoint &other)
+{
+ other.disconnect();
+
+ other.target = target;
+ other.targetMethod = targetMethod;
+
+ if (!isConnected())
+ return;
+
+ if (SignalType == type) {
+ Signal *other_s = other.toSignal();
+ Signal *s = asSignal();
+
+ other_s->source = s->source;
+ other_s->sourceSignal = s->sourceSignal;
+ s->source = 0;
+ } else if(NotifierType == type) {
+ Notifier *other_n = other.toNotifier();
+ Notifier *n = asNotifier();
+
+ other_n->notifier = n->notifier;
+ other_n->disconnected = n->disconnected;
+ if (other_n->disconnected) *other_n->disconnected = &other;
+
+ if (n->next) {
+ other_n->next = n->next;
+ n->next->asNotifier()->prev = &other_n->next;
+ }
+ other_n->prev = n->prev;
+ *other_n->prev = &other;
+
+ n->prev = 0;
+ n->next = 0;
+ n->disconnected = 0;
+ n->notifier = 0;
+ }
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativenotifier_p.h b/src/declarative/qml/qdeclarativenotifier_p.h
new file mode 100644
index 0000000000..45ce9be096
--- /dev/null
+++ b/src/declarative/qml/qdeclarativenotifier_p.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVENOTIFIER_P_H
+#define QDECLARATIVENOTIFIER_P_H
+
+#include "private/qdeclarativeguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeNotifierEndpoint;
+class QDeclarativeNotifier
+{
+public:
+ inline QDeclarativeNotifier();
+ inline ~QDeclarativeNotifier();
+ inline void notify();
+
+private:
+ friend class QDeclarativeNotifierEndpoint;
+
+ static void emitNotify(QDeclarativeNotifierEndpoint *);
+ QDeclarativeNotifierEndpoint *endpoints;
+};
+
+class QDeclarativeNotifierEndpoint
+{
+public:
+ inline QDeclarativeNotifierEndpoint();
+ inline QDeclarativeNotifierEndpoint(QObject *t, int m);
+ inline ~QDeclarativeNotifierEndpoint();
+
+ QObject *target;
+ int targetMethod;
+
+ inline bool isConnected();
+ inline bool isConnected(QObject *source, int sourceSignal);
+ inline bool isConnected(QDeclarativeNotifier *);
+
+ void connect(QObject *source, int sourceSignal);
+ inline void connect(QDeclarativeNotifier *);
+ inline void disconnect();
+
+ void copyAndClear(QDeclarativeNotifierEndpoint &other);
+
+private:
+ friend class QDeclarativeNotifier;
+
+ struct Signal {
+ QDeclarativeGuard<QObject> source;
+ int sourceSignal;
+ };
+
+ struct Notifier {
+ QDeclarativeNotifier *notifier;
+ QDeclarativeNotifierEndpoint **disconnected;
+
+ QDeclarativeNotifierEndpoint *next;
+ QDeclarativeNotifierEndpoint **prev;
+ };
+
+ enum { InvalidType, SignalType, NotifierType } type;
+ union {
+ char signalData[sizeof(Signal)];
+ char notifierData[sizeof(Notifier)];
+ };
+
+ inline Notifier *toNotifier();
+ inline Notifier *asNotifier();
+ inline Signal *toSignal();
+ inline Signal *asSignal();
+};
+
+QDeclarativeNotifier::QDeclarativeNotifier()
+: endpoints(0)
+{
+}
+
+QDeclarativeNotifier::~QDeclarativeNotifier()
+{
+ QDeclarativeNotifierEndpoint *endpoint = endpoints;
+ while (endpoint) {
+ QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier();
+ endpoint = n->next;
+
+ n->next = 0;
+ n->prev = 0;
+ n->notifier = 0;
+ if (n->disconnected) *n->disconnected = 0;
+ n->disconnected = 0;
+ }
+ endpoints = 0;
+}
+
+void QDeclarativeNotifier::notify()
+{
+ if (endpoints) emitNotify(endpoints);
+}
+
+QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint()
+: target(0), targetMethod(0), type(InvalidType)
+{
+}
+
+QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint(QObject *t, int m)
+: target(t), targetMethod(m), type(InvalidType)
+{
+}
+
+QDeclarativeNotifierEndpoint::~QDeclarativeNotifierEndpoint()
+{
+ disconnect();
+ if (SignalType == type) {
+ Signal *s = asSignal();
+ s->~Signal();
+ }
+}
+
+bool QDeclarativeNotifierEndpoint::isConnected()
+{
+ if (SignalType == type) {
+ return asSignal()->source;
+ } else if (NotifierType == type) {
+ return asNotifier()->notifier;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativeNotifierEndpoint::isConnected(QObject *source, int sourceSignal)
+{
+ return SignalType == type && asSignal()->source == source && asSignal()->sourceSignal == sourceSignal;
+}
+
+bool QDeclarativeNotifierEndpoint::isConnected(QDeclarativeNotifier *notifier)
+{
+ return NotifierType == type && asNotifier()->notifier == notifier;
+}
+
+void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier)
+{
+ Notifier *n = toNotifier();
+
+ if (n->notifier == notifier)
+ return;
+
+ disconnect();
+
+ n->next = notifier->endpoints;
+ if (n->next) { n->next->asNotifier()->prev = &n->next; }
+ notifier->endpoints = this;
+ n->prev = &notifier->endpoints;
+ n->notifier = notifier;
+}
+
+void QDeclarativeNotifierEndpoint::disconnect()
+{
+ if (type == SignalType) {
+ Signal *s = (Signal *)&signalData;
+ if (s->source) {
+ QMetaObject::disconnectOne(s->source, s->sourceSignal, target, targetMethod);
+ s->source = 0;
+ }
+ } else if (type == NotifierType) {
+ Notifier *n = asNotifier();
+
+ if (n->next) n->next->asNotifier()->prev = n->prev;
+ if (n->prev) *n->prev = n->next;
+ if (n->disconnected) *n->disconnected = 0;
+ n->next = 0;
+ n->prev = 0;
+ n->disconnected = 0;
+ n->notifier = 0;
+ }
+}
+
+QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::toNotifier()
+{
+ if (NotifierType == type)
+ return asNotifier();
+
+ if (SignalType == type) {
+ disconnect();
+ Signal *s = asSignal();
+ s->~Signal();
+ }
+
+ Notifier *n = asNotifier();
+ n->next = 0;
+ n->prev = 0;
+ n->disconnected = 0;
+ n->notifier = 0;
+ type = NotifierType;
+ return n;
+}
+
+QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::asNotifier()
+{
+ return (Notifier *)(&notifierData);
+}
+
+QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::toSignal()
+{
+ if (SignalType == type)
+ return asSignal();
+
+ disconnect();
+ Signal *s = asSignal();
+ new (s) Signal;
+ type = SignalType;
+
+ return s;
+}
+
+QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::asSignal()
+{
+ return (Signal *)(&signalData);
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVENOTIFIER_P_H
+
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
new file mode 100644
index 0000000000..9eecc65e3c
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
@@ -0,0 +1,1199 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeobjectscriptclass_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)
+
+#if defined(__GNUC__)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+// The code in this file does not violate strict aliasing, but GCC thinks it does
+// so turn off the warnings for us to have a clean build
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+# endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+struct ObjectData : public QScriptDeclarativeClass::Object {
+ ObjectData(QObject *o, int t) : object(o), type(t) {
+ if (o) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+ if (ddata) ddata->objectDataRefCount++;
+ }
+ }
+
+ virtual ~ObjectData() {
+ if (object && !object->parent()) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (ddata && !ddata->indestructible && 0 == --ddata->objectDataRefCount)
+ object->deleteLater();
+ }
+ }
+
+ QDeclarativeGuard<QObject> object;
+ int type;
+};
+
+/*
+ The QDeclarativeObjectScriptClass handles property access for QObjects
+ via QtScript. It is also used to provide a more useful API in
+ QtScript for QML.
+ */
+QDeclarativeObjectScriptClass::QDeclarativeObjectScriptClass(QDeclarativeEngine *bindEngine)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
+ methods(bindEngine), lastData(0), engine(bindEngine)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ m_destroy = scriptEngine->newFunction(destroy);
+ m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
+ m_toString = scriptEngine->newFunction(tostring);
+ m_toStringId = createPersistentIdentifier(QLatin1String("toString"));
+}
+
+QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass()
+{
+}
+
+QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (!object)
+ return scriptEngine->nullValue();
+// return newObject(scriptEngine, this, new ObjectData(object, type));
+
+ if (QObjectPrivate::get(object)->wasDeleted)
+ return scriptEngine->undefinedValue();
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+
+ if (!ddata) {
+ return scriptEngine->undefinedValue();
+ } else if (!ddata->indestructible && !object->parent()) {
+ return newObject(scriptEngine, this, new ObjectData(object, type));
+ } else if (!ddata->scriptValue) {
+ ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type)));
+ return *ddata->scriptValue;
+ } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) {
+ return *ddata->scriptValue;
+ } else {
+ return newObject(scriptEngine, this, new ObjectData(object, type));
+ }
+}
+
+QObject *QDeclarativeObjectScriptClass::toQObject(const QScriptValue &value) const
+{
+ return value.toQObject();
+}
+
+int QDeclarativeObjectScriptClass::objectType(const QScriptValue &value) const
+{
+ if (scriptClass(value) != this)
+ return QVariant::Invalid;
+
+ Object *o = object(value);
+ return ((ObjectData*)(o))->type;
+}
+
+QScriptClass::QueryFlags
+QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ return queryProperty(toQObject(object), name, flags, 0);
+}
+
+QScriptClass::QueryFlags
+QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name,
+ QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext,
+ QueryHints hints)
+{
+ Q_UNUSED(flags);
+ lastData = 0;
+ lastTNData = 0;
+
+ if (name == m_destroyId.identifier ||
+ name == m_toStringId.identifier)
+ return QScriptClass::HandlesReadAccess;
+
+ if (!obj)
+ return 0;
+
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ lastData = QDeclarativePropertyCache::property(engine, obj, name, local);
+ if ((hints & ImplicitObject) && lastData && lastData->revision != 0) {
+
+ QDeclarativeData *ddata = QDeclarativeData::get(obj);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData))
+ return 0;
+ }
+
+ if (lastData)
+ return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
+
+ if (!(hints & SkipAttachedProperties)) {
+ if (!evalContext && context()) {
+ // Global object, QScriptContext activation object, QDeclarativeContext object
+ QScriptValue scopeNode = scopeChainValue(context(), -3);
+ if (scopeNode.isValid()) {
+ Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass);
+
+ evalContext = enginePrivate->contextClass->contextFromValue(scopeNode);
+ }
+ }
+
+ if (evalContext && evalContext->imports) {
+ QDeclarativeTypeNameCache::Data *data = evalContext->imports->data(name);
+ if (data) {
+ lastTNData = data;
+ return QScriptClass::HandlesReadAccess;
+ }
+ }
+ }
+
+ if (!(hints & ImplicitObject)) {
+ local.coreIndex = -1;
+ lastData = &local;
+ return QScriptClass::HandlesWriteAccess;
+ }
+
+ return 0;
+}
+
+QDeclarativeObjectScriptClass::Value
+QDeclarativeObjectScriptClass::property(Object *object, const Identifier &name)
+{
+ return property(toQObject(object), name);
+}
+
+QDeclarativeObjectScriptClass::Value
+QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (name == m_destroyId.identifier)
+ return Value(scriptEngine, m_destroy);
+ else if (name == m_toStringId.identifier)
+ return Value(scriptEngine, m_toString);
+
+ if (lastData && !lastData->isValid())
+ return Value();
+
+ Q_ASSERT(obj);
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+
+ if (lastTNData) {
+
+ if (lastTNData->type)
+ return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type));
+ else
+ return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace));
+
+ } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) {
+ if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
+ return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex));
+ } else {
+ // Uncomment to use QtScript method call logic
+ // QScriptValue sobj = scriptEngine->newQObject(obj);
+ // return Value(scriptEngine, sobj.property(toString(name)));
+ return Value(scriptEngine, methods.newMethod(obj, lastData));
+ }
+ } else {
+ if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) {
+ if (lastData->coreIndex == 0) {
+ enginePriv->capturedProperties <<
+ QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier());
+ } else {
+ enginePriv->capturedProperties <<
+ QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex);
+ }
+ }
+
+ if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) {
+ QDeclarativeValueType *valueType = enginePriv->valueTypes[lastData->propType];
+ if (valueType)
+ return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType));
+ }
+
+ if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) {
+ return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, lastData->propType));
+ } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, newQObject(rv, lastData->propType));
+ } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQScriptValue) {
+ QScriptValue rv = scriptEngine->nullValue();
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::QReal) {
+ qreal rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::Int || lastData->flags & QDeclarativePropertyCache::Data::IsEnumType) {
+ int rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::Bool) {
+ bool rv = false;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::QString) {
+ QString rv;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::UInt) {
+ uint rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::Float) {
+ float rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else if (lastData->propType == QMetaType::Double) {
+ double rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
+ return Value(scriptEngine, rv);
+ } else {
+ QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
+ return Value(scriptEngine, enginePriv->scriptValueFromVariant(var));
+ }
+ }
+}
+
+void QDeclarativeObjectScriptClass::setProperty(Object *object,
+ const Identifier &name,
+ const QScriptValue &value)
+{
+ return setProperty(toQObject(object), name, value, context());
+}
+
+void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
+ const Identifier &name,
+ const QScriptValue &value,
+ QScriptContext *context,
+ QDeclarativeContextData *evalContext)
+{
+ Q_UNUSED(name);
+
+ Q_ASSERT(obj);
+ Q_ASSERT(lastData);
+ Q_ASSERT(context);
+
+ if (!lastData->isValid()) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ toString(name) + QLatin1Char('\"');
+ context->throwError(error);
+ return;
+ }
+
+ if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) &&
+ !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ toString(name) + QLatin1Char('\"');
+ context->throwError(error);
+ return;
+ }
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+
+ if (!evalContext) {
+ // Global object, QScriptContext activation object, QDeclarativeContext object
+ QScriptValue scopeNode = scopeChainValue(context, -3);
+ if (scopeNode.isValid()) {
+ Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass);
+
+ evalContext = enginePriv->contextClass->contextFromValue(scopeNode);
+ }
+ }
+
+ QDeclarativeBinding *newBinding = 0;
+ if (value.isFunction() && !value.isRegExp()) {
+ QScriptContextInfo ctxtInfo(context);
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+
+ newBinding = new QDeclarativeBinding(value, obj, evalContext);
+ newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext));
+ if (newBinding->expression().contains(QLatin1String("this")))
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *delBinding =
+ QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding);
+ if (delBinding)
+ delBinding->destroy();
+
+ if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+ QObject *o = 0;
+ int status = -1;
+ int flags = 0;
+ void *argv[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv);
+ } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) {
+ void *a[] = { 0 };
+ QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a);
+ } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) {
+ QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext);
+ } else if (value.isUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(lastData->propType));
+ context->throwError(error);
+ } else if (value.isFunction() && !value.isRegExp()) {
+ // this is handled by the binding creation above
+ } else {
+ QVariant v;
+ if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
+ v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
+ else
+ v = enginePriv->scriptValueToVariant(value, lastData->propType);
+
+ if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(lastData->propType));
+ context->throwError(error);
+ }
+ }
+}
+
+bool QDeclarativeObjectScriptClass::isQObject() const
+{
+ return true;
+}
+
+QObject *QDeclarativeObjectScriptClass::toQObject(Object *object, bool *ok)
+{
+ if (ok) *ok = true;
+
+ ObjectData *data = (ObjectData*)object;
+ return data->object.data();
+}
+
+QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *)
+{
+ QObject* obj = context->thisObject().toQObject();
+
+ QString ret;
+ if(obj){
+ QString objectName = obj->objectName();
+
+ ret += QString::fromUtf8(obj->metaObject()->className());
+ ret += QLatin1String("(0x");
+ ret += QString::number((quintptr)obj,16);
+
+ if (!objectName.isEmpty()) {
+ ret += QLatin1String(", \"");
+ ret += objectName;
+ ret += QLatin1Char('\"');
+ }
+
+ ret += QLatin1Char(')');
+ }else{
+ ret += QLatin1String("null");
+ }
+ return QScriptValue(ret);
+}
+
+QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+ QScriptValue that = context->thisObject();
+
+ if (scriptClass(that) != p->objectClass)
+ return engine->undefinedValue();
+
+ ObjectData *data = (ObjectData *)p->objectClass->object(that);
+ if (!data->object)
+ return engine->undefinedValue();
+
+ QDeclarativeData *ddata = QDeclarativeData::get(data->object, false);
+ if (!ddata || ddata->indestructible)
+ return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object"));
+
+ QObject *obj = data->object;
+ int delay = 0;
+ if (context->argumentCount() > 0)
+ delay = context->argument(0).toInt32();
+ if (delay > 0)
+ QTimer::singleShot(delay, obj, SLOT(deleteLater()));
+ else
+ obj->deleteLater();
+
+ return engine->undefinedValue();
+}
+
+QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object)
+{
+ QObject *obj = toQObject(object);
+ if (!obj)
+ return QStringList();
+
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+
+ QDeclarativePropertyCache *cache = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(obj);
+ if (ddata)
+ cache = ddata->propertyCache;
+ if (!cache) {
+ cache = enginePrivate->cache(obj);
+ if (cache) {
+ if (ddata) { cache->addref(); ddata->propertyCache = cache; }
+ } else {
+ // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
+ // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal.
+ // XXX This is a workaround for QTBUG-9420.
+ const QMetaObject *mo = obj->metaObject();
+ QStringList r;
+ int pc = mo->propertyCount();
+ int po = mo->propertyOffset();
+ for (int i=po; i<pc; ++i)
+ r += QString::fromUtf8(mo->property(i).name());
+ return r;
+ }
+ }
+ return cache->propertyNames();
+}
+
+bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2)
+{
+ ObjectData *d1 = (ObjectData *)o1;
+ ObjectData *d2 = (ObjectData *)o2;
+
+ return d1 == d2 || d1->object == d2->object;
+}
+
+struct MethodData : public QScriptDeclarativeClass::Object {
+ MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {}
+
+ QDeclarativeGuard<QObject> object;
+ QDeclarativePropertyCache::Data data;
+};
+
+QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *bindEngine)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
+ engine(bindEngine)
+{
+ qRegisterMetaType<QList<QObject *> >("QList<QObject *>");
+
+ setSupportsCall(true);
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ m_connect = scriptEngine->newFunction(connect);
+ m_connectId = createPersistentIdentifier(QLatin1String("connect"));
+ m_disconnect = scriptEngine->newFunction(disconnect);
+ m_disconnectId = createPersistentIdentifier(QLatin1String("disconnect"));
+}
+
+QDeclarativeObjectMethodScriptClass::~QDeclarativeObjectMethodScriptClass()
+{
+}
+
+QScriptValue QDeclarativeObjectMethodScriptClass::newMethod(QObject *object, const QDeclarativePropertyCache::Data *method)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return newObject(scriptEngine, this, new MethodData(object, *method));
+}
+
+QScriptValue QDeclarativeObjectMethodScriptClass::connect(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+
+ QScriptValue that = context->thisObject();
+ if (&p->objectClass->methods != scriptClass(that))
+ return engine->undefinedValue();
+
+ MethodData *data = (MethodData *)object(that);
+
+ if (!data->object || context->argumentCount() == 0)
+ return engine->undefinedValue();
+
+ QByteArray signal("2");
+ signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
+
+ if (context->argumentCount() == 1) {
+ qScriptConnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
+ } else {
+ qScriptConnect(data->object, signal.constData(), context->argument(0), context->argument(1));
+ }
+
+ return engine->undefinedValue();
+}
+
+QScriptValue QDeclarativeObjectMethodScriptClass::disconnect(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
+
+ QScriptValue that = context->thisObject();
+ if (&p->objectClass->methods != scriptClass(that))
+ return engine->undefinedValue();
+
+ MethodData *data = (MethodData *)object(that);
+
+ if (!data->object || context->argumentCount() == 0)
+ return engine->undefinedValue();
+
+ QByteArray signal("2");
+ signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
+
+ if (context->argumentCount() == 1) {
+ qScriptDisconnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
+ } else {
+ qScriptDisconnect(data->object, signal.constData(), context->argument(0), context->argument(1));
+ }
+
+ return engine->undefinedValue();
+}
+
+QScriptClass::QueryFlags
+QDeclarativeObjectMethodScriptClass::queryProperty(Object *, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(flags);
+ if (name == m_connectId.identifier || name == m_disconnectId.identifier)
+ return QScriptClass::HandlesReadAccess;
+ else
+ return 0;
+
+}
+
+QDeclarativeObjectMethodScriptClass::Value
+QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ if (name == m_connectId.identifier)
+ return Value(scriptEngine, m_connect);
+ else if (name == m_disconnectId.identifier)
+ return Value(scriptEngine, m_disconnect);
+ else
+ return Value();
+}
+
+namespace {
+struct MetaCallArgument {
+ inline MetaCallArgument();
+ inline ~MetaCallArgument();
+ inline void *dataPtr();
+
+ inline void initAsType(int type, QDeclarativeEngine *);
+ void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &);
+ inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *);
+
+private:
+ MetaCallArgument(const MetaCallArgument &);
+
+ inline void cleanup();
+
+ char data[4 * sizeof(void *)];
+ int type;
+ bool isObjectType;
+};
+}
+
+MetaCallArgument::MetaCallArgument()
+: type(QVariant::Invalid), isObjectType(false)
+{
+}
+
+MetaCallArgument::~MetaCallArgument()
+{
+ cleanup();
+}
+
+void MetaCallArgument::cleanup()
+{
+ if (type == QMetaType::QString) {
+ ((QString *)&data)->~QString();
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ ((QVariant *)&data)->~QVariant();
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ ((QScriptValue *)&data)->~QScriptValue();
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ ((QList<QObject *> *)&data)->~QList<QObject *>();
+ }
+}
+
+void *MetaCallArgument::dataPtr()
+{
+ if (type == -1)
+ return ((QVariant *)data)->data();
+ else
+ return (void *)&data;
+}
+
+void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e)
+{
+ if (type != 0) { cleanup(); type = 0; }
+ if (callType == 0) return;
+
+ QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue(engine->undefinedValue());
+ type = callType;
+ } else if (callType == QMetaType::Int ||
+ callType == QMetaType::UInt ||
+ callType == QMetaType::Bool ||
+ callType == QMetaType::Double ||
+ callType == QMetaType::Float) {
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = 0;
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ new (&data) QString();
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ type = callType;
+ new (&data) QVariant();
+ } else if (callType == qMetaTypeId<QList<QObject *> >()) {
+ type = callType;
+ new (&data) QList<QObject *>();
+ } else {
+ type = -1;
+ new (&data) QVariant(callType, (void *)0);
+ }
+}
+
+void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value)
+{
+ if (type != 0) { cleanup(); type = 0; }
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue(value);
+ type = qMetaTypeId<QScriptValue>();
+ } else if (callType == QMetaType::Int) {
+ *((int *)&data) = int(value.toInt32());
+ type = callType;
+ } else if (callType == QMetaType::UInt) {
+ *((uint *)&data) = uint(value.toUInt32());
+ type = callType;
+ } else if (callType == QMetaType::Bool) {
+ *((bool *)&data) = value.toBool();
+ type = callType;
+ } else if (callType == QMetaType::Double) {
+ *((double *)&data) = double(value.toNumber());
+ type = callType;
+ } else if (callType == QMetaType::Float) {
+ *((float *)&data) = float(value.toNumber());
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ if (value.isNull() || value.isUndefined())
+ new (&data) QString();
+ else
+ new (&data) QString(value.toString());
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = value.toQObject();
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value));
+ type = callType;
+ } else if (callType == qMetaTypeId<QList<QObject*> >()) {
+ QList<QObject *> *list = new (&data) QList<QObject *>();
+ if (value.isArray()) {
+ int length = value.property(QLatin1String("length")).toInt32();
+ for (int ii = 0; ii < length; ++ii) {
+ QScriptValue arrayItem = value.property(ii);
+ QObject *d = arrayItem.toQObject();
+ list->append(d);
+ }
+ } else if (QObject *d = value.toQObject()) {
+ list->append(d);
+ }
+ type = callType;
+ } else {
+ new (&data) QVariant();
+ type = -1;
+
+ QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
+ QVariant v = priv->scriptValueToVariant(value);
+ if (v.userType() == callType) {
+ *((QVariant *)&data) = v;
+ } else if (v.canConvert((QVariant::Type)callType)) {
+ *((QVariant *)&data) = v;
+ ((QVariant *)&data)->convert((QVariant::Type)callType);
+ } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) {
+ QObject *obj = priv->toQObject(v);
+
+ if (obj) {
+ const QMetaObject *objMo = obj->metaObject();
+ while (objMo && objMo != mo) objMo = objMo->superClass();
+ if (!objMo) obj = 0;
+ }
+
+ *((QVariant *)&data) = QVariant(callType, &obj);
+ } else {
+ *((QVariant *)&data) = QVariant(callType, (void *)0);
+ }
+ }
+}
+
+QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e)
+{
+ QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
+
+ if (type == qMetaTypeId<QScriptValue>()) {
+ return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data));
+ } else if (type == QMetaType::Int) {
+ return QScriptDeclarativeClass::Value(engine, *((int *)&data));
+ } else if (type == QMetaType::UInt) {
+ return QScriptDeclarativeClass::Value(engine, *((uint *)&data));
+ } else if (type == QMetaType::Bool) {
+ return QScriptDeclarativeClass::Value(engine, *((bool *)&data));
+ } else if (type == QMetaType::Double) {
+ return QScriptDeclarativeClass::Value(engine, *((double *)&data));
+ } else if (type == QMetaType::Float) {
+ return QScriptDeclarativeClass::Value(engine, *((float *)&data));
+ } else if (type == QMetaType::QString) {
+ return QScriptDeclarativeClass::Value(engine, *((QString *)&data));
+ } else if (type == QMetaType::QObjectStar) {
+ QObject *object = *((QObject **)&data);
+ if (object)
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
+ return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object));
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ QList<QObject *> &list = *(QList<QObject *>*)&data;
+ QScriptValue rv = engine->newArray(list.count());
+ QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *object = list.at(ii);
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ rv.setProperty(ii, priv->objectClass->newQObject(object));
+ }
+ return QScriptDeclarativeClass::Value(engine, rv);
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e);
+ QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data));
+ if (rv.isQObject()) {
+ QObject *object = rv.toQObject();
+ if (object)
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ }
+ return QScriptDeclarativeClass::Value(engine, rv);
+ } else {
+ return QScriptDeclarativeClass::Value();
+ }
+}
+
+int QDeclarativeObjectMethodScriptClass::enumType(const QMetaObject *meta, const QString &strname)
+{
+ QByteArray str = strname.toUtf8();
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return QVariant::Int;
+ }
+ return QVariant::Invalid;
+}
+
+QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt)
+{
+ MethodData *method = static_cast<MethodData *>(o);
+
+ if (method->data.relatedIndex == -1)
+ return callPrecise(method->object, method->data, ctxt);
+ else
+ return callOverloaded(method, ctxt);
+}
+
+QDeclarativeObjectMethodScriptClass::Value
+QDeclarativeObjectMethodScriptClass::callPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
+ QScriptContext *ctxt)
+{
+ if (data.flags & QDeclarativePropertyCache::Data::HasArguments) {
+
+ QMetaMethod m = object->metaObject()->method(data.coreIndex);
+ QList<QByteArray> argTypeNames = m.parameterTypes();
+ QVarLengthArray<int, 9> argTypes(argTypeNames.count());
+
+ // ### Cache
+ for (int ii = 0; ii < argTypeNames.count(); ++ii) {
+ argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
+ if (argTypes[ii] == QVariant::Invalid)
+ argTypes[ii] = enumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
+ if (argTypes[ii] == QVariant::Invalid)
+ return Value(ctxt, ctxt->throwError(QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)))));
+ }
+
+ if (argTypes.count() > ctxt->argumentCount())
+ return Value(ctxt, ctxt->throwError(QLatin1String("Insufficient arguments")));
+
+ return callMethod(object, data.coreIndex, data.propType, argTypes.count(), argTypes.data(), ctxt);
+
+ } else {
+
+ return callMethod(object, data.coreIndex, data.propType, 0, 0, ctxt);
+
+ }
+}
+
+QDeclarativeObjectMethodScriptClass::Value
+QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index,
+ int returnType, int argCount, int *argTypes,
+ QScriptContext *ctxt)
+{
+ if (argCount > 0) {
+
+ QVarLengthArray<MetaCallArgument, 9> args(argCount + 1);
+ args[0].initAsType(returnType, engine);
+
+ for (int ii = 0; ii < argCount; ++ii)
+ args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii));
+
+ QVarLengthArray<void *, 9> argData(args.count());
+ for (int ii = 0; ii < args.count(); ++ii)
+ argData[ii] = args[ii].dataPtr();
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+
+ return args[0].toValue(engine);
+
+ } else if (returnType != 0) {
+
+ MetaCallArgument arg;
+ arg.initAsType(returnType, engine);
+
+ void *args[] = { arg.dataPtr() };
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+
+ return arg.toValue(engine);
+
+ } else {
+
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ return Value();
+
+ }
+}
+
+/*!
+Resolve the overloaded method to call. The algorithm works conceptually like this:
+ 1. Resolve the set of overloads it is *possible* to call.
+ Impossible overloads include those that have too many parameters or have parameters
+ of unknown type.
+ 2. Filter the set of overloads to only contain those with the closest number of
+ parameters.
+ For example, if we are called with 3 parameters and there are 2 overloads that
+ take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
+ 3. Find the best remaining overload based on its match score.
+ If two or more overloads have the same match score, call the last one. The match
+ score is constructed by adding the matchScore() result for each of the parameters.
+*/
+QDeclarativeObjectMethodScriptClass::Value
+QDeclarativeObjectMethodScriptClass::callOverloaded(MethodData *method, QScriptContext *ctxt)
+{
+ int argumentCount = ctxt->argumentCount();
+
+ QDeclarativePropertyCache::Data *best = 0;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QDeclarativePropertyCache::Data dummy;
+ QDeclarativePropertyCache::Data *attempt = &method->data;
+
+ do {
+ QList<QByteArray> methodArgTypeNames;
+
+ if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments)
+ methodArgTypeNames = method->object->metaObject()->method(attempt->coreIndex).parameterTypes();
+
+ int methodArgumentCount = methodArgTypeNames.count();
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
+
+ bool unknownArgument = false;
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
+ if (methodArgTypes[ii] == QVariant::Invalid)
+ methodArgTypes[ii] = enumType(method->object->metaObject(),
+ QString::fromLatin1(methodArgTypeNames.at(ii)));
+ if (methodArgTypes[ii] == QVariant::Invalid) {
+ unknownArgument = true;
+ break;
+ }
+ methodMatchScore += matchScore(ctxt->argument(ii), methodArgTypes[ii], methodArgTypeNames.at(ii));
+ }
+ if (unknownArgument)
+ continue; // We don't understand all the parameters
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+
+ } while((attempt = relatedMethod(method->object, attempt, dummy)) != 0);
+
+ if (best) {
+ return callPrecise(method->object, *best, ctxt);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ QDeclarativePropertyCache::Data *candidate = &method->data;
+ while (candidate) {
+ error += QLatin1String("\n ") + QString::fromUtf8(method->object->metaObject()->method(candidate->coreIndex).signature());
+ candidate = relatedMethod(method->object, candidate, dummy);
+ }
+ return Value(ctxt, ctxt->throwError(error));
+ }
+}
+
+/*!
+ Returns the match score for converting \a actual to be of type \a conversionType. A
+ zero score means "perfect match" whereas a higher score is worse.
+
+ The conversion table is copied out of the QtScript callQtMethod() function.
+*/
+int QDeclarativeObjectMethodScriptClass::matchScore(const QScriptValue &actual, int conversionType,
+ const QByteArray &conversionTypeName)
+{
+ if (actual.isNumber()) {
+ switch (conversionType) {
+ case QMetaType::Double:
+ return 0;
+ case QMetaType::Float:
+ return 1;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ return 2;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ return 3;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return 4;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ return 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return 6;
+ default:
+ return 10;
+ }
+ } else if (actual.isString()) {
+ switch (conversionType) {
+ case QMetaType::QString:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual.isBoolean()) {
+ switch (conversionType) {
+ case QMetaType::Bool:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual.isDate()) {
+ switch (conversionType) {
+ case QMetaType::QDateTime:
+ return 0;
+ case QMetaType::QDate:
+ return 1;
+ case QMetaType::QTime:
+ return 2;
+ default:
+ return 10;
+ }
+ } else if (actual.isRegExp()) {
+ switch (conversionType) {
+ case QMetaType::QRegExp:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual.isVariant()) {
+ if (conversionType == qMetaTypeId<QVariant>())
+ return 0;
+ else if (actual.toVariant().userType() == conversionType)
+ return 0;
+ else
+ return 10;
+ } else if (actual.isArray()) {
+ switch (conversionType) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual.isQObject()) {
+ switch (conversionType) {
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual.isNull()) {
+ switch (conversionType) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ if (!conversionTypeName.endsWith('*'))
+ return 10;
+ else
+ return 0;
+ }
+ } else {
+ return 10;
+ }
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static QByteArray QMetaMethod_name(const QMetaMethod &m)
+{
+ QByteArray sig = m.signature();
+ int paren = sig.indexOf('(');
+ if (paren == -1)
+ return sig;
+ else
+ return sig.left(paren);
+}
+
+/*!
+Returns the next related method, if one, or 0.
+*/
+QDeclarativePropertyCache::Data *
+QDeclarativeObjectMethodScriptClass::relatedMethod(QObject *object, QDeclarativePropertyCache::Data *current,
+ QDeclarativePropertyCache::Data &dummy)
+{
+ QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
+ if (current->relatedIndex == -1)
+ return 0;
+
+ if (cache) {
+ return cache->method(current->relatedIndex);
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
+
+ while (methodOffset > current->relatedIndex) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObject_methods(mo);
+ }
+
+ QMetaMethod method = mo->method(current->relatedIndex);
+ dummy.load(method);
+
+ // Look for overloaded methods
+ QByteArray methodName = QMetaMethod_name(method);
+ for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
+ if (methodName == QMetaMethod_name(mo->method(ii))) {
+ dummy.relatedIndex = ii;
+ return &dummy;
+ }
+ }
+
+ return &dummy;
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
new file mode 100644
index 0000000000..850a94f364
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEOBJECTSCRIPTCLASS_P_H
+#define QDECLARATIVEOBJECTSCRIPTCLASS_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;
+class QScriptContext;
+class QScriptEngine;
+class QDeclarativeContextData;
+class MethodData;
+
+class Q_AUTOTEST_EXPORT QDeclarativeObjectMethodScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeObjectMethodScriptClass();
+
+ QScriptValue newMethod(QObject *, const QDeclarativePropertyCache::Data *);
+
+protected:
+ virtual Value call(Object *, QScriptContext *);
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+
+private:
+ int enumType(const QMetaObject *, const QString &);
+
+ Value callPrecise(QObject *, const QDeclarativePropertyCache::Data &, QScriptContext *);
+ Value callOverloaded(MethodData *, QScriptContext *);
+ Value callMethod(QObject *, int index, int returnType, int argCount, int *argTypes, QScriptContext *ctxt);
+
+ int matchScore(const QScriptValue &, int, const QByteArray &);
+ QDeclarativePropertyCache::Data *relatedMethod(QObject *, QDeclarativePropertyCache::Data *current,
+ QDeclarativePropertyCache::Data &dummy);
+
+ PersistentIdentifier m_connectId;
+ PersistentIdentifier m_disconnectId;
+ QScriptValue m_connect;
+ QScriptValue m_disconnect;
+
+ static QScriptValue connect(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue disconnect(QScriptContext *context, QScriptEngine *engine);
+
+ QDeclarativeEngine *engine;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeObjectScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeObjectScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeObjectScriptClass();
+
+ QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar);
+
+ QObject *toQObject(const QScriptValue &) const;
+ int objectType(const QScriptValue &) const;
+
+ enum QueryHint {
+ ImplicitObject = 0x01,
+ SkipAttachedProperties = 0x02
+ };
+ Q_DECLARE_FLAGS(QueryHints, QueryHint)
+
+ QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &,
+ QScriptClass::QueryFlags flags,
+ QDeclarativeContextData *evalContext,
+ QueryHints hints = 0);
+
+ Value property(QObject *, const Identifier &);
+
+ void setProperty(QObject *, const Identifier &name, const QScriptValue &,
+ QScriptContext *context, QDeclarativeContextData *evalContext = 0);
+ virtual QStringList propertyNames(Object *);
+ virtual bool compare(Object *, Object *);
+
+protected:
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+
+ virtual Value property(Object *, const Identifier &);
+ virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ virtual bool isQObject() const;
+ virtual QObject *toQObject(Object *, bool *ok = 0);
+
+private:
+ friend class QDeclarativeObjectMethodScriptClass;
+ QDeclarativeObjectMethodScriptClass methods;
+
+ QDeclarativeTypeNameCache::Data *lastTNData;
+ QDeclarativePropertyCache::Data *lastData;
+ QDeclarativePropertyCache::Data local;
+
+ PersistentIdentifier m_destroyId;
+ PersistentIdentifier m_toStringId;
+ QScriptValue m_destroy;
+ QScriptValue m_toString;
+
+ static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
+
+ QDeclarativeEngine *engine;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeObjectScriptClass::QueryHints);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEOBJECTSCRIPTCLASS_P_H
+
diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp
new file mode 100644
index 0000000000..d5b94245fd
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeparser.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 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/qdeclarativeparser_p.h"
+
+#include "qdeclarativepropertyvaluesource.h"
+#include "private/qdeclarativevme_p.h"
+#include "qdeclarative.h"
+#include "private/qdeclarativecomponent_p.h"
+#include "qdeclarativecomponent.h"
+#include "private/qmetaobjectbuilder_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "parser/qdeclarativejsast_p.h"
+#include "parser/qdeclarativejsengine_p.h"
+
+#include <QStack>
+#include <QColor>
+#include <QPointF>
+#include <QSizeF>
+#include <QRectF>
+#include <QStringBuilder>
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+using namespace QDeclarativeParser;
+
+QDeclarativeParser::Object::Object()
+: type(-1), majorVersion(-1), minorVersion(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1)
+{
+}
+
+QDeclarativeParser::Object::~Object()
+{
+ if (defaultProperty) defaultProperty->release();
+ if (synthCache) synthCache->release();
+ foreach(Property *prop, properties)
+ prop->release();
+ foreach(Property *prop, valueProperties)
+ prop->release();
+ foreach(Property *prop, signalProperties)
+ prop->release();
+ foreach(Property *prop, attachedProperties)
+ prop->release();
+ foreach(Property *prop, groupedProperties)
+ prop->release();
+ foreach(Property *prop, valueTypeProperties)
+ prop->release();
+ typedef QPair<Property *, int> PropPair;
+ foreach(const PropPair &prop, scriptStringProperties)
+ prop.first->release();
+ foreach(const DynamicProperty &prop, dynamicProperties)
+ if (prop.defaultValue) prop.defaultValue->release();
+}
+
+void Object::setBindingBit(int b)
+{
+ while (bindingBitmask.size() < 4 * (1 + b / 32))
+ bindingBitmask.append(char(0));
+
+ quint32 *bits = (quint32 *)bindingBitmask.data();
+ bits[b / 32] |= (1 << (b % 32));
+}
+
+const QMetaObject *Object::metaObject() const
+{
+ if (!metadata.isEmpty() && metatype)
+ return &extObject;
+ else
+ return metatype;
+}
+
+QDeclarativeParser::Property *Object::getDefaultProperty()
+{
+ if (!defaultProperty) {
+ defaultProperty = new Property;
+ defaultProperty->parent = this;
+ }
+ return defaultProperty;
+}
+
+void QDeclarativeParser::Object::addValueProperty(Property *p)
+{
+ p->addref();
+ valueProperties << p;
+}
+
+void QDeclarativeParser::Object::addSignalProperty(Property *p)
+{
+ p->addref();
+ signalProperties << p;
+}
+
+void QDeclarativeParser::Object::addAttachedProperty(Property *p)
+{
+ p->addref();
+ attachedProperties << p;
+}
+
+void QDeclarativeParser::Object::addGroupedProperty(Property *p)
+{
+ p->addref();
+ groupedProperties << p;
+}
+
+void QDeclarativeParser::Object::addValueTypeProperty(Property *p)
+{
+ p->addref();
+ valueTypeProperties << p;
+}
+
+void QDeclarativeParser::Object::addScriptStringProperty(Property *p, int stack)
+{
+ p->addref();
+ scriptStringProperties << qMakePair(p, stack);
+}
+
+
+Property *QDeclarativeParser::Object::getProperty(const QByteArray &name, bool create)
+{
+ if (!properties.contains(name)) {
+ if (create) {
+ Property *property = new Property(name);
+ property->parent = this;
+ properties.insert(name, property);
+ } else {
+ return 0;
+ }
+ }
+ return properties[name];
+}
+
+QDeclarativeParser::Object::DynamicProperty::DynamicProperty()
+: isDefaultProperty(false), type(Variant), defaultValue(0)
+{
+}
+
+QDeclarativeParser::Object::DynamicProperty::DynamicProperty(const DynamicProperty &o)
+: isDefaultProperty(o.isDefaultProperty),
+ type(o.type),
+ customType(o.customType),
+ name(o.name),
+ defaultValue(o.defaultValue),
+ location(o.location)
+{
+}
+
+QDeclarativeParser::Object::DynamicSignal::DynamicSignal()
+{
+}
+
+QDeclarativeParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o)
+: name(o.name), parameterTypes(o.parameterTypes),
+ parameterNames(o.parameterNames)
+{
+}
+
+QDeclarativeParser::Object::DynamicSlot::DynamicSlot()
+{
+}
+
+QDeclarativeParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o)
+: name(o.name), body(o.body), parameterNames(o.parameterNames), location(o.location)
+{
+}
+
+QDeclarativeParser::Property::Property()
+: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false),
+ isValueTypeSubProperty(false), isAlias(false)
+{
+}
+
+QDeclarativeParser::Property::Property(const QByteArray &n)
+: parent(0), type(0), index(-1), value(0), name(n), isDefault(false),
+ isDeferred(false), isValueTypeSubProperty(false), isAlias(false)
+{
+}
+
+QDeclarativeParser::Property::~Property()
+{
+ foreach(Value *value, values)
+ value->release();
+ foreach(Value *value, onValues)
+ value->release();
+ if (value) value->release();
+}
+
+QDeclarativeParser::Object *QDeclarativeParser::Property::getValue(const LocationSpan &l)
+{
+ if (!value) { value = new QDeclarativeParser::Object; value->location = l; }
+ return value;
+}
+
+void QDeclarativeParser::Property::addValue(Value *v)
+{
+ values << v;
+}
+
+void QDeclarativeParser::Property::addOnValue(Value *v)
+{
+ onValues << v;
+}
+
+bool QDeclarativeParser::Property::isEmpty() const
+{
+ return !value && values.isEmpty() && onValues.isEmpty();
+}
+
+QDeclarativeParser::Value::Value()
+: type(Unknown), object(0)
+{
+}
+
+QDeclarativeParser::Value::~Value()
+{
+ if (object) object->release();
+}
+
+QDeclarativeParser::Variant::Variant()
+: t(Invalid) {}
+
+QDeclarativeParser::Variant::Variant(const Variant &o)
+: t(o.t), d(o.d), s(o.s)
+{
+}
+
+QDeclarativeParser::Variant::Variant(bool v)
+: t(Boolean), b(v)
+{
+}
+
+QDeclarativeParser::Variant::Variant(double v, const QString &asWritten)
+: t(Number), d(v), s(asWritten)
+{
+}
+
+QDeclarativeParser::Variant::Variant(const QString &v)
+: t(String), s(v)
+{
+}
+
+QDeclarativeParser::Variant::Variant(const QString &v, QDeclarativeJS::AST::Node *n)
+: t(Script), n(n), s(v)
+{
+}
+
+QDeclarativeParser::Variant &QDeclarativeParser::Variant::operator=(const Variant &o)
+{
+ t = o.t;
+ d = o.d;
+ s = o.s;
+ return *this;
+}
+
+QDeclarativeParser::Variant::Type QDeclarativeParser::Variant::type() const
+{
+ return t;
+}
+
+bool QDeclarativeParser::Variant::asBoolean() const
+{
+ return b;
+}
+
+QString QDeclarativeParser::Variant::asString() const
+{
+ return s;
+}
+
+double QDeclarativeParser::Variant::asNumber() const
+{
+ return d;
+}
+
+//reverse of Lexer::singleEscape()
+QString escapedString(const QString &string)
+{
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.length(); ++i) {
+ const QChar &c = string.at(i);
+ switch(c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+}
+
+QString QDeclarativeParser::Variant::asScript() const
+{
+ switch(type()) {
+ default:
+ case Invalid:
+ return QString();
+ case Boolean:
+ return b?QLatin1String("true"):QLatin1String("false");
+ case Number:
+ if (s.isEmpty())
+ return QString::number(d);
+ else
+ return s;
+ case String:
+ return escapedString(s);
+ case Script:
+ return s;
+ }
+}
+
+QDeclarativeJS::AST::Node *QDeclarativeParser::Variant::asAST() const
+{
+ if (type() == Script)
+ return n;
+ else
+ return 0;
+}
+
+bool QDeclarativeParser::Variant::isStringList() const
+{
+ if (isString())
+ return true;
+
+ if (type() != Script || !n)
+ return false;
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return false;
+
+ AST::ElementList *elements = array->elements;
+
+ while (elements) {
+
+ if (!AST::cast<AST::StringLiteral *>(elements->expression))
+ return false;
+
+ elements = elements->next;
+ }
+
+ return true;
+}
+
+QStringList QDeclarativeParser::Variant::asStringList() const
+{
+ QStringList rv;
+ if (isString()) {
+ rv << asString();
+ return rv;
+ }
+
+ AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
+ if (!array)
+ return rv;
+
+ AST::ElementList *elements = array->elements;
+ while (elements) {
+
+ AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression);
+ if (!string)
+ return QStringList();
+ rv.append(string->value->asString());
+
+ elements = elements->next;
+ }
+
+ return rv;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h
new file mode 100644
index 0000000000..8f41a9198a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeparser_p.h
@@ -0,0 +1,381 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPARSER_P_H
+#define QDECLARATIVEPARSER_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/qbytearray.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativerefcount_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePropertyCache;
+namespace QDeclarativeJS { namespace AST { class Node; } }
+
+/*
+ XXX
+
+ These types are created (and owned) by the QDeclarativeXmlParser and consumed by the
+ QDeclarativeCompiler. During the compilation phase the compiler will update some of
+ the fields for both its own use and for the use of the upcoming QDeclarativeDom API.
+
+ The types are part of the generic sounding "QDeclarativeParser" namespace for legacy
+ reasons (there used to be more in this namespace) and will be cleaned up and
+ migrated into a more appropriate location shortly.
+*/
+namespace QDeclarativeParser
+{
+ struct Location
+ {
+ Location() : line(-1), column(-1) {}
+ int line;
+ int column;
+ };
+
+ struct LocationRange
+ {
+ LocationRange() : offset(0), length(0) {}
+ quint32 offset;
+ quint32 length;
+ };
+
+ struct LocationSpan
+ {
+ Location start;
+ Location end;
+ LocationRange range;
+
+ bool operator<(LocationSpan &o) const {
+ return (start.line < o.start.line) ||
+ (start.line == o.start.line && start.column < o.start.column);
+ }
+ };
+
+ class Property;
+ class Object : public QDeclarativeRefCount
+ {
+ public:
+ Object();
+ virtual ~Object();
+
+ // Type of the object. The integer is an index into the
+ // QDeclarativeCompiledData::types array, or -1 if the object is a property
+ // group.
+ int type;
+ // The url of this object if it is an external type. Used by the DOM
+ QUrl url;
+
+ // version information if type is defined in library or C++
+ int majorVersion;
+ int minorVersion;
+
+ // The fully-qualified name of this type
+ QByteArray typeName;
+ // The class name
+ QByteArray className;
+ // The id assigned to the object (if any). Set by the QDeclarativeCompiler
+ QString id;
+ // The id index assigned to the object (if any). Set by the QDeclarativeCompiler
+ int idIndex;
+ // Custom parsed data
+ QByteArray custom;
+ // Bit mask of the properties assigned bindings
+ QByteArray bindingBitmask;
+ void setBindingBit(int);
+ // Returns the metaobject for this type, or 0 if not available.
+ // Internally selectd between the metatype and extObject variables
+ const QMetaObject *metaObject() const;
+
+ // The compile time metaobject for this type
+ const QMetaObject *metatype;
+ // The synthesized metaobject, if QML added signals or properties to
+ // this type. Otherwise null
+ QAbstractDynamicMetaObject extObject;
+ QByteArray metadata; // Generated by compiler
+ QByteArray synthdata; // Generated by compiler
+ QDeclarativePropertyCache *synthCache; // Generated by compiler
+
+ Property *getDefaultProperty();
+ Property *getProperty(const QByteArray &name, bool create=true);
+
+ Property *defaultProperty;
+ QHash<QByteArray, Property *> properties;
+
+ // Output of the compilation phase (these properties continue to exist
+ // in either the defaultProperty or properties members too)
+ void addValueProperty(Property *);
+ void addSignalProperty(Property *);
+ void addAttachedProperty(Property *);
+ void addGroupedProperty(Property *);
+ void addValueTypeProperty(Property *);
+ void addScriptStringProperty(Property *, int = 0);
+ QList<Property *> valueProperties;
+ QList<Property *> signalProperties;
+ QList<Property *> attachedProperties;
+ QList<Property *> groupedProperties;
+ QList<Property *> valueTypeProperties;
+ QList<QPair<Property *, int> > scriptStringProperties;
+
+ // Script blocks that were nested under this object
+ struct ScriptBlock {
+ enum Pragma {
+ None = 0x00000000,
+ Shared = 0x00000001
+ };
+ Q_DECLARE_FLAGS(Pragmas, Pragma)
+
+ QString code;
+ QString file;
+ Pragmas pragmas;
+ };
+
+ // The bytes to cast instances by to get to the QDeclarativeParserStatus
+ // interface. -1 indicates the type doesn't support this interface.
+ // Set by the QDeclarativeCompiler.
+ int parserStatusCast;
+
+ LocationSpan location;
+
+ struct DynamicProperty {
+ DynamicProperty();
+ DynamicProperty(const DynamicProperty &);
+
+ enum Type { Variant, Int, Bool, Real, String, Url, Color, Time, Date, DateTime, Alias, Custom, CustomList };
+
+ bool isDefaultProperty;
+ Type type;
+ QByteArray customType;
+ QByteArray name;
+ QDeclarativeParser::Property *defaultValue;
+ LocationSpan location;
+ };
+ struct DynamicSignal {
+ DynamicSignal();
+ DynamicSignal(const DynamicSignal &);
+
+ QByteArray name;
+ QList<QByteArray> parameterTypes;
+ QList<QByteArray> parameterNames;
+ };
+ struct DynamicSlot {
+ DynamicSlot();
+ DynamicSlot(const DynamicSlot &);
+
+ QByteArray name;
+ QString body;
+ QList<QByteArray> parameterNames;
+ LocationSpan location;
+ };
+
+ // The list of dynamic properties
+ QList<DynamicProperty> dynamicProperties;
+ // The list of dynamic signals
+ QList<DynamicSignal> dynamicSignals;
+ // The list of dynamic slots
+ QList<DynamicSlot> dynamicSlots;
+ };
+
+ class Q_DECLARATIVE_EXPORT Variant
+ {
+ public:
+ enum Type {
+ Invalid,
+ Boolean,
+ Number,
+ String,
+ Script
+ };
+
+ Variant();
+ Variant(const Variant &);
+ Variant(bool);
+ Variant(double, const QString &asWritten=QString());
+ Variant(const QString &);
+ Variant(const QString &, QDeclarativeJS::AST::Node *);
+ Variant &operator=(const Variant &);
+
+ Type type() const;
+
+ bool isBoolean() const { return type() == Boolean; }
+ bool isNumber() const { return type() == Number; }
+ bool isString() const { return type() == String; }
+ bool isScript() const { return type() == Script; }
+ bool isStringList() const;
+
+ bool asBoolean() const;
+ QString asString() const;
+ double asNumber() const;
+ QString asScript() const;
+ QDeclarativeJS::AST::Node *asAST() const;
+ QStringList asStringList() const;
+
+ private:
+ Type t;
+ union {
+ bool b;
+ double d;
+ QDeclarativeJS::AST::Node *n;
+ };
+ QString s;
+ };
+
+ class Value : public QDeclarativeRefCount
+ {
+ public:
+ Value();
+ virtual ~Value();
+
+ enum Type {
+ // The type of this value assignment is not yet known
+ Unknown,
+ // This is used as a literal property assignment
+ Literal,
+ // This is used as a property binding assignment
+ PropertyBinding,
+ // This is used as a QDeclarativePropertyValueSource assignment
+ ValueSource,
+ // This is used as a QDeclarativePropertyValueInterceptor assignment
+ ValueInterceptor,
+ // This is used as a property QObject assignment
+ CreatedObject,
+ // This is used as a signal object assignment
+ SignalObject,
+ // This is used as a signal expression assignment
+ SignalExpression,
+ // This is used as an id assignment only
+ Id
+ };
+ Type type;
+
+ // ### Temporary (for id only)
+ QString primitive() const { return value.isString() ? value.asString() : value.asScript(); }
+
+ // Primitive value
+ Variant value;
+ // Object value
+ Object *object;
+
+ LocationSpan location;
+ };
+
+ class Property : public QDeclarativeRefCount
+ {
+ public:
+ Property();
+ Property(const QByteArray &n);
+ virtual ~Property();
+
+ // The Object to which this property is attached
+ Object *parent;
+
+ Object *getValue(const LocationSpan &);
+ void addValue(Value *v);
+ void addOnValue(Value *v);
+
+ // The QVariant::Type of the property, or 0 (QVariant::Invalid) if
+ // unknown.
+ int type;
+ // The metaobject index of this property, or -1 if unknown.
+ int index;
+
+ // Returns true if this is an empty property - both value and values
+ // are unset.
+ bool isEmpty() const;
+ // The list of values assigned to this property. Content in values
+ // and value are mutually exclusive
+ QList<Value *> values;
+ // The list of values assigned to this property using the "on" syntax
+ QList<Value *> onValues;
+ // The accessed property. This is used to represent dot properties.
+ // Content in value and values are mutually exclusive.
+ Object *value;
+ // The property name
+ QByteArray name;
+ // True if this property was accessed as the default property.
+ bool isDefault;
+ // True if the setting of this property will be deferred. Set by the
+ // QDeclarativeCompiler
+ bool isDeferred;
+ // True if this property is a value-type pseudo-property
+ bool isValueTypeSubProperty;
+ // True if this property is a property alias. Set by the
+ // QDeclarativeCompiler
+ bool isAlias;
+
+ LocationSpan location;
+ LocationRange listValueRange;
+ QList<int> listCommaPositions;
+ };
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeParser::Object::ScriptBlock::Pragmas);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeParser::Variant)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPARSER_P_H
diff --git a/src/declarative/qml/qdeclarativeparserstatus.cpp b/src/declarative/qml/qdeclarativeparserstatus.cpp
new file mode 100644
index 0000000000..836e1a6bd8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeparserstatus.cpp
@@ -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 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"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativeParserStatus
+ \since 4.7
+ \brief The QDeclarativeParserStatus class provides updates on the QML parser state.
+
+ QDeclarativeParserStatus provides a mechanism for classes instantiated by
+ a QDeclarativeEngine to receive notification at key points in their creation.
+
+ This class is often used for optimization purposes, as it allows you to defer an
+ expensive operation until after all the properties have been set on an
+ object. For example, QML's \l {Text} element uses the parser status
+ to defer text layout until all of its properties have been set (we
+ don't want to layout when the \c text is assigned, and then relayout
+ when the \c font is assigned, and relayout again when the \c width is assigned,
+ and so on).
+
+ To use QDeclarativeParserStatus, you must inherit both a QObject-derived class
+ and QDeclarativeParserStatus, and use the Q_INTERFACES() macro.
+
+ \code
+ class MyObject : public QObject, public QDeclarativeParserStatus
+ {
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+
+ public:
+ MyObject(QObject *parent = 0);
+ ...
+ void classBegin();
+ void componentComplete();
+ }
+ \endcode
+*/
+
+/*! \internal */
+QDeclarativeParserStatus::QDeclarativeParserStatus()
+: d(0)
+{
+}
+
+/*! \internal */
+QDeclarativeParserStatus::~QDeclarativeParserStatus()
+{
+ if(d)
+ (*d) = 0;
+}
+
+/*!
+ \fn void QDeclarativeParserStatus::classBegin()
+
+ Invoked after class creation, but before any properties have been set.
+*/
+
+/*!
+ \fn void QDeclarativeParserStatus::componentComplete()
+
+ Invoked after the root component that caused this instantiation has
+ completed construction. At this point all static values and binding values
+ have been assigned to the class.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeparserstatus.h b/src/declarative/qml/qdeclarativeparserstatus.h
new file mode 100644
index 0000000000..cebcee11e9
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeparserstatus.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 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 QDECLARATIVEPARSERSTATUS_H
+#define QDECLARATIVEPARSERSTATUS_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QDeclarativeParserStatus
+{
+public:
+ QDeclarativeParserStatus();
+ virtual ~QDeclarativeParserStatus();
+
+ virtual void classBegin()=0;
+ virtual void componentComplete()=0;
+
+private:
+ friend class QDeclarativeVME;
+ friend class QDeclarativeComponent;
+ friend class QDeclarativeComponentPrivate;
+ friend class QDeclarativeEnginePrivate;
+ QDeclarativeParserStatus **d;
+};
+Q_DECLARE_INTERFACE(QDeclarativeParserStatus, "com.trolltech.qml.QDeclarativeParserStatus")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPARSERSTATUS_H
diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h
new file mode 100644
index 0000000000..7ac3369fc7
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeprivate.h
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPRIVATE_H
+#define QDECLARATIVEPRIVATE_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/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+typedef QObject *(*QDeclarativeAttachedPropertiesFunc)(QObject *);
+
+template <typename TYPE>
+class QDeclarativeTypeInfo
+{
+public:
+ enum {
+ hasAttachedProperties = 0
+ };
+};
+
+
+class QDeclarativeCustomParser;
+namespace QDeclarativePrivate
+{
+ void Q_DECLARATIVE_EXPORT qdeclarativeelement_destructor(QObject *);
+ template<typename T>
+ class QDeclarativeElement : public T
+ {
+ public:
+ virtual ~QDeclarativeElement() {
+ QDeclarativePrivate::qdeclarativeelement_destructor(this);
+ }
+ };
+
+ template<typename T>
+ void createInto(void *memory) { new (memory) QDeclarativeElement<T>; }
+
+ template<typename T>
+ QObject *createParent(QObject *p) { return new T(p); }
+
+ template<class From, class To, int N>
+ struct StaticCastSelectorClass
+ {
+ static inline int cast() { return -1; }
+ };
+
+ template<class From, class To>
+ struct StaticCastSelectorClass<From, To, sizeof(int)>
+ {
+ static inline int cast() { return int(reinterpret_cast<quintptr>(static_cast<To *>(reinterpret_cast<From *>(0x10000000)))) - 0x10000000; }
+ };
+
+ template<class From, class To>
+ struct StaticCastSelector
+ {
+ typedef int yes_type;
+ typedef char no_type;
+
+ static yes_type check(To *);
+ static no_type check(...);
+
+ static inline int cast()
+ {
+ return StaticCastSelectorClass<From, To, sizeof(check(reinterpret_cast<From *>(0)))>::cast();
+ }
+ };
+
+ template <typename T>
+ struct has_attachedPropertiesMember
+ {
+ static bool const value = QDeclarativeTypeInfo<T>::hasAttachedProperties;
+ };
+
+ template <typename T, bool hasMember>
+ class has_attachedPropertiesMethod
+ {
+ public:
+ typedef int yes_type;
+ typedef char no_type;
+
+ template<typename ReturnType>
+ static yes_type check(ReturnType *(*)(QObject *));
+ static no_type check(...);
+
+ static bool const value = sizeof(check(&T::qmlAttachedProperties)) == sizeof(yes_type);
+ };
+
+ template <typename T>
+ class has_attachedPropertiesMethod<T, false>
+ {
+ public:
+ static bool const value = false;
+ };
+
+ template<typename T, int N>
+ class AttachedPropertySelector
+ {
+ public:
+ static inline QDeclarativeAttachedPropertiesFunc func() { return 0; }
+ static inline const QMetaObject *metaObject() { return 0; }
+ };
+ template<typename T>
+ class AttachedPropertySelector<T, 1>
+ {
+ static inline QObject *attachedProperties(QObject *obj) {
+ return T::qmlAttachedProperties(obj);
+ }
+ template<typename ReturnType>
+ static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) {
+ return &ReturnType::staticMetaObject;
+ }
+ public:
+ static inline QDeclarativeAttachedPropertiesFunc func() {
+ return &attachedProperties;
+ }
+ static inline const QMetaObject *metaObject() {
+ return attachedPropertiesMetaObject(&T::qmlAttachedProperties);
+ }
+ };
+
+ template<typename T>
+ inline QDeclarativeAttachedPropertiesFunc attachedPropertiesFunc()
+ {
+ return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func();
+ }
+
+ template<typename T>
+ inline const QMetaObject *attachedPropertiesMetaObject()
+ {
+ return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject();
+ }
+
+ enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
+ typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
+
+ struct RegisterType {
+ int version;
+
+ int typeId;
+ int listId;
+ int objectSize;
+ void (*create)(void *);
+ QString noCreationReason;
+
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+ const char *elementName;
+ const QMetaObject *metaObject;
+
+ QDeclarativeAttachedPropertiesFunc attachedPropertiesFunction;
+ const QMetaObject *attachedPropertiesMetaObject;
+
+ int parserStatusCast;
+ int valueSourceCast;
+ int valueInterceptorCast;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QDeclarativeCustomParser *customParser;
+ int revision;
+ // If this is extended ensure "version" is bumped!!!
+ };
+
+ struct RegisterInterface {
+ int version;
+
+ int typeId;
+ int listId;
+
+ const char *iid;
+ };
+
+ struct RegisterAutoParent {
+ int version;
+
+ AutoParentFunction function;
+ };
+
+ enum RegistrationType {
+ TypeRegistration = 0,
+ InterfaceRegistration = 1,
+ AutoParentRegistration = 2
+ };
+
+ int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPRIVATE_H
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
new file mode 100644
index 0000000000..7f74da4ee6
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -0,0 +1,1649 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+
+#include "qdeclarative.h"
+#include "private/qdeclarativebinding_p.h"
+#include "qdeclarativecontext.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativeboundsignal_p.h"
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qdeclarativelist_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+
+#include <QStringList>
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QDeclarativeProperty
+\since 4.7
+\brief The QDeclarativeProperty class abstracts accessing properties on objects created from QML.
+
+As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect
+and interact with objects created by QML. However, some of the new features provided by QML - such
+as type safety and attached properties - are most easily used through the QDeclarativeProperty class
+that simplifies some of their natural complexity.
+
+Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates
+a property on a specific object instance. To read a property's value, programmers create a
+QDeclarativeProperty instance and call the read() method. Likewise to write a property value the
+write() method is used.
+
+For example, for the following QML code:
+
+\qml
+// MyItem.qml
+import QtQuick 1.0
+
+Text { text: "A bit of text" }
+\endqml
+
+The \l Text object's properties could be accessed using QDeclarativeProperty, like this:
+
+\code
+#include <QDeclarativeProperty>
+#include <QGraphicsObject>
+
+...
+
+QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
+QDeclarativeProperty property(view.rootObject(), "font.pixelSize");
+qWarning() << "Current pixel size:" << property.read().toInt();
+property.write(24);
+qWarning() << "Pixel size should now be 24:" << property.read().toInt();
+\endcode
+*/
+
+/*!
+ Create an invalid QDeclarativeProperty.
+*/
+QDeclarativeProperty::QDeclarativeProperty()
+: d(0)
+{
+}
+
+/*! \internal */
+QDeclarativeProperty::~QDeclarativeProperty()
+{
+ if (d)
+ d->release();
+ d = 0;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj. If there is no
+ default property, an invalid QDeclarativeProperty will be created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj
+ using the \l{QDeclarativeContext} {context} \a ctxt. If there is
+ no default property, an invalid QDeclarativeProperty will be
+ created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initDefault(obj);
+}
+
+/*!
+ Creates a QDeclarativeProperty for the default property of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine. If there is no default property, an
+ invalid QDeclarativeProperty will be created.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine)
+ : d(new QDeclarativePropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initDefault(obj);
+}
+
+/*!
+ Initialize from the default property of \a obj
+*/
+void QDeclarativePropertyPrivate::initDefault(QObject *obj)
+{
+ if (!obj)
+ return;
+
+ QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj);
+ core.load(p);
+ if (core.isValid())
+ object = obj;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->initProperty(obj, name);
+ if (!isValid()) d->object = 0;
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj
+ using the \l{QDeclarativeContext} {context} \a ctxt.
+*/
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = ctxt?QDeclarativeContextData::get(ctxt):0;
+ d->engine = ctxt?ctxt->engine():0;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+/*!
+ Creates a QDeclarativeProperty for the property \a name of \a obj
+ using the environment for instantiating QML components that is
+ provided by \a engine.
+ */
+QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine)
+: d(new QDeclarativePropertyPrivate)
+{
+ d->context = 0;
+ d->engine = engine;
+ d->initProperty(obj, name);
+ if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; }
+}
+
+Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes);
+
+void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name)
+{
+ if (!obj) return;
+
+ QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0;
+
+ QStringList path = name.split(QLatin1Char('.'));
+ if (path.isEmpty()) return;
+
+ QObject *currentObject = obj;
+
+ // Everything up to the last property must be an "object type" property
+ for (int ii = 0; ii < path.count() - 1; ++ii) {
+ const QString &pathName = path.at(ii);
+
+ if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) {
+ if (data->type) {
+ QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ } else {
+ Q_ASSERT(data->typeNamespace);
+ if ((ii + 1) == path.count()) return; // No type following the namespace
+
+ ++ii; data = data->typeNamespace->data(path.at(ii));
+ if (!data || !data->type) return; // Invalid type in namespace
+
+ QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction();
+ if (!func) return; // Not an attachable type
+
+ currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject);
+ if (!currentObject) return; // Something is broken with the attachable type
+ }
+ } else {
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *property =
+ QDeclarativePropertyCache::property(engine, obj, pathName, local);
+
+ if (!property) return; // Not a property
+ if (property->flags & QDeclarativePropertyCache::Data::IsFunction)
+ return; // Not an object property
+
+ if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) {
+ // We're now at a value type property. We can use a global valuetypes array as we
+ // never actually use the objects, just look up their properties.
+ QObject *typeObject = (*qmlValueTypes())[property->propType];
+ if (!typeObject) return; // Not a value type
+
+ int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData());
+ if (idx == -1) return; // Value type property does not exist
+
+ QMetaProperty vtProp = typeObject->metaObject()->property(idx);
+
+ object = currentObject;
+ core = *property;
+ valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp);
+ valueType.valueTypeCoreIdx = idx;
+ valueType.valueTypePropType = vtProp.userType();
+
+ return;
+ } else {
+ if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived))
+ return; // Not an object property
+
+ void *args[] = { &currentObject, 0 };
+ QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args);
+ if (!currentObject) return; // No value
+
+ }
+ }
+
+ }
+
+ const QString &terminal = path.last();
+
+ if (terminal.count() >= 3 &&
+ terminal.at(0) == QLatin1Char('o') &&
+ terminal.at(1) == QLatin1Char('n') &&
+ terminal.at(2).isUpper()) {
+
+ QString signalName = terminal.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData());
+ if (method.signature()) {
+ object = currentObject;
+ core.load(method);
+ return;
+ }
+ }
+
+ // Property
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *property =
+ QDeclarativePropertyCache::property(engine, currentObject, terminal, local);
+ if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) {
+ object = currentObject;
+ core = *property;
+ nameCache = terminal;
+ isNameCached = true;
+ }
+}
+
+/*!
+ Create a copy of \a other.
+*/
+QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other)
+{
+ d = other.d;
+ if (d)
+ d->addref();
+}
+
+/*!
+ \enum QDeclarativeProperty::PropertyTypeCategory
+
+ This enum specifies a category of QML property.
+
+ \value InvalidCategory The property is invalid, or is a signal property.
+ \value List The property is a QDeclarativeListProperty list property
+ \value Object The property is a QObject derived type pointer
+ \value Normal The property is a normal value property.
+ */
+
+/*!
+ \enum QDeclarativeProperty::Type
+
+ This enum specifies a type of QML property.
+
+ \value Invalid The property is invalid.
+ \value Property The property is a regular Qt property.
+ \value SignalProperty The property is a signal property.
+*/
+
+/*!
+ Returns the property category.
+*/
+QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const
+{
+ return d ? d->propertyTypeCategory() : InvalidCategory;
+}
+
+QDeclarativeProperty::PropertyTypeCategory
+QDeclarativePropertyPrivate::propertyTypeCategory() const
+{
+ uint type = this->type();
+
+ if (isValueType()) {
+ return QDeclarativeProperty::Normal;
+ } else if (type & QDeclarativeProperty::Property) {
+ int type = propertyType();
+ if (type == QVariant::Invalid)
+ return QDeclarativeProperty::InvalidCategory;
+ else if (QDeclarativeValueTypeFactory::isValueType((uint)type))
+ return QDeclarativeProperty::Normal;
+ else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived)
+ return QDeclarativeProperty::Object;
+ else if (core.flags & QDeclarativePropertyCache::Data::IsQList)
+ return QDeclarativeProperty::List;
+ else
+ return QDeclarativeProperty::Normal;
+ } else {
+ return QDeclarativeProperty::InvalidCategory;
+ }
+}
+
+/*!
+ Returns the type name of the property, or 0 if the property has no type
+ name.
+*/
+const char *QDeclarativeProperty::propertyTypeName() const
+{
+ if (!d)
+ return 0;
+ if (d->isValueType()) {
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context);
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName();
+
+ if (!ep) delete valueType;
+
+ return rv;
+ } else if (d->object && type() & Property && d->core.isValid()) {
+ return d->object->metaObject()->property(d->core.coreIndex).typeName();
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns true if \a other and this QDeclarativeProperty represent the same
+ property.
+*/
+bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const
+{
+ if (!d || !other.d)
+ return false;
+ // category is intentially omitted here as it is generated
+ // from the other members
+ return d->object == other.d->object &&
+ d->core == other.d->core &&
+ d->valueType == other.d->valueType;
+}
+
+/*!
+ Returns the QVariant type of the property, or QVariant::Invalid if the
+ property has no QVariant type.
+*/
+int QDeclarativeProperty::propertyType() const
+{
+ return d ? d->propertyType() : int(QVariant::Invalid);
+}
+
+bool QDeclarativePropertyPrivate::isValueType() const
+{
+ return valueType.valueTypeCoreIdx != -1;
+}
+
+int QDeclarativePropertyPrivate::propertyType() const
+{
+ uint type = this->type();
+ if (isValueType()) {
+ return valueType.valueTypePropType;
+ } else if (type & QDeclarativeProperty::Property) {
+ if (core.propType == (int)QVariant::LastType)
+ return qMetaTypeId<QVariant>();
+ else
+ return core.propType;
+ } else {
+ return QVariant::Invalid;
+ }
+}
+
+QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const
+{
+ if (core.flags & QDeclarativePropertyCache::Data::IsFunction)
+ return QDeclarativeProperty::SignalProperty;
+ else if (core.isValid())
+ return QDeclarativeProperty::Property;
+ else
+ return QDeclarativeProperty::Invalid;
+}
+
+/*!
+ Returns the type of the property.
+*/
+QDeclarativeProperty::Type QDeclarativeProperty::type() const
+{
+ return d ? d->type() : Invalid;
+}
+
+/*!
+ Returns true if this QDeclarativeProperty represents a regular Qt property.
+*/
+bool QDeclarativeProperty::isProperty() const
+{
+ return type() & Property;
+}
+
+/*!
+ Returns true if this QDeclarativeProperty represents a QML signal property.
+*/
+bool QDeclarativeProperty::isSignalProperty() const
+{
+ return type() & SignalProperty;
+}
+
+/*!
+ Returns the QDeclarativeProperty's QObject.
+*/
+QObject *QDeclarativeProperty::object() const
+{
+ return d ? d->object : 0;
+}
+
+/*!
+ Assign \a other to this QDeclarativeProperty.
+*/
+QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other)
+{
+ if (d)
+ d->release();
+ d = other.d;
+ if (d)
+ d->addref();
+
+ return *this;
+}
+
+/*!
+ Returns true if the property is writable, otherwise false.
+*/
+bool QDeclarativeProperty::isWritable() const
+{
+ if (!d)
+ return false;
+ if (!d->object)
+ return false;
+ if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list
+ return true;
+ else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler
+ return false;
+ else if (d->core.isValid()) //normal property
+ return d->core.flags & QDeclarativePropertyCache::Data::IsWritable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is designable, otherwise false.
+*/
+bool QDeclarativeProperty::isDesignable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex).isDesignable();
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is resettable, otherwise false.
+*/
+bool QDeclarativeProperty::isResettable() const
+{
+ if (!d)
+ return false;
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->core.flags & QDeclarativePropertyCache::Data::IsResettable;
+ else
+ return false;
+}
+
+/*!
+ Returns true if the QDeclarativeProperty refers to a valid property, otherwise
+ false.
+*/
+bool QDeclarativeProperty::isValid() const
+{
+ if (!d)
+ return false;
+ return type() != Invalid;
+}
+
+/*!
+ Return the name of this QML property.
+*/
+QString QDeclarativeProperty::name() const
+{
+ if (!d)
+ return QString();
+ if (!d->isNameCached) {
+ // ###
+ if (!d->object) {
+ } else if (d->isValueType()) {
+ QString rv = d->core.name(d->object) + QLatin1Char('.');
+
+ QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0;
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[d->core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType);
+ Q_ASSERT(valueType);
+
+ rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name());
+
+ if (!ep) delete valueType;
+
+ d->nameCache = rv;
+ } else if (type() & SignalProperty) {
+ QString name = QLatin1String("on") + d->core.name(d->object);
+ name[2] = name.at(2).toUpper();
+ d->nameCache = name;
+ } else {
+ d->nameCache = d->core.name(d->object);
+ }
+ d->isNameCached = true;
+ }
+
+ return d->nameCache;
+}
+
+/*!
+ Returns the \l{QMetaProperty} {Qt property} associated with
+ this QML property.
+ */
+QMetaProperty QDeclarativeProperty::property() const
+{
+ if (!d)
+ return QMetaProperty();
+ if (type() & Property && d->core.isValid() && d->object)
+ return d->object->metaObject()->property(d->core.coreIndex);
+ else
+ return QMetaProperty();
+}
+
+/*!
+ Return the QMetaMethod for this property if it is a SignalProperty,
+ otherwise returns an invalid QMetaMethod.
+*/
+QMetaMethod QDeclarativeProperty::method() const
+{
+ if (!d)
+ return QMetaMethod();
+ if (type() & SignalProperty && d->object)
+ return d->object->metaObject()->method(d->core.coreIndex);
+ else
+ return QMetaMethod();
+}
+
+/*!
+ Returns the binding associated with this property, or 0 if no binding
+ exists.
+*/
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that)
+{
+ if (!that.d || !that.isProperty() || !that.d->object)
+ return 0;
+
+ return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx);
+}
+
+/*!
+ Set the binding associated with this property to \a newBinding. Returns
+ the existing binding (if any), otherwise 0.
+
+ \a newBinding will be enabled, and the returned binding (if any) will be
+ disabled.
+
+ Ownership of \a newBinding transfers to QML. Ownership of the return value
+ is assumed by the caller.
+
+ \a flags is passed through to the binding and is used for the initial update (when
+ the binding sets the initial value, it will use these flags for the write).
+*/
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that,
+ QDeclarativeAbstractBinding *newBinding,
+ WriteFlags flags)
+{
+ if (!that.d || !that.isProperty() || !that.d->object) {
+ if (newBinding)
+ newBinding->destroy();
+ return 0;
+ }
+
+ return that.d->setBinding(that.d->object, that.d->core.coreIndex,
+ that.d->valueType.valueTypeCoreIdx, newBinding, flags);
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object);
+ if (!data)
+ return 0;
+
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1)
+ return 0;
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex);
+ }
+
+ if (!data->hasBindingBit(coreIndex))
+ return 0;
+
+ QDeclarativeAbstractBinding *binding = data->bindings;
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+
+ if (binding && valueTypeIndex != -1) {
+ if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) {
+ int index = coreIndex | (valueTypeIndex << 24);
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+ }
+ }
+
+ return binding;
+}
+
+void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex,
+ QObject **targetObject, int *targetBindingIndex)
+{
+ int coreIndex = bindingIndex & 0xFFFFFF;
+ int valueTypeIndex = bindingIndex >> 24;
+ if (valueTypeIndex == 0) valueTypeIndex = -1;
+
+ QDeclarativeData *data = QDeclarativeData::get(object, false);
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+
+ int aBindingIndex = aCoreIndex;
+ if (aValueTypeIndex != -1)
+ aBindingIndex |= aValueTypeIndex << 24;
+ else if (valueTypeIndex != -1)
+ aBindingIndex |= valueTypeIndex << 24;
+
+ findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex);
+ return;
+ }
+ }
+ }
+
+ *targetObject = object;
+ *targetBindingIndex = bindingIndex;
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex,
+ QDeclarativeAbstractBinding *newBinding, WriteFlags flags)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
+ QDeclarativeAbstractBinding *binding = 0;
+
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
+ newBinding, flags);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding) {
+ binding->removeFromObject();
+ binding->setEnabled(false, 0);
+ }
+
+ if (newBinding) {
+ newBinding->addToObject(object, index);
+ newBinding->setEnabled(true, flags);
+ }
+
+ return binding;
+}
+
+QDeclarativeAbstractBinding *
+QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex,
+ QDeclarativeAbstractBinding *newBinding)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding);
+ QDeclarativeAbstractBinding *binding = 0;
+
+ if (data) {
+ QDeclarativePropertyCache::Data *propertyData =
+ data->propertyCache?data->propertyCache->property(coreIndex):0;
+ if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) {
+ const QDeclarativeVMEMetaObject *vme =
+ static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex));
+
+ QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1;
+ if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) {
+ if (newBinding) newBinding->destroy();
+ return 0;
+ }
+
+ // This will either be a value type sub-reference or an alias to a value-type sub-reference not both
+ Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1);
+ return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex,
+ newBinding);
+ }
+ }
+
+ if (data && data->hasBindingBit(coreIndex)) {
+ binding = data->bindings;
+
+ while (binding && binding->propertyIndex() != coreIndex)
+ binding = binding->m_nextBinding;
+ }
+
+ int index = coreIndex;
+ if (valueTypeIndex != -1)
+ index |= (valueTypeIndex << 24);
+
+ if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy)
+ binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index);
+
+ if (binding)
+ binding->removeFromObject();
+
+ if (newBinding)
+ newBinding->addToObject(object, index);
+
+ return binding;
+}
+
+/*!
+ Returns the expression associated with this signal property, or 0 if no
+ signal expression exists.
+*/
+QDeclarativeExpression *
+QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that)
+{
+ if (!(that.type() & QDeclarativeProperty::SignalProperty))
+ return 0;
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->expression();
+ }
+
+ return 0;
+}
+
+/*!
+ Set the signal expression associated with this signal property to \a expr.
+ Returns the existing signal expression (if any), otherwise 0.
+
+ Ownership of \a expr transfers to QML. Ownership of the return value is
+ assumed by the caller.
+*/
+QDeclarativeExpression *
+QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that,
+ QDeclarativeExpression *expr)
+{
+ if (!(that.type() & QDeclarativeProperty::SignalProperty)) {
+ delete expr;
+ return 0;
+ }
+
+ const QObjectList &children = that.d->object->children();
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal && signal->index() == that.index())
+ return signal->setExpression(expr);
+ }
+
+ if (expr) {
+ QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object);
+ return signal->setExpression(expr);
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Returns the property value.
+*/
+QVariant QDeclarativeProperty::read() const
+{
+ if (!d)
+ return QVariant();
+ if (!d->object)
+ return QVariant();
+
+ if (type() & SignalProperty) {
+
+ return QVariant();
+
+ } else if (type() & Property) {
+
+ return d->readValueProperty();
+
+ }
+ return QVariant();
+}
+
+/*!
+Return the \a name property value of \a object. This method is equivalent to:
+\code
+ QDeclarativeProperty p(object, name);
+ p.read();
+\endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name)
+{
+ QDeclarativeProperty p(object, name);
+ return p.read();
+}
+
+/*!
+ Return the \a name property value of \a object using the
+ \l{QDeclarativeContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, context);
+ p.read();
+ \endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt)
+{
+ QDeclarativeProperty p(object, name, ctxt);
+ return p.read();
+}
+
+/*!
+
+ Return the \a name property value of \a object using the environment
+ for instantiating QML components that is provided by \a engine. .
+ This method is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, engine);
+ p.read();
+ \endcode
+*/
+QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine)
+{
+ QDeclarativeProperty p(object, name, engine);
+ return p.read();
+}
+
+QVariant QDeclarativePropertyPrivate::readValueProperty()
+{
+ if (isValueType()) {
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[core.propType];
+ else valueType = QDeclarativeValueTypeFactory::valueType(core.propType);
+ Q_ASSERT(valueType);
+
+ valueType->read(object, core.coreIndex);
+
+ QVariant rv =
+ valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType);
+
+ if (!ep) delete valueType;
+ return rv;
+
+ } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) {
+
+ QDeclarativeListProperty<QObject> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine));
+
+ } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args);
+ return QVariant::fromValue(rv);
+
+ } else {
+
+ return object->metaObject()->property(core.coreIndex).read(object.data());
+
+ }
+}
+
+//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
+bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags)
+{
+ if (!object || !prop.isWritable())
+ return false;
+
+ QVariant v = value;
+ if (prop.isEnumType()) {
+ QMetaEnum menum = prop.enumerator();
+ if (v.userType() == QVariant::String
+#ifdef QT3_SUPPORT
+ || v.userType() == QVariant::CString
+#endif
+ ) {
+ if (prop.isFlagType())
+ v = QVariant(menum.keysToValue(value.toByteArray()));
+ else
+ v = QVariant(menum.keyToValue(value.toByteArray()));
+ } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
+ int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
+ if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData())
+ return false;
+ v = QVariant(*reinterpret_cast<const int *>(v.constData()));
+ }
+ v.convert(QVariant::Int);
+ }
+
+ // the status variable is changed by qt_metacall to indicate what it did
+ // this feature is currently only used by QtDBus and should not be depended
+ // upon. Don't change it without looking into QDBusAbstractInterface first
+ // -1 (unchanged): normal qt_metacall, result stored in argv[0]
+ // changed: result stored directly in value, return the value of status
+ int status = -1;
+ void *argv[] = { v.data(), &v, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv);
+ return status;
+}
+
+bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags)
+{
+ // Remove any existing bindings on this property
+ if (!(flags & DontRemoveBinding) &&
+ (type() & QDeclarativeProperty::Property) && object) {
+ QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex,
+ valueType.valueTypeCoreIdx, 0, flags);
+ if (binding) binding->destroy();
+ }
+
+ bool rv = false;
+ if (isValueType()) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context);
+
+ QDeclarativeValueType *writeBack = 0;
+ if (ep) {
+ writeBack = ep->valueTypes[core.propType];
+ } else {
+ writeBack = QDeclarativeValueTypeFactory::valueType(core.propType);
+ }
+
+ writeBack->read(object, core.coreIndex);
+
+ QDeclarativePropertyCache::Data data = core;
+ data.flags = valueType.flags;
+ data.coreIndex = valueType.valueTypeCoreIdx;
+ data.propType = valueType.valueTypePropType;
+ rv = write(writeBack, data, value, context, flags);
+
+ writeBack->write(object, core.coreIndex, flags);
+ if (!ep) delete writeBack;
+
+ } else {
+
+ rv = write(object, core, value, context, flags);
+
+ }
+
+ return rv;
+}
+
+bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property,
+ const QVariant &value, QDeclarativeContextData *context,
+ WriteFlags flags)
+{
+ int coreIdx = property.coreIndex;
+ int status = -1; //for dbus
+
+ if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) {
+ QMetaProperty prop = object->metaObject()->property(property.coreIndex);
+ QVariant v = value;
+ // Enum values come through the script engine as doubles
+ if (value.userType() == QVariant::Double) {
+ double integral;
+ double fractional = modf(value.toDouble(), &integral);
+ if (qFuzzyIsNull(fractional))
+ v.convert(QVariant::Int);
+ }
+ return writeEnumProperty(prop, coreIdx, object, v, flags);
+ }
+
+ int propertyType = property.propType;
+ int variantType = value.userType();
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context);
+
+ if (propertyType == QVariant::Url) {
+
+ QUrl u;
+ bool found = false;
+ if (variantType == QVariant::Url) {
+ u = value.toUrl();
+ found = true;
+ } else if (variantType == QVariant::ByteArray) {
+ u = QUrl(QString::fromUtf8(value.toByteArray()));
+ found = true;
+ } else if (variantType == QVariant::String) {
+ u = QUrl(value.toString());
+ found = true;
+ }
+
+ if (!found)
+ return false;
+
+ if (context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ int status = -1;
+ void *argv[] = { &u, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv);
+
+ } else if (variantType == propertyType) {
+
+ void *a[] = { (void *)value.constData(), 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (qMetaTypeId<QVariant>() == propertyType) {
+
+ void *a[] = { (void *)&value, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+
+ } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
+
+ const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType());
+
+ if (!valMo)
+ return false;
+
+ QObject *o = *(QObject **)value.constData();
+ const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType);
+
+ if (o) valMo = o->metaObject();
+
+ if (canConvert(valMo, propMo)) {
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else if (!o && canConvert(propMo, valMo)) {
+ // In the case of a null QObject, we assign the null if there is
+ // any change that the null variant type could be up or down cast to
+ // the property type.
+ void *args[] = { &o, 0, &status, &flags };
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx,
+ args);
+ } else {
+ return false;
+ }
+
+ } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) {
+
+ const QMetaObject *listType = 0;
+ if (enginePriv) {
+ listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType));
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType));
+ if (!type) return false;
+ listType = type->baseMetaObject();
+ }
+ if (!listType) return false;
+
+ QDeclarativeListProperty<void> prop;
+ void *args[] = { &prop, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args);
+
+ if (!prop.clear) return false;
+
+ prop.clear(&prop);
+
+ if (value.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *o = list.at(ii);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+ } else {
+ QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value);
+ if (o && !canConvert(o->metaObject(), listType))
+ o = 0;
+ prop.append(&prop, (void *)o);
+ }
+
+ } else {
+ Q_ASSERT(variantType != propertyType);
+
+ bool ok = false;
+ QVariant v;
+ if (variantType == QVariant::String)
+ v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok);
+ if (!ok) {
+ v = value;
+ if (v.convert((QVariant::Type)propertyType)) {
+ ok = true;
+ } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) {
+ QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType);
+ if (con) {
+ v = con(value.toString());
+ if (v.userType() == propertyType)
+ ok = true;
+ }
+ }
+ }
+ if (ok) {
+ void *a[] = { (void *)v.constData(), 0, &status, &flags};
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType)
+{
+ if (engine) {
+ return engine->rawMetaObjectForType(userType);
+ } else {
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType);
+ return type?type->baseMetaObject():0;
+ }
+}
+
+/*!
+ Sets the property value to \a value and returns true.
+ Returns false if the property can't be set because the
+ \a value is the wrong type, for example.
+ */
+bool QDeclarativeProperty::write(const QVariant &value) const
+{
+ return QDeclarativePropertyPrivate::write(*this, value, 0);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object. This method
+ is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value)
+{
+ QDeclarativeProperty p(object, name);
+ return p.write(value);
+}
+
+/*!
+ Writes \a value to the \a name property of \a object using the
+ \l{QDeclarativeContext} {context} \a ctxt. This method is
+ equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, ctxt);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object,
+ const QString &name,
+ const QVariant &value,
+ QDeclarativeContext *ctxt)
+{
+ QDeclarativeProperty p(object, name, ctxt);
+ return p.write(value);
+}
+
+/*!
+
+ Writes \a value to the \a name property of \a object using the
+ environment for instantiating QML components that is provided by
+ \a engine. This method is equivalent to:
+
+ \code
+ QDeclarativeProperty p(object, name, engine);
+ p.write(value);
+ \endcode
+*/
+bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value,
+ QDeclarativeEngine *engine)
+{
+ QDeclarativeProperty p(object, name, engine);
+ return p.write(value);
+}
+
+/*!
+ Resets the property and returns true if the property is
+ resettable. If the property is not resettable, nothing happens
+ and false is returned.
+*/
+bool QDeclarativeProperty::reset() const
+{
+ if (isResettable()) {
+ void *args[] = { 0 };
+ QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that,
+ const QVariant &value, WriteFlags flags)
+{
+ if (!that.d)
+ return false;
+ if (that.d->object && that.type() & QDeclarativeProperty::Property &&
+ that.d->core.isValid() && that.isWritable())
+ return that.d->writeValueProperty(value, flags);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a change notifier signal, otherwise false.
+*/
+bool QDeclarativeProperty::hasNotifySignal() const
+{
+ if (type() & Property && d->object) {
+ return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal();
+ }
+ return false;
+}
+
+/*!
+ Returns true if the property needs a change notifier signal for bindings
+ to remain upto date, false otherwise.
+
+ Some properties, such as attached properties or those whose value never
+ changes, do not require a change notifier.
+*/
+bool QDeclarativeProperty::needsNotifySignal() const
+{
+ return type() & Property && !property().isConstant();
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a method of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a method.
+*/
+bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Connects the property's change notifier signal to the
+ specified \a slot of the \a dest object and returns
+ true. Returns false if this metaproperty does not
+ represent a regular Qt property or if it has no
+ change notifier signal, or if the \a dest object does
+ not have the specified \a slot.
+*/
+bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const
+{
+ if (!(type() & Property) || !d->object)
+ return false;
+
+ QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex);
+ if (prop.hasNotifySignal()) {
+ QByteArray signal(QByteArray("2") + prop.notifySignal().signature());
+ return QObject::connect(d->object, signal.constData(), dest, slot);
+ } else {
+ return false;
+ }
+}
+
+/*!
+ Return the Qt metaobject index of the property.
+*/
+int QDeclarativeProperty::index() const
+{
+ return d ? d->core.coreIndex : -1;
+}
+
+int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that)
+{
+ return that.d ? that.d->valueType.valueTypeCoreIdx : -1;
+}
+
+/*!
+ Returns the "property index" for use in bindings. The top 8 bits are the value type
+ offset, and 0 otherwise. The bottom 24-bits are the regular property index.
+*/
+int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that)
+{
+ if (!that.d)
+ return -1;
+ int rv = that.d->core.coreIndex;
+ if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1)
+ rv = rv | (that.d->valueType.valueTypeCoreIdx << 24);
+ return rv;
+}
+
+struct SerializedData {
+ bool isValueType;
+ QDeclarativePropertyCache::Data core;
+};
+
+struct ValueTypeSerializedData : public SerializedData {
+ QDeclarativePropertyCache::ValueTypeData valueType;
+};
+
+QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index,
+ const QMetaObject *subObject, int subIndex)
+{
+ QMetaProperty prop = metaObject->property(index);
+ QMetaProperty subProp = subObject->property(subIndex);
+
+ ValueTypeSerializedData sd;
+ sd.isValueType = true;
+ sd.core.load(metaObject->property(index));
+ sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp);
+ sd.valueType.valueTypeCoreIdx = subIndex;
+ sd.valueType.valueTypePropType = subProp.userType();
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+
+ return rv;
+}
+
+QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index)
+{
+ SerializedData sd;
+ sd.isValueType = false;
+ sd.core.load(metaObject->property(index));
+
+ QByteArray rv((const char *)&sd, sizeof(sd));
+ return rv;
+}
+
+QDeclarativeProperty
+QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt)
+{
+ QDeclarativeProperty prop;
+
+ if (data.isEmpty())
+ return prop;
+
+ const SerializedData *sd = (const SerializedData *)data.constData();
+ if (sd->isValueType) {
+ const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd;
+ return restore(vt->core, vt->valueType, object, ctxt);
+ } else {
+ QDeclarativePropertyCache::ValueTypeData data;
+ return restore(sd->core, data, object, ctxt);
+ }
+}
+
+QDeclarativeProperty
+QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt)
+{
+ QDeclarativeProperty prop;
+
+ prop.d = new QDeclarativePropertyPrivate;
+ prop.d->object = object;
+ prop.d->context = ctxt;
+ prop.d->engine = ctxt->engine;
+
+ prop.d->core = data;
+ prop.d->valueType = valueType;
+
+ return prop;
+}
+
+/*!
+ Returns true if lhs and rhs refer to the same metaobject data
+*/
+bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs)
+{
+ return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+}
+
+/*!
+ Returns true if from inherits to.
+*/
+bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to)
+{
+ if (from && to == &QObject::staticMetaObject)
+ return true;
+
+ while (from) {
+ if (equal(from, to))
+ return true;
+ from = from->superClass();
+ }
+
+ return false;
+}
+
+/*!
+ Return the signal corresponding to \a name
+*/
+QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name)
+{
+ Q_ASSERT(mo);
+ int methods = mo->methodCount();
+ for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal
+ QMetaMethod method = mo->method(ii);
+ QByteArray methodName = method.signature();
+ int idx = methodName.indexOf('(');
+ methodName = methodName.left(idx);
+
+ if (methodName == name)
+ return method;
+ }
+
+ // If no signal is found, but the signal is of the form "onBlahChanged",
+ // return the notify signal for the property "Blah"
+ if (name.endsWith("Changed")) {
+ QByteArray propName = name.mid(0, name.length() - 7);
+ int propIdx = mo->indexOfProperty(propName.constData());
+ if (propIdx >= 0) {
+ QMetaProperty prop = mo->property(propIdx);
+ if (prop.hasNotifySignal())
+ return prop.notifySignal();
+ }
+ }
+
+ return QMetaMethod();
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static inline int QMetaObject_properties(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount;
+}
+
+static inline void flush_vme_signal(const QObject *object, int index)
+{
+ QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+ if (data && data->propertyCache) {
+ QDeclarativePropertyCache::Data *property = data->propertyCache->method(index);
+
+ if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) {
+ const QMetaObject *metaObject = object->metaObject();
+ int methodOffset = metaObject->methodOffset();
+
+ while (methodOffset > index) {
+ metaObject = metaObject->d.superdata;
+ methodOffset -= QMetaObject_methods(metaObject);
+ }
+
+ QDeclarativeVMEMetaObject *vme =
+ static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject));
+
+ vme->connectAliasSignal(index);
+ }
+ }
+}
+
+/*!
+Connect \a sender \a signal_index to \a receiver \a method_index with the specified
+\a type and \a types. This behaves identically to QMetaObject::connect() except that
+it connects any lazy "proxy" signal connections set up by QML.
+
+It is possible that this logic should be moved to QMetaObject::connect().
+*/
+bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type, int *types)
+{
+ flush_vme_signal(sender, signal_index);
+ flush_vme_signal(receiver, method_index);
+
+ return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
+}
+
+/*!
+Return \a metaObject's [super] meta object that provides data for \a property.
+*/
+const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property)
+{
+ int propertyOffset = metaObject->propertyOffset();
+
+ while (propertyOffset > property) {
+ metaObject = metaObject->d.superdata;
+ propertyOffset -= QMetaObject_properties(metaObject);
+ }
+
+ return metaObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeproperty.h b/src/declarative/qml/qdeclarativeproperty.h
new file mode 100644
index 0000000000..6d0e3f73c1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproperty.h
@@ -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 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 QDECLARATIVEPROPERTY_H
+#define QDECLARATIVEPROPERTY_H
+
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QObject;
+class QVariant;
+class QDeclarativeContext;
+class QDeclarativeEngine;
+
+class QDeclarativePropertyPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeProperty
+{
+public:
+ enum PropertyTypeCategory {
+ InvalidCategory,
+ List,
+ Object,
+ Normal
+ };
+
+ enum Type {
+ Invalid,
+ Property,
+ SignalProperty
+ };
+
+ QDeclarativeProperty();
+ ~QDeclarativeProperty();
+
+ QDeclarativeProperty(QObject *);
+ QDeclarativeProperty(QObject *, QDeclarativeContext *);
+ QDeclarativeProperty(QObject *, QDeclarativeEngine *);
+
+ QDeclarativeProperty(QObject *, const QString &);
+ QDeclarativeProperty(QObject *, const QString &, QDeclarativeContext *);
+ QDeclarativeProperty(QObject *, const QString &, QDeclarativeEngine *);
+
+ QDeclarativeProperty(const QDeclarativeProperty &);
+ QDeclarativeProperty &operator=(const QDeclarativeProperty &);
+
+ bool operator==(const QDeclarativeProperty &) const;
+
+ Type type() const;
+ bool isValid() const;
+ bool isProperty() const;
+ bool isSignalProperty() const;
+
+ int propertyType() const;
+ PropertyTypeCategory propertyTypeCategory() const;
+ const char *propertyTypeName() const;
+
+ QString name() const;
+
+ QVariant read() const;
+ static QVariant read(QObject *, const QString &);
+ static QVariant read(QObject *, const QString &, QDeclarativeContext *);
+ static QVariant read(QObject *, const QString &, QDeclarativeEngine *);
+
+ bool write(const QVariant &) const;
+ static bool write(QObject *, const QString &, const QVariant &);
+ static bool write(QObject *, const QString &, const QVariant &, QDeclarativeContext *);
+ static bool write(QObject *, const QString &, const QVariant &, QDeclarativeEngine *);
+
+ bool reset() const;
+
+ bool hasNotifySignal() const;
+ bool needsNotifySignal() const;
+ bool connectNotifySignal(QObject *dest, const char *slot) const;
+ bool connectNotifySignal(QObject *dest, int method) const;
+
+ bool isWritable() const;
+ bool isDesignable() const;
+ bool isResettable() const;
+ QObject *object() const;
+
+ int index() const;
+ QMetaProperty property() const;
+ QMetaMethod method() const;
+
+private:
+ friend class QDeclarativePropertyPrivate;
+ QDeclarativePropertyPrivate *d;
+};
+typedef QList<QDeclarativeProperty> QDeclarativeProperties;
+
+inline uint qHash (const QDeclarativeProperty &key)
+{
+ return qHash(key.object()) + qHash(key.name());
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROPERTY_H
diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h
new file mode 100644
index 0000000000..bd2c891de1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproperty_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPROPERTY_P_H
+#define QDECLARATIVEPROPERTY_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 "qdeclarativeproperty.h"
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContext;
+class QDeclarativeEnginePrivate;
+class QDeclarativeExpression;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePropertyPrivate : public QDeclarativeRefCount
+{
+public:
+ enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02, RemoveBindingOnAliasWrite = 0x04 };
+ Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
+
+ QDeclarativePropertyPrivate()
+ : context(0), engine(0), object(0), isNameCached(false) {}
+
+ QDeclarativeContextData *context;
+ QDeclarativeEngine *engine;
+ QDeclarativeGuard<QObject> object;
+
+ bool isNameCached:1;
+ QDeclarativePropertyCache::Data core;
+ QString nameCache;
+
+ // Describes the "virtual" value-type sub-property.
+ QDeclarativePropertyCache::ValueTypeData valueType;
+
+ void initProperty(QObject *obj, const QString &name);
+ void initDefault(QObject *obj);
+
+ bool isValueType() const;
+ int propertyType() const;
+ QDeclarativeProperty::Type type() const;
+ QDeclarativeProperty::PropertyTypeCategory propertyTypeCategory() const;
+
+ QVariant readValueProperty();
+ bool writeValueProperty(const QVariant &, WriteFlags);
+
+ static const QMetaObject *rawMetaObjectForType(QDeclarativeEnginePrivate *, int);
+ static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
+ const QVariant &value, int flags);
+ static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &,
+ QDeclarativeContextData *, WriteFlags flags = 0);
+ static void findAliasTarget(QObject *, int, QObject **, int *);
+ static QDeclarativeAbstractBinding *setBinding(QObject *, int coreIndex, int valueTypeIndex /* -1 */,
+ QDeclarativeAbstractBinding *,
+ WriteFlags flags = DontRemoveBinding);
+ static QDeclarativeAbstractBinding *setBindingNoEnable(QObject *, int coreIndex, int valueTypeIndex /* -1 */,
+ QDeclarativeAbstractBinding *);
+ static QDeclarativeAbstractBinding *binding(QObject *, int coreIndex, int valueTypeIndex /* -1 */);
+
+ static QByteArray saveValueType(const QMetaObject *, int,
+ const QMetaObject *, int);
+ static QByteArray saveProperty(const QMetaObject *, int);
+
+ static QDeclarativeProperty restore(const QByteArray &, QObject *, QDeclarativeContextData *);
+ static QDeclarativeProperty restore(const QDeclarativePropertyCache::Data &,
+ const QDeclarativePropertyCache::ValueTypeData &,
+ QObject *,
+ QDeclarativeContextData *);
+
+ static bool equal(const QMetaObject *, const QMetaObject *);
+ static bool canConvert(const QMetaObject *from, const QMetaObject *to);
+
+ // "Public" (to QML) methods
+ static QDeclarativeAbstractBinding *binding(const QDeclarativeProperty &that);
+ static QDeclarativeAbstractBinding *setBinding(const QDeclarativeProperty &that,
+ QDeclarativeAbstractBinding *,
+ WriteFlags flags = DontRemoveBinding);
+ static QDeclarativeExpression *signalExpression(const QDeclarativeProperty &that);
+ static QDeclarativeExpression *setSignalExpression(const QDeclarativeProperty &that,
+ QDeclarativeExpression *) ;
+ static bool write(const QDeclarativeProperty &that, const QVariant &, WriteFlags);
+ static int valueTypeCoreIndex(const QDeclarativeProperty &that);
+ static int bindingIndex(const QDeclarativeProperty &that);
+ static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
+ static bool connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index,
+ int type = 0, int *types = 0);
+ static const QMetaObject *metaObjectForProperty(const QMetaObject *, int);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyPrivate::WriteFlags)
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEPROPERTY_P_H
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
new file mode 100644
index 0000000000..6a39a65532
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -0,0 +1,471 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepropertycache_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include <QtCore/qdebug.h>
+
+Q_DECLARE_METATYPE(QScriptValue)
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine)
+{
+ int propType = p.userType();
+
+ Flags flags;
+
+ if (p.isConstant())
+ flags |= Data::IsConstant;
+ if (p.isWritable())
+ flags |= Data::IsWritable;
+ if (p.isResettable())
+ flags |= Data::IsResettable;
+
+ if (propType == qMetaTypeId<QDeclarativeBinding *>()) {
+ flags |= Data::IsQmlBinding;
+ } else if (propType == qMetaTypeId<QScriptValue>()) {
+ flags |= Data::IsQScriptValue;
+ } else if (p.isEnumType()) {
+ flags |= Data::IsEnumType;
+ } else {
+ QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType)
+ : QDeclarativeMetaType::typeCategory(propType);
+ if (cat == QDeclarativeMetaType::Object)
+ flags |= Data::IsQObjectDerived;
+ else if (cat == QDeclarativeMetaType::List)
+ flags |= Data::IsQList;
+ }
+
+ return flags;
+}
+
+void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeEngine *engine)
+{
+ propType = p.userType();
+ if (QVariant::Type(propType) == QVariant::LastType)
+ propType = qMetaTypeId<QVariant>();
+ coreIndex = p.propertyIndex();
+ notifyIndex = p.notifySignalIndex();
+ flags = flagsForProperty(p, engine);
+ revision = p.revision();
+}
+
+void QDeclarativePropertyCache::Data::load(const QMetaMethod &m)
+{
+ coreIndex = m.methodIndex();
+ relatedIndex = -1;
+ flags |= Data::IsFunction;
+ if (m.methodType() == QMetaMethod::Signal)
+ flags |= Data::IsSignal;
+ propType = QVariant::Invalid;
+
+ const char *returnType = m.typeName();
+ if (returnType)
+ propType = QMetaType::type(returnType);
+
+ QList<QByteArray> params = m.parameterTypes();
+ if (!params.isEmpty())
+ flags |= Data::HasArguments;
+ revision = m.revision();
+}
+
+
+/*!
+Creates a new empty QDeclarativePropertyCache.
+*/
+QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e)
+: QDeclarativeCleanup(e), engine(e)
+{
+ Q_ASSERT(engine);
+}
+
+/*!
+Creates a new QDeclarativePropertyCache of \a metaObject.
+*/
+QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject)
+: QDeclarativeCleanup(e), engine(e)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(metaObject);
+
+ update(engine, metaObject);
+}
+
+QDeclarativePropertyCache::~QDeclarativePropertyCache()
+{
+ clear();
+}
+
+void QDeclarativePropertyCache::clear()
+{
+ for (int ii = 0; ii < indexCache.count(); ++ii) {
+ if (indexCache.at(ii)) indexCache.at(ii)->release();
+ }
+
+ for (int ii = 0; ii < methodIndexCache.count(); ++ii) {
+ RData *data = methodIndexCache.at(ii);
+ if (data) data->release();
+ }
+
+ for (StringCache::ConstIterator iter = stringCache.begin();
+ iter != stringCache.end(); ++iter) {
+ RData *data = (*iter);
+ data->release();
+ }
+
+ for (IdentifierCache::ConstIterator iter = identifierCache.begin();
+ iter != identifierCache.end(); ++iter) {
+ RData *data = (*iter);
+ data->release();
+ }
+
+ indexCache.clear();
+ methodIndexCache.clear();
+ stringCache.clear();
+ identifierCache.clear();
+}
+
+QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject,
+ const QString &property)
+{
+ Q_ASSERT(metaObject);
+
+ QDeclarativePropertyCache::Data rv;
+ {
+ const QMetaObject *cmo = metaObject;
+ while (cmo) {
+ int idx = metaObject->indexOfProperty(property.toUtf8());
+ if (idx != -1) {
+ QMetaProperty p = metaObject->property(idx);
+ if (p.isScriptable()) {
+ rv.load(metaObject->property(idx));
+ return rv;
+ } else {
+ while (cmo && cmo->propertyOffset() >= idx)
+ cmo = cmo->superClass();
+ }
+ } else {
+ cmo = 0;
+ }
+ }
+ }
+
+ int methodCount = metaObject->methodCount();
+ for (int ii = methodCount - 1; ii >= 3; --ii) { // >=3 to block the destroyed signal and deleteLater() slot
+ QMetaMethod m = metaObject->method(ii);
+ if (m.access() == QMetaMethod::Private)
+ continue;
+ QString methodName = QString::fromUtf8(m.signature());
+
+ int parenIdx = methodName.indexOf(QLatin1Char('('));
+ Q_ASSERT(parenIdx != -1);
+ QStringRef methodNameRef = methodName.leftRef(parenIdx);
+
+ if (methodNameRef == property) {
+ rv.load(m);
+ return rv;
+ }
+ }
+
+ return rv;
+}
+
+QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const
+{
+ QDeclarativePropertyCache *cache = new QDeclarativePropertyCache(engine);
+ cache->indexCache = indexCache;
+ cache->methodIndexCache = methodIndexCache;
+ cache->stringCache = stringCache;
+ cache->identifierCache = identifierCache;
+ cache->allowedRevisionCache = allowedRevisionCache;
+
+ for (int ii = 0; ii < indexCache.count(); ++ii) {
+ if (indexCache.at(ii)) indexCache.at(ii)->addref();
+ }
+ for (int ii = 0; ii < methodIndexCache.count(); ++ii) {
+ if (methodIndexCache.at(ii)) methodIndexCache.at(ii)->addref();
+ }
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ (*iter)->addref();
+ for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter)
+ (*iter)->addref();
+
+ return cache;
+}
+
+void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject,
+ Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags)
+{
+ append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
+}
+
+void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject,
+ int revision,
+ Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags)
+{
+ Q_UNUSED(revision);
+
+ allowedRevisionCache.append(0);
+
+ QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+ int methodCount = metaObject->methodCount();
+ // 3 to block the destroyed signal and the deleteLater() slot
+ int methodOffset = qMax(3, metaObject->methodOffset());
+
+ methodIndexCache.resize(methodCount);
+ for (int ii = methodOffset; ii < methodCount; ++ii) {
+ QMetaMethod m = metaObject->method(ii);
+ if (m.access() == QMetaMethod::Private)
+ continue;
+ QString methodName = QString::fromUtf8(m.signature());
+
+ int parenIdx = methodName.indexOf(QLatin1Char('('));
+ Q_ASSERT(parenIdx != -1);
+ methodName = methodName.left(parenIdx);
+
+ RData *data = new RData;
+ data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName);
+ methodIndexCache[ii] = data;
+
+ data->load(m);
+ if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method)
+ data->flags |= methodFlags;
+ else if (m.methodType() == QMetaMethod::Signal)
+ data->flags |= signalFlags;
+
+ data->metaObjectOffset = allowedRevisionCache.count() - 1;
+
+ if (stringCache.contains(methodName)) {
+ RData *old = stringCache[methodName];
+ // We only overload methods in the same class, exactly like C++
+ if (old->flags & Data::IsFunction && old->coreIndex >= methodOffset)
+ data->relatedIndex = old->coreIndex;
+ data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
+ data->overrideIndex = old->coreIndex;
+ stringCache[methodName]->release();
+ identifierCache[data->identifier.identifier]->release();
+ }
+
+ stringCache.insert(methodName, data);
+ identifierCache.insert(data->identifier.identifier, data);
+ data->addref();
+ data->addref();
+ }
+
+ int propCount = metaObject->propertyCount();
+ int propOffset = metaObject->propertyOffset();
+
+ indexCache.resize(propCount);
+ for (int ii = propOffset; ii < propCount; ++ii) {
+ QMetaProperty p = metaObject->property(ii);
+ if (!p.isScriptable())
+ continue;
+
+ QString propName = QString::fromUtf8(p.name());
+
+ RData *data = new RData;
+ data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName);
+ indexCache[ii] = data;
+
+ data->load(p, engine);
+ data->flags |= propertyFlags;
+
+ data->metaObjectOffset = allowedRevisionCache.count() - 1;
+
+ if (stringCache.contains(propName)) {
+ RData *old = stringCache[propName];
+ data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
+ data->overrideIndex = old->coreIndex;
+ stringCache[propName]->release();
+ identifierCache[data->identifier.identifier]->release();
+ }
+
+ stringCache.insert(propName, data);
+ identifierCache.insert(data->identifier.identifier, data);
+ data->addref();
+ data->addref();
+ }
+}
+
+void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject)
+{
+ if (!metaObject)
+ return;
+
+ updateRecur(engine, metaObject->superClass());
+
+ append(engine, metaObject);
+}
+
+void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaObject *metaObject)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(metaObject);
+
+ clear();
+
+ // Optimization to prevent unnecessary reallocation of lists
+ indexCache.reserve(metaObject->propertyCount());
+ methodIndexCache.reserve(metaObject->methodCount());
+
+ updateRecur(engine,metaObject);
+}
+
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(int index) const
+{
+ if (index < 0 || index >= indexCache.count())
+ return 0;
+
+ return indexCache.at(index);
+}
+
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::method(int index) const
+{
+ if (index < 0 || index >= methodIndexCache.count())
+ return 0;
+
+ return methodIndexCache.at(index);
+}
+
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(const QString &str) const
+{
+ return stringCache.value(str);
+}
+
+QString QDeclarativePropertyCache::Data::name(QObject *object)
+{
+ if (!object)
+ return QString();
+
+ return name(object->metaObject());
+}
+
+QString QDeclarativePropertyCache::Data::name(const QMetaObject *metaObject)
+{
+ if (!metaObject || coreIndex == -1)
+ return QString();
+
+ if (flags & IsFunction) {
+ QMetaMethod m = metaObject->method(coreIndex);
+
+ QString name = QString::fromUtf8(m.signature());
+ int parenIdx = name.indexOf(QLatin1Char('('));
+ if (parenIdx != -1)
+ name = name.left(parenIdx);
+ return name;
+ } else {
+ QMetaProperty p = metaObject->property(coreIndex);
+ return QString::fromUtf8(p.name());
+ }
+}
+
+QStringList QDeclarativePropertyCache::propertyNames() const
+{
+ return stringCache.keys();
+}
+
+QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ const QScriptDeclarativeClass::Identifier &name, Data &local)
+{
+ QDeclarativePropertyCache::Data *rv = 0;
+
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+
+ QDeclarativePropertyCache *cache = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(obj);
+ if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine)
+ cache = ddata->propertyCache;
+ if (!cache) {
+ cache = enginePrivate->cache(obj);
+ if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+ }
+
+ if (cache) {
+ rv = cache->property(name);
+ } else {
+ local = QDeclarativePropertyCache::create(obj->metaObject(), enginePrivate->objectClass->toString(name));
+ if (local.isValid())
+ rv = &local;
+ }
+
+ return rv;
+}
+
+QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ const QString &name, Data &local)
+{
+ QDeclarativePropertyCache::Data *rv = 0;
+
+ if (!engine) {
+ local = QDeclarativePropertyCache::create(obj->metaObject(), name);
+ if (local.isValid())
+ rv = &local;
+ } else {
+ QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+
+ QDeclarativePropertyCache *cache = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(obj);
+ if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine)
+ cache = ddata->propertyCache;
+ if (!cache) {
+ cache = enginePrivate->cache(obj);
+ if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+ }
+
+ if (cache) {
+ rv = cache->property(name);
+ } else {
+ local = QDeclarativePropertyCache::create(obj->metaObject(), name);
+ if (local.isValid())
+ rv = &local;
+ }
+ }
+
+ return rv;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
new file mode 100644
index 0000000000..eeeff1aea1
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEPROPERTYCACHE_P_H
+#define QDECLARATIVEPROPERTYCACHE_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/qdeclarativerefcount_p.h"
+#include "private/qdeclarativecleanup_p.h"
+#include "private/qdeclarativenotifier_p.h"
+
+#include <QtCore/qvector.h>
+
+#include <QtScript/private/qscriptdeclarativeclass_p.h>
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QMetaProperty;
+
+class Q_AUTOTEST_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+{
+public:
+ QDeclarativePropertyCache(QDeclarativeEngine *);
+ QDeclarativePropertyCache(QDeclarativeEngine *, const QMetaObject *);
+ virtual ~QDeclarativePropertyCache();
+
+ struct Data {
+ inline Data();
+ inline bool operator==(const Data &);
+
+ enum Flag {
+ NoFlags = 0x00000000,
+
+ // Can apply to all properties, except IsFunction
+ IsConstant = 0x00000001,
+ IsWritable = 0x00000002,
+ IsResettable = 0x00000004,
+ IsAlias = 0x00000008,
+
+ // These are mutualy exclusive
+ IsFunction = 0x00000010,
+ IsQObjectDerived = 0x00000020,
+ IsEnumType = 0x00000040,
+ IsQList = 0x00000080,
+ IsQmlBinding = 0x00000100,
+ IsQScriptValue = 0x00000200,
+
+ // Apply only to IsFunctions
+ IsVMEFunction = 0x00000400,
+ HasArguments = 0x00000800,
+ IsSignal = 0x00001000,
+ IsVMESignal = 0x00002000
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ bool isValid() const { return coreIndex != -1; }
+
+ Flags flags;
+ int propType;
+ int coreIndex;
+ union {
+ int notifyIndex; // When !IsFunction
+ int relatedIndex; // When IsFunction
+ };
+ uint overrideIndexIsProperty : 1;
+ int overrideIndex : 31;
+ int revision;
+ int metaObjectOffset;
+
+ static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0);
+ void load(const QMetaProperty &, QDeclarativeEngine *engine = 0);
+ void load(const QMetaMethod &);
+ QString name(QObject *);
+ QString name(const QMetaObject *);
+ };
+
+ struct ValueTypeData {
+ inline ValueTypeData();
+ inline bool operator==(const ValueTypeData &);
+ Data::Flags flags; // flags of the access property on the value type proxy object
+ int valueTypeCoreIdx; // The prop index of the access property on the value type proxy object
+ int valueTypePropType; // The QVariant::Type of access property on the value type proxy object
+ };
+
+ void update(QDeclarativeEngine *, const QMetaObject *);
+
+ QDeclarativePropertyCache *copy() const;
+ void append(QDeclarativeEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags,
+ Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags);
+ void append(QDeclarativeEngine *, const QMetaObject *, int revision, Data::Flag propertyFlags = Data::NoFlags,
+ Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags);
+
+ static Data create(const QMetaObject *, const QString &);
+
+ inline Data *property(const QScriptDeclarativeClass::Identifier &id) const;
+ Data *property(const QString &) const;
+ Data *property(int) const;
+ Data *method(int) const;
+ QStringList propertyNames() const;
+
+ inline Data *overrideData(Data *) const;
+ inline bool isAllowedInRevision(Data *) const;
+
+ inline QDeclarativeEngine *qmlEngine() const;
+ static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &);
+ static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &);
+
+protected:
+ virtual void clear();
+
+private:
+ friend class QDeclarativeEnginePrivate;
+
+ struct RData : public Data, public QDeclarativeRefCount {
+ QScriptDeclarativeClass::PersistentIdentifier identifier;
+ };
+
+ typedef QVector<RData *> IndexCache;
+ typedef QHash<QString, RData *> StringCache;
+ typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+ typedef QVector<int> AllowedRevisionCache;
+
+ void updateRecur(QDeclarativeEngine *, const QMetaObject *);
+
+ QDeclarativeEngine *engine;
+ IndexCache indexCache;
+ IndexCache methodIndexCache;
+ StringCache stringCache;
+ IdentifierCache identifierCache;
+ AllowedRevisionCache allowedRevisionCache;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags);
+
+QDeclarativePropertyCache::Data::Data()
+: flags(0), propType(0), coreIndex(-1), notifyIndex(-1), overrideIndexIsProperty(false), overrideIndex(-1),
+ revision(0), metaObjectOffset(-1)
+{
+}
+
+bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache::Data &other)
+{
+ return flags == other.flags &&
+ propType == other.propType &&
+ coreIndex == other.coreIndex &&
+ notifyIndex == other.notifyIndex &&
+ revision == other.revision;
+}
+
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::overrideData(Data *data) const
+{
+ if (data->overrideIndex < 0)
+ return 0;
+
+ if (data->overrideIndexIsProperty)
+ return indexCache.at(data->overrideIndex);
+ else
+ return methodIndexCache.at(data->overrideIndex);
+}
+
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const
+{
+ return identifierCache.value(id);
+}
+
+QDeclarativePropertyCache::ValueTypeData::ValueTypeData()
+: flags(QDeclarativePropertyCache::Data::NoFlags), valueTypeCoreIdx(-1), valueTypePropType(0)
+{
+}
+
+bool QDeclarativePropertyCache::ValueTypeData::operator==(const ValueTypeData &o)
+{
+ return flags == o.flags &&
+ valueTypeCoreIdx == o.valueTypeCoreIdx &&
+ valueTypePropType == o.valueTypePropType;
+}
+
+bool QDeclarativePropertyCache::isAllowedInRevision(Data *data) const
+{
+ return (data->metaObjectOffset == -1 && data->revision == 0) ||
+ (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
+}
+
+QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const
+{
+ return engine;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEPROPERTYCACHE_P_H
diff --git a/src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp
new file mode 100644
index 0000000000..ab33bad06f
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.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 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 "qdeclarativepropertyvalueinterceptor.h"
+
+#include "qdeclarative.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativePropertyValueInterceptor
+ \brief The QDeclarativePropertyValueInterceptor class is inherited by property interceptors such as Behavior.
+ \internal
+
+ This class intercepts property writes, allowing for custom handling. For example, Behavior uses this
+ interception to provide a default animation for all changes to a property's value.
+ */
+
+/*!
+ Constructs a QDeclarativePropertyValueInterceptor.
+*/
+QDeclarativePropertyValueInterceptor::QDeclarativePropertyValueInterceptor()
+{
+}
+
+QDeclarativePropertyValueInterceptor::~QDeclarativePropertyValueInterceptor()
+{
+}
+
+/*!
+ \fn void QDeclarativePropertyValueInterceptor::setTarget(const QDeclarativeProperty &property)
+ Set the target \a property for the value interceptor. This method will
+ be called by the QML engine when assigning a value interceptor.
+*/
+
+/*!
+ \fn void QDeclarativePropertyValueInterceptor::write(const QVariant &value)
+ This method will be called when a new \a value is assigned to the property being intercepted.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativepropertyvalueinterceptor.h b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.h
new file mode 100644
index 0000000000..1bcd25987f
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.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 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 QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H
+#define QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeProperty;
+class Q_DECLARATIVE_EXPORT QDeclarativePropertyValueInterceptor
+{
+public:
+ QDeclarativePropertyValueInterceptor();
+ virtual ~QDeclarativePropertyValueInterceptor();
+ virtual void setTarget(const QDeclarativeProperty &property) = 0;
+ virtual void write(const QVariant &value) = 0;
+};
+Q_DECLARE_INTERFACE(QDeclarativePropertyValueInterceptor, "com.trolltech.qml.QDeclarativePropertyValueInterceptor")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H
diff --git a/src/declarative/qml/qdeclarativepropertyvaluesource.cpp b/src/declarative/qml/qdeclarativepropertyvaluesource.cpp
new file mode 100644
index 0000000000..12c769adfd
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertyvaluesource.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativepropertyvaluesource.h"
+
+#include "qdeclarative.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDeclarativePropertyValueSource
+ \brief The QDeclarativePropertyValueSource class is an interface for property value sources such as animations and bindings.
+
+ See \l{Property Value Sources} for information on writing custom property
+ value sources.
+ */
+
+/*!
+ Constructs a QDeclarativePropertyValueSource.
+*/
+QDeclarativePropertyValueSource::QDeclarativePropertyValueSource()
+{
+}
+
+/*!
+ Destroys the value source.
+*/
+QDeclarativePropertyValueSource::~QDeclarativePropertyValueSource()
+{
+}
+
+/*!
+ \fn void QDeclarativePropertyValueSource::setTarget(const QDeclarativeProperty &property)
+ Set the target \a property for the value source. This method will
+ be called by the QML engine when assigning a value source.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativepropertyvaluesource.h b/src/declarative/qml/qdeclarativepropertyvaluesource.h
new file mode 100644
index 0000000000..493ad81e49
--- /dev/null
+++ b/src/declarative/qml/qdeclarativepropertyvaluesource.h
@@ -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 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 QDECLARATIVEPROPERTYVALUESOURCE_H
+#define QDECLARATIVEPROPERTYVALUESOURCE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeProperty;
+class Q_DECLARATIVE_EXPORT QDeclarativePropertyValueSource
+{
+public:
+ QDeclarativePropertyValueSource();
+ virtual ~QDeclarativePropertyValueSource();
+ virtual void setTarget(const QDeclarativeProperty &) = 0;
+};
+Q_DECLARE_INTERFACE(QDeclarativePropertyValueSource, "com.trolltech.qml.QDeclarativePropertyValueSource")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROPERTYVALUESOURCE_H
diff --git a/src/declarative/qml/qdeclarativeproxymetaobject.cpp b/src/declarative/qml/qdeclarativeproxymetaobject.cpp
new file mode 100644
index 0000000000..5a8dc14820
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproxymetaobject.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeproxymetaobject_p.h"
+#include "private/qdeclarativeproperty_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeProxyMetaObject::QDeclarativeProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
+: metaObjects(mList), proxies(0), parent(0), object(obj)
+{
+ *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject;
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ if (op->metaObject)
+ parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+
+ op->metaObject = this;
+}
+
+QDeclarativeProxyMetaObject::~QDeclarativeProxyMetaObject()
+{
+ if (parent)
+ delete parent;
+ parent = 0;
+
+ if (proxies)
+ delete [] proxies;
+ proxies = 0;
+}
+
+int QDeclarativeProxyMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if ((c == QMetaObject::ReadProperty ||
+ c == QMetaObject::WriteProperty) &&
+ id >= metaObjects->last().propertyOffset) {
+
+ for (int ii = 0; ii < metaObjects->count(); ++ii) {
+ const ProxyData &data = metaObjects->at(ii);
+ if (id >= data.propertyOffset) {
+ if (!proxies) {
+ proxies = new QObject*[metaObjects->count()];
+ ::memset(proxies, 0,
+ sizeof(QObject *) * metaObjects->count());
+ }
+
+ if (!proxies[ii]) {
+ QObject *proxy = data.createFunc(object);
+ const QMetaObject *metaObject = proxy->metaObject();
+ proxies[ii] = proxy;
+
+ int localOffset = data.metaObject->methodOffset();
+ int methodOffset = metaObject->methodOffset();
+ int methods = metaObject->methodCount() - methodOffset;
+
+ // ### - Can this be done more optimally?
+ for (int jj = 0; jj < methods; ++jj) {
+ QMetaMethod method =
+ metaObject->method(jj + methodOffset);
+ if (method.methodType() == QMetaMethod::Signal)
+ QDeclarativePropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
+ }
+ }
+
+ int proxyOffset = proxies[ii]->metaObject()->propertyOffset();
+ int proxyId = id - data.propertyOffset + proxyOffset;
+
+ return proxies[ii]->qt_metacall(c, proxyId, a);
+ }
+ }
+ } else if (c == QMetaObject::InvokeMetaMethod &&
+ id >= metaObjects->last().methodOffset) {
+ QMetaMethod m = object->metaObject()->method(id);
+ if (m.methodType() == QMetaMethod::Signal) {
+ QMetaObject::activate(object, id, a);
+ return -1;
+ }
+ }
+
+ if (parent)
+ return parent->metaCall(c, id, a);
+ else
+ return object->qt_metacall(c, id, a);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeproxymetaobject_p.h b/src/declarative/qml/qdeclarativeproxymetaobject_p.h
new file mode 100644
index 0000000000..4fc987a821
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeproxymetaobject_p.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 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 QDECLARATIVEPROXYMETAOBJECT_P_H
+#define QDECLARATIVEPROXYMETAOBJECT_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/qmetaobjectbuilder_p.h"
+#include "qdeclarative.h"
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QObject>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeProxyMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ struct ProxyData {
+ typedef QObject *(*CreateFunc)(QObject *);
+ QMetaObject *metaObject;
+ CreateFunc createFunc;
+ int propertyOffset;
+ int methodOffset;
+ };
+
+ QDeclarativeProxyMetaObject(QObject *, QList<ProxyData> *);
+ virtual ~QDeclarativeProxyMetaObject();
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+
+private:
+ QList<ProxyData> *metaObjects;
+ QObject **proxies;
+
+ QAbstractDynamicMetaObject *parent;
+ QObject *object;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROXYMETAOBJECT_P_H
+
diff --git a/src/declarative/qml/qdeclarativerefcount.cpp b/src/declarative/qml/qdeclarativerefcount.cpp
new file mode 100644
index 0000000000..276e6279e3
--- /dev/null
+++ b/src/declarative/qml/qdeclarativerefcount.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativerefcount_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeRefCount::QDeclarativeRefCount()
+: refCount(1)
+{
+}
+
+QDeclarativeRefCount::~QDeclarativeRefCount()
+{
+}
+
+void QDeclarativeRefCount::addref()
+{
+ Q_ASSERT(refCount > 0);
+ ++refCount;
+}
+
+void QDeclarativeRefCount::release()
+{
+ Q_ASSERT(refCount > 0);
+ --refCount;
+ if (refCount == 0)
+ delete this;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativerefcount_p.h b/src/declarative/qml/qdeclarativerefcount_p.h
new file mode 100644
index 0000000000..b896e5f33f
--- /dev/null
+++ b/src/declarative/qml/qdeclarativerefcount_p.h
@@ -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 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 QDECLARATIVEREFCOUNT_P_H
+#define QDECLARATIVEREFCOUNT_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_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QDeclarativeRefCount
+{
+public:
+ QDeclarativeRefCount();
+ virtual ~QDeclarativeRefCount();
+ void addref();
+ void release();
+
+private:
+ int refCount;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEREFCOUNT_P_H
diff --git a/src/declarative/qml/qdeclarativerewrite.cpp b/src/declarative/qml/qdeclarativerewrite.cpp
new file mode 100644
index 0000000000..6311e01d43
--- /dev/null
+++ b/src/declarative/qml/qdeclarativerewrite.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativerewrite_p.h"
+
+#include "private/qdeclarativeglobal_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
+
+namespace QDeclarativeRewrite {
+
+bool SharedBindingTester::isSharable(const QString &code)
+{
+ Engine engine;
+ NodePool pool(QString(), &engine);
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement())
+ return false;
+
+ return isSharable(parser.statement());
+}
+
+bool SharedBindingTester::isSharable(AST::Node *node)
+{
+ _sharable = true;
+ AST::Node::acceptChild(node, this);
+ return _sharable;
+}
+
+QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable)
+{
+ Engine engine;
+ NodePool pool(QString(), &engine);
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement()) {
+ if (ok) *ok = false;
+ return QString();
+ } else {
+ if (ok) *ok = true;
+ if (sharable) {
+ SharedBindingTester tester;
+ *sharable = tester.isSharable(parser.statement());
+ }
+ }
+ return rewrite(code, 0, parser.statement());
+}
+
+QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable)
+{
+ if (!node)
+ return code;
+
+ if (sharable) {
+ SharedBindingTester tester;
+ *sharable = tester.isSharable(node);
+ }
+
+ QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast();
+ QDeclarativeJS::AST::Statement *statement = node->statementCast();
+ if(!expression && !statement)
+ return code;
+
+ TextWriter w;
+ _writer = &w;
+ _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
+ _inLoop = 0;
+
+ accept(node);
+
+ unsigned startOfStatement = 0;
+ unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position;
+
+ QString startString = QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { ");
+ if (expression)
+ startString += QLatin1String("return ");
+ _writer->replace(startOfStatement, 0, startString);
+ _writer->replace(endOfStatement, 0, QLatin1String(" })"));
+
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ QString codeCopy = code;
+ w.write(&codeCopy);
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(code);
+ qWarning() << "=============================================================";
+ }
+
+ return codeCopy;
+}
+
+void RewriteBinding::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+QString RewriteBinding::rewrite(QString code, unsigned position,
+ AST::Statement *node)
+{
+ TextWriter w;
+ _writer = &w;
+ _position = position;
+ _inLoop = 0;
+
+ accept(node);
+
+ unsigned startOfStatement = node->firstSourceLocation().begin() - _position;
+ unsigned endOfStatement = node->lastSourceLocation().end() - _position;
+
+ _writer->replace(startOfStatement, 0, QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { "));
+ _writer->replace(endOfStatement, 0, QLatin1String(" })"));
+
+ if (rewriteDump()) {
+ qWarning() << "=============================================================";
+ qWarning() << "Rewrote:";
+ qWarning() << qPrintable(code);
+ }
+
+ w.write(&code);
+
+ if (rewriteDump()) {
+ qWarning() << "To:";
+ qWarning() << qPrintable(code);
+ qWarning() << "=============================================================";
+ }
+
+ return code;
+}
+
+bool RewriteBinding::visit(AST::Block *ast)
+{
+ for (AST::StatementList *it = ast->statements; it; it = it->next) {
+ if (! it->next) {
+ // we need to rewrite only the last statement of a block.
+ accept(it->statement);
+ }
+ }
+
+ return false;
+}
+
+bool RewriteBinding::visit(AST::ExpressionStatement *ast)
+{
+ if (! _inLoop) {
+ unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
+ _writer->replace(startOfExpressionStatement, 0, QLatin1String("return "));
+ }
+
+ return false;
+}
+
+bool RewriteBinding::visit(AST::DoWhileStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::DoWhileStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::WhileStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::WhileStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::ForStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::ForStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::LocalForStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::LocalForStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::ForEachStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::ForEachStatement *)
+{
+ --_inLoop;
+}
+
+bool RewriteBinding::visit(AST::LocalForEachStatement *)
+{
+ ++_inLoop;
+ return true;
+}
+
+void RewriteBinding::endVisit(AST::LocalForEachStatement *)
+{
+ --_inLoop;
+}
+
+} // namespace QDeclarativeRewrite
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativerewrite_p.h b/src/declarative/qml/qdeclarativerewrite_p.h
new file mode 100644
index 0000000000..7c20a39044
--- /dev/null
+++ b/src/declarative/qml/qdeclarativerewrite_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEREWRITE_P_H
+#define QDECLARATIVEREWRITE_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 "rewriter/textwriter_p.h"
+#include "parser/qdeclarativejslexer_p.h"
+#include "parser/qdeclarativejsparser_p.h"
+#include "parser/qdeclarativejsnodepool_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeRewrite {
+using namespace QDeclarativeJS;
+
+class SharedBindingTester : protected AST::Visitor
+{
+ bool _sharable;
+public:
+ bool isSharable(const QString &code);
+ bool isSharable(AST::Node *Node);
+
+ virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; }
+ virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; }
+ virtual bool visit(AST::CallExpression *) { _sharable = false; return false; }
+};
+
+class RewriteBinding: protected AST::Visitor
+{
+ unsigned _position;
+ TextWriter *_writer;
+ QByteArray _name;
+
+public:
+ QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0);
+ QString operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable = 0);
+
+ //name of the function: used for the debugger
+ void setName(const QByteArray &name) { _name = name; }
+
+protected:
+ using AST::Visitor::visit;
+
+ void accept(AST::Node *node);
+ QString rewrite(QString code, unsigned position, AST::Statement *node);
+
+ virtual bool visit(AST::Block *ast);
+ virtual bool visit(AST::ExpressionStatement *ast);
+
+ virtual bool visit(AST::DoWhileStatement *ast);
+ virtual void endVisit(AST::DoWhileStatement *ast);
+
+ virtual bool visit(AST::WhileStatement *ast);
+ virtual void endVisit(AST::WhileStatement *ast);
+
+ virtual bool visit(AST::ForStatement *ast);
+ virtual void endVisit(AST::ForStatement *ast);
+
+ virtual bool visit(AST::LocalForStatement *ast);
+ virtual void endVisit(AST::LocalForStatement *ast);
+
+ virtual bool visit(AST::ForEachStatement *ast);
+ virtual void endVisit(AST::ForEachStatement *ast);
+
+ virtual bool visit(AST::LocalForEachStatement *ast);
+ virtual void endVisit(AST::LocalForEachStatement *ast);
+
+private:
+ int _inLoop;
+};
+
+} // namespace QDeclarativeRewrite
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEREWRITE_P_H
+
diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp
new file mode 100644
index 0000000000..e04cfc52af
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescriptparser.cpp
@@ -0,0 +1,1206 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativescriptparser_p.h"
+
+#include "private/qdeclarativeparser_p.h"
+#include "parser/qdeclarativejsengine_p.h"
+#include "parser/qdeclarativejsparser_p.h"
+#include "parser/qdeclarativejslexer_p.h"
+#include "parser/qdeclarativejsnodepool_p.h"
+#include "parser/qdeclarativejsastvisitor_p.h"
+#include "parser/qdeclarativejsast_p.h"
+#include "private/qdeclarativerewrite_p.h"
+
+#include <QStack>
+#include <QCoreApplication>
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+using namespace QDeclarativeParser;
+
+namespace {
+
+class ProcessAST: protected AST::Visitor
+{
+ struct State {
+ State() : object(0), property(0) {}
+ State(QDeclarativeParser::Object *o) : object(o), property(0) {}
+ State(QDeclarativeParser::Object *o, Property *p) : object(o), property(p) {}
+
+ QDeclarativeParser::Object *object;
+ Property *property;
+ };
+
+ struct StateStack : public QStack<State>
+ {
+ void pushObject(QDeclarativeParser::Object *obj)
+ {
+ push(State(obj));
+ }
+
+ void pushProperty(const QString &name, const LocationSpan &location)
+ {
+ const State &state = top();
+ if (state.property) {
+ State s(state.property->getValue(location),
+ state.property->getValue(location)->getProperty(name.toUtf8()));
+ s.property->location = location;
+ push(s);
+ } else {
+ State s(state.object,
+ state.object->getProperty(name.toUtf8()));
+
+ s.property->location = location;
+ push(s);
+ }
+ }
+ };
+
+public:
+ ProcessAST(QDeclarativeScriptParser *parser);
+ virtual ~ProcessAST();
+
+ void operator()(const QString &code, AST::Node *node);
+
+protected:
+
+ QDeclarativeParser::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment,
+ const QString &objectType,
+ AST::SourceLocation typeLocation,
+ LocationSpan location,
+ AST::UiObjectInitializer *initializer = 0);
+
+ QDeclarativeParser::Variant getVariant(AST::ExpressionNode *expr);
+
+ LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
+ LocationSpan location(AST::UiQualifiedId *);
+
+ using AST::Visitor::visit;
+ using AST::Visitor::endVisit;
+
+ virtual bool visit(AST::UiProgram *node);
+ virtual bool visit(AST::UiImport *node);
+ virtual bool visit(AST::UiObjectDefinition *node);
+ virtual bool visit(AST::UiPublicMember *node);
+ virtual bool visit(AST::UiObjectBinding *node);
+
+ virtual bool visit(AST::UiScriptBinding *node);
+ virtual bool visit(AST::UiArrayBinding *node);
+ virtual bool visit(AST::UiSourceElement *node);
+
+ void accept(AST::Node *node);
+
+ QString asString(AST::UiQualifiedId *node) const;
+
+ const State state() const;
+ QDeclarativeParser::Object *currentObject() const;
+ Property *currentProperty() const;
+
+ QString qualifiedNameId() const;
+
+ QString textAt(const AST::SourceLocation &loc) const
+ { return _contents.mid(loc.offset, loc.length); }
+
+
+ QString textAt(const AST::SourceLocation &first,
+ const AST::SourceLocation &last) const
+ { return _contents.mid(first.offset, last.offset + last.length - first.offset); }
+
+ QString asString(AST::ExpressionNode *expr)
+ {
+ if (! expr)
+ return QString();
+
+ return textAt(expr->firstSourceLocation(), expr->lastSourceLocation());
+ }
+
+ QString asString(AST::Statement *stmt)
+ {
+ if (! stmt)
+ return QString();
+
+ QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
+ s += QLatin1Char('\n');
+ return s;
+ }
+
+private:
+ QDeclarativeScriptParser *_parser;
+ StateStack _stateStack;
+ QStringList _scope;
+ QString _contents;
+};
+
+ProcessAST::ProcessAST(QDeclarativeScriptParser *parser)
+ : _parser(parser)
+{
+}
+
+ProcessAST::~ProcessAST()
+{
+}
+
+void ProcessAST::operator()(const QString &code, AST::Node *node)
+{
+ _contents = code;
+ accept(node);
+}
+
+void ProcessAST::accept(AST::Node *node)
+{
+ AST::Node::acceptChild(node, this);
+}
+
+const ProcessAST::State ProcessAST::state() const
+{
+ if (_stateStack.isEmpty())
+ return State();
+
+ return _stateStack.back();
+}
+
+QDeclarativeParser::Object *ProcessAST::currentObject() const
+{
+ return state().object;
+}
+
+Property *ProcessAST::currentProperty() const
+{
+ return state().property;
+}
+
+QString ProcessAST::qualifiedNameId() const
+{
+ return _scope.join(QLatin1String("/"));
+}
+
+QString ProcessAST::asString(AST::UiQualifiedId *node) const
+{
+ QString s;
+
+ for (AST::UiQualifiedId *it = node; it; it = it->next) {
+ s.append(it->name->asString());
+
+ if (it->next)
+ s.append(QLatin1Char('.'));
+ }
+
+ return s;
+}
+
+QDeclarativeParser::Object *
+ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
+ bool onAssignment,
+ const QString &objectType,
+ AST::SourceLocation typeLocation,
+ LocationSpan location,
+ AST::UiObjectInitializer *initializer)
+{
+ int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.'));
+ bool isType = !objectType.isEmpty() &&
+ (objectType.at(0).isUpper() ||
+ (lastTypeDot >= 0 && objectType.at(lastTypeDot+1).isUpper()));
+
+ int propertyCount = 0;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name->asString(),
+ this->location(name));
+ }
+
+ if (!onAssignment && propertyCount && currentProperty() && currentProperty()->values.count()) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ if (!isType) {
+
+ if(propertyCount || !currentObject()) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected type name"));
+ error.setLine(typeLocation.startLine);
+ error.setColumn(typeLocation.startColumn);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ LocationSpan loc = ProcessAST::location(typeLocation, typeLocation);
+ if (propertyName)
+ loc = ProcessAST::location(propertyName);
+
+ _stateStack.pushProperty(objectType, loc);
+ accept(initializer);
+ _stateStack.pop();
+
+ return 0;
+
+ } else {
+ // Class
+
+ QString resolvableObjectType = objectType;
+ if (lastTypeDot >= 0)
+ resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/'));
+
+ QDeclarativeParser::Object *obj = new QDeclarativeParser::Object;
+
+ QDeclarativeScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType);
+ obj->type = typeRef->id;
+
+ typeRef->refObjects.append(obj);
+
+ // XXX this doesn't do anything (_scope never builds up)
+ _scope.append(resolvableObjectType);
+ obj->typeName = qualifiedNameId().toUtf8();
+ _scope.removeLast();
+
+ obj->location = location;
+
+ if (propertyCount) {
+ Property *prop = currentProperty();
+ QDeclarativeParser::Value *v = new QDeclarativeParser::Value;
+ v->object = obj;
+ v->location = obj->location;
+ if (onAssignment)
+ prop->addOnValue(v);
+ else
+ prop->addValue(v);
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ } else {
+
+ if (! _parser->tree()) {
+ _parser->setTree(obj);
+ } else {
+ const State state = _stateStack.top();
+ QDeclarativeParser::Value *v = new QDeclarativeParser::Value;
+ v->object = obj;
+ v->location = obj->location;
+ if (state.property) {
+ state.property->addValue(v);
+ } else {
+ Property *defaultProp = state.object->getDefaultProperty();
+ if (defaultProp->location.start.line == -1) {
+ defaultProp->location = v->location;
+ defaultProp->location.end = defaultProp->location.start;
+ defaultProp->location.range.length = 0;
+ }
+ defaultProp->addValue(v);
+ }
+ }
+ }
+
+ _stateStack.pushObject(obj);
+ accept(initializer);
+ _stateStack.pop();
+
+ return obj;
+ }
+}
+
+LocationSpan ProcessAST::location(AST::UiQualifiedId *id)
+{
+ return location(id->identifierToken, id->identifierToken);
+}
+
+LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end)
+{
+ LocationSpan rv;
+ rv.start.line = start.startLine;
+ rv.start.column = start.startColumn;
+ rv.end.line = end.startLine;
+ rv.end.column = end.startColumn + end.length - 1;
+ rv.range.offset = start.offset;
+ rv.range.length = end.offset + end.length - start.offset;
+ return rv;
+}
+
+// UiProgram: UiImportListOpt UiObjectMemberList ;
+bool ProcessAST::visit(AST::UiProgram *node)
+{
+ accept(node->imports);
+ accept(node->members->member);
+ return false;
+}
+
+// UiImport: T_IMPORT T_STRING_LITERAL ;
+bool ProcessAST::visit(AST::UiImport *node)
+{
+ QString uri;
+ QDeclarativeScriptParser::Import import;
+
+ if (node->fileName) {
+ uri = node->fileName->asString();
+
+ if (uri.endsWith(QLatin1String(".js"))) {
+ import.type = QDeclarativeScriptParser::Import::Script;
+ } else {
+ import.type = QDeclarativeScriptParser::Import::File;
+ }
+ } else {
+ import.type = QDeclarativeScriptParser::Import::Library;
+ uri = asString(node->importUri);
+ }
+
+ AST::SourceLocation startLoc = node->importToken;
+ AST::SourceLocation endLoc = node->semicolonToken;
+
+ // Qualifier
+ if (node->importId) {
+ import.qualifier = node->importId->asString();
+ if (!import.qualifier.at(0).isUpper()) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid import qualifier ID"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ if (import.qualifier == QLatin1String("Qt")) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Reserved name \"Qt\" cannot be used as an qualifier"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ // Check for script qualifier clashes
+ bool isScript = import.type == QDeclarativeScriptParser::Import::Script;
+ for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
+ const QDeclarativeScriptParser::Import &other = _parser->_imports.at(ii);
+ bool otherIsScript = other.type == QDeclarativeScriptParser::Import::Script;
+
+ if ((isScript || otherIsScript) && import.qualifier == other.qualifier) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import qualifiers must be unique."));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ }
+
+ } else if (import.type == QDeclarativeScriptParser::Import::Script) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import requires a qualifier"));
+ error.setLine(node->fileNameToken.startLine);
+ error.setColumn(node->fileNameToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ if (node->versionToken.isValid()) {
+ import.version = textAt(node->versionToken);
+ } else if (import.type == QDeclarativeScriptParser::Import::Library) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Library import requires a version"));
+ error.setLine(node->importIdToken.startLine);
+ error.setColumn(node->importIdToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+
+ import.location = location(startLoc, endLoc);
+ import.uri = uri;
+
+ _parser->_imports << import;
+
+ return false;
+}
+
+bool ProcessAST::visit(AST::UiPublicMember *node)
+{
+ const struct TypeNameToType {
+ const char *name;
+ Object::DynamicProperty::Type type;
+ const char *qtName;
+ } propTypeNameToTypes[] = {
+ { "int", Object::DynamicProperty::Int, "int" },
+ { "bool", Object::DynamicProperty::Bool, "bool" },
+ { "double", Object::DynamicProperty::Real, "double" },
+ { "real", Object::DynamicProperty::Real, "qreal" },
+ { "string", Object::DynamicProperty::String, "QString" },
+ { "url", Object::DynamicProperty::Url, "QUrl" },
+ { "color", Object::DynamicProperty::Color, "QColor" },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", Object::DynamicProperty::Time, "QTime" },
+ // { "date", Object::DynamicProperty::Date, "QDate" },
+ { "date", Object::DynamicProperty::DateTime, "QDateTime" },
+ { "variant", Object::DynamicProperty::Variant, "QVariant" }
+ };
+ const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ if(node->type == AST::UiPublicMember::Signal) {
+ const QString name = node->name->asString();
+
+ Object::DynamicSignal signal;
+ signal.name = name.toUtf8();
+
+ AST::UiParameterList *p = node->parameters;
+ while (p) {
+ const QString memberType = p->type->asString();
+ const char *qtType = 0;
+ for(int ii = 0; !qtType && ii < propTypeNameToTypesCount; ++ii) {
+ if(QLatin1String(propTypeNameToTypes[ii].name) == memberType)
+ qtType = propTypeNameToTypes[ii].qtName;
+ }
+
+ if (!qtType) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected parameter type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ signal.parameterTypes << qtType;
+ signal.parameterNames << p->name->asString().toUtf8();
+ p = p->finish();
+ }
+
+ _stateStack.top().object->dynamicSignals << signal;
+ } else {
+ const QString memberType = node->memberType->asString();
+ const QString name = node->name->asString();
+
+ bool typeFound = false;
+ Object::DynamicProperty::Type type;
+
+ if (memberType == QLatin1String("alias")) {
+ type = Object::DynamicProperty::Alias;
+ typeFound = true;
+ }
+
+ for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
+ if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) {
+ type = propTypeNameToTypes[ii].type;
+ typeFound = true;
+ }
+ }
+
+ if (!typeFound && memberType.at(0).isUpper()) {
+ QString typemodifier;
+ if(node->typeModifier)
+ typemodifier = node->typeModifier->asString();
+ if (typemodifier.isEmpty()) {
+ type = Object::DynamicProperty::Custom;
+ } else if(typemodifier == QLatin1String("list")) {
+ type = Object::DynamicProperty::CustomList;
+ } else {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ typeFound = true;
+ } else if (node->typeModifier) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Unexpected property type modifier"));
+ error.setLine(node->typeModifierToken.startLine);
+ error.setColumn(node->typeModifierToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ if(!typeFound) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected property type"));
+ error.setLine(node->typeToken.startLine);
+ error.setColumn(node->typeToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ if (node->isReadonlyMember) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Readonly not yet supported"));
+ error.setLine(node->readonlyToken.startLine);
+ error.setColumn(node->readonlyToken.startColumn);
+ _parser->_errors << error;
+ return false;
+
+ }
+ Object::DynamicProperty property;
+ property.isDefaultProperty = node->isDefaultMember;
+ property.type = type;
+ if (type >= Object::DynamicProperty::Custom) {
+ QDeclarativeScriptParser::TypeReference *typeRef =
+ _parser->findOrCreateType(memberType);
+ typeRef->refObjects.append(_stateStack.top().object);
+ }
+ property.customType = memberType.toUtf8();
+ property.name = name.toUtf8();
+ property.location = location(node->firstSourceLocation(),
+ node->lastSourceLocation());
+
+ if (node->expression) { // default value
+ property.defaultValue = new Property;
+ property.defaultValue->parent = _stateStack.top().object;
+ property.defaultValue->location =
+ location(node->expression->firstSourceLocation(),
+ node->expression->lastSourceLocation());
+ QDeclarativeParser::Value *value = new QDeclarativeParser::Value;
+ value->location = location(node->expression->firstSourceLocation(),
+ node->expression->lastSourceLocation());
+ value->value = getVariant(node->expression);
+ property.defaultValue->values << value;
+ }
+
+ _stateStack.top().object->dynamicProperties << property;
+
+ // process QML-like initializers (e.g. property Object o: Object {})
+ accept(node->binding);
+ }
+
+ return false;
+}
+
+
+// UiObjectMember: UiQualifiedId UiObjectInitializer ;
+bool ProcessAST::visit(AST::UiObjectDefinition *node)
+{
+ LocationSpan l = location(node->firstSourceLocation(),
+ node->lastSourceLocation());
+
+ const QString objectType = asString(node->qualifiedTypeNameId);
+ const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
+
+ defineObjectBinding(/*propertyName = */ 0, false, objectType,
+ typeLocation, l, node->initializer);
+
+ return false;
+}
+
+
+// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+bool ProcessAST::visit(AST::UiObjectBinding *node)
+{
+ LocationSpan l = location(node->qualifiedTypeNameId->identifierToken,
+ node->initializer->rbraceToken);
+
+ const QString objectType = asString(node->qualifiedTypeNameId);
+ const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
+
+ defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType,
+ typeLocation, l, node->initializer);
+
+ return false;
+}
+
+QDeclarativeParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr)
+{
+ if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
+ return QDeclarativeParser::Variant(lit->value->asString());
+ } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
+ return QDeclarativeParser::Variant(true);
+ } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
+ return QDeclarativeParser::Variant(false);
+ } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
+ return QDeclarativeParser::Variant(lit->value, asString(expr));
+ } else {
+
+ if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
+ if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
+ return QDeclarativeParser::Variant(-lit->value, asString(expr));
+ }
+ }
+
+ return QDeclarativeParser::Variant(asString(expr), expr);
+ }
+}
+
+
+// UiObjectMember: UiQualifiedId T_COLON Statement ;
+bool ProcessAST::visit(AST::UiScriptBinding *node)
+{
+ int propertyCount = 0;
+ AST::UiQualifiedId *propertyName = node->qualifiedId;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name->asString(),
+ location(name));
+ }
+
+ Property *prop = currentProperty();
+
+ if (prop->values.count()) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ QDeclarativeParser::Variant primitive;
+
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) {
+ primitive = getVariant(stmt->expression);
+ } else { // do binding
+ primitive = QDeclarativeParser::Variant(asString(node->statement),
+ node->statement);
+ }
+
+ prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset;
+ prop->location.range.offset = node->qualifiedId->identifierToken.offset;
+ QDeclarativeParser::Value *v = new QDeclarativeParser::Value;
+ v->value = primitive;
+ v->location = location(node->statement->firstSourceLocation(),
+ node->statement->lastSourceLocation());
+
+ prop->addValue(v);
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ return true;
+}
+
+static QList<int> collectCommas(AST::UiArrayMemberList *members)
+{
+ QList<int> commas;
+
+ if (members) {
+ for (AST::UiArrayMemberList *it = members->next; it; it = it->next) {
+ commas.append(it->commaToken.offset);
+ }
+ }
+
+ return commas;
+}
+
+// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+bool ProcessAST::visit(AST::UiArrayBinding *node)
+{
+ int propertyCount = 0;
+ AST::UiQualifiedId *propertyName = node->qualifiedId;
+ for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
+ ++propertyCount;
+ _stateStack.pushProperty(name->name->asString(),
+ location(name));
+ }
+
+ Property* prop = currentProperty();
+
+ if (prop->values.count()) {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
+ error.setLine(this->location(propertyName).start.line);
+ error.setColumn(this->location(propertyName).start.column);
+ _parser->_errors << error;
+ return 0;
+ }
+
+ accept(node->members);
+
+ // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range:
+ prop->listValueRange.offset = node->lbracketToken.offset;
+ prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset;
+
+ // Store the positions of the comma token too, again for the DOM to be able to retrieve it.
+ prop->listCommaPositions = collectCommas(node->members);
+
+ while (propertyCount--)
+ _stateStack.pop();
+
+ return false;
+}
+
+bool ProcessAST::visit(AST::UiSourceElement *node)
+{
+ QDeclarativeParser::Object *obj = currentObject();
+
+ if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
+
+ Object::DynamicSlot slot;
+ slot.location = location(funDecl->firstSourceLocation(), funDecl->lastSourceLocation());
+
+ AST::FormalParameterList *f = funDecl->formals;
+ while (f) {
+ slot.parameterNames << f->name->asString().toUtf8();
+ f = f->finish();
+ }
+
+ AST::SourceLocation loc = funDecl->rparenToken;
+ loc.offset = loc.end();
+ loc.startColumn += 1;
+ QString body = textAt(loc, funDecl->rbraceToken);
+ slot.name = funDecl->name->asString().toUtf8();
+ slot.body = body;
+ obj->dynamicSlots << slot;
+
+ } else {
+ QDeclarativeError error;
+ error.setDescription(QCoreApplication::translate("QDeclarativeParser","JavaScript declaration outside Script element"));
+ error.setLine(node->firstSourceLocation().startLine);
+ error.setColumn(node->firstSourceLocation().startColumn);
+ _parser->_errors << error;
+ }
+ return false;
+}
+
+} // end of anonymous namespace
+
+
+QDeclarativeScriptParser::QDeclarativeScriptParser()
+: root(0), data(0)
+{
+
+}
+
+QDeclarativeScriptParser::~QDeclarativeScriptParser()
+{
+ clear();
+}
+
+class QDeclarativeScriptParserJsASTData
+{
+public:
+ QDeclarativeScriptParserJsASTData(const QString &filename)
+ : nodePool(filename, &engine) {}
+
+ Engine engine;
+ NodePool nodePool;
+};
+
+bool QDeclarativeScriptParser::parse(const QByteArray &qmldata, const QUrl &url)
+{
+ clear();
+
+ const QString fileName = url.toString();
+ _scriptFile = fileName;
+
+ QTextStream stream(qmldata, QIODevice::ReadOnly);
+#ifndef QT_NO_TEXTCODEC
+ stream.setCodec("UTF-8");
+#endif
+ const QString code = stream.readAll();
+
+ data = new QDeclarativeScriptParserJsASTData(fileName);
+
+ Lexer lexer(&data->engine);
+ lexer.setCode(code, /*line = */ 1);
+
+ Parser parser(&data->engine);
+
+ if (! parser.parse() || !_errors.isEmpty()) {
+
+ // Extract errors from the parser
+ foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
+
+ if (m.isWarning())
+ continue;
+
+ QDeclarativeError error;
+ error.setUrl(url);
+ error.setDescription(m.message);
+ error.setLine(m.loc.startLine);
+ error.setColumn(m.loc.startColumn);
+ _errors << error;
+
+ }
+ }
+
+ if (_errors.isEmpty()) {
+ ProcessAST process(this);
+ process(code, parser.ast());
+
+ // Set the url for process errors
+ for(int ii = 0; ii < _errors.count(); ++ii)
+ _errors[ii].setUrl(url);
+ }
+
+ return _errors.isEmpty();
+}
+
+QList<QDeclarativeScriptParser::TypeReference*> QDeclarativeScriptParser::referencedTypes() const
+{
+ return _refTypes;
+}
+
+QDeclarativeParser::Object *QDeclarativeScriptParser::tree() const
+{
+ return root;
+}
+
+QList<QDeclarativeScriptParser::Import> QDeclarativeScriptParser::imports() const
+{
+ return _imports;
+}
+
+QList<QDeclarativeError> QDeclarativeScriptParser::errors() const
+{
+ return _errors;
+}
+
+static void replaceWithSpace(QString &str, int idx, int n)
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+/*
+Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
+are:
+ library
+*/
+QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptParser::extractPragmas(QString &script)
+{
+ QDeclarativeParser::Object::ScriptBlock::Pragmas rv = QDeclarativeParser::Object::ScriptBlock::None;
+
+ const QString pragma(QLatin1String("pragma"));
+ const QString library(QLatin1String("library"));
+
+ QDeclarativeJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QDeclarativeJSGrammar::T_DOT)
+ return rv;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.currentLineNo();
+
+ token = l.lex();
+
+ if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
+ l.currentLineNo() != startLine ||
+ script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return rv;
+
+ token = l.lex();
+
+ if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
+ l.currentLineNo() != startLine)
+ return rv;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.currentLineNo() == startLine)
+ return rv;
+
+ if (pragmaValue == library) {
+ rv |= QDeclarativeParser::Object::ScriptBlock::Shared;
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return rv;
+ }
+ }
+ return rv;
+}
+
+#define CHECK_LINE if(l.currentLineNo() != startLine) return rv;
+#define CHECK_TOKEN(t) if (token != QDeclarativeJSGrammar:: t) return rv;
+
+static const int uriTokens[] = {
+ QDeclarativeJSGrammar::T_IDENTIFIER,
+ QDeclarativeJSGrammar::T_PROPERTY,
+ QDeclarativeJSGrammar::T_SIGNAL,
+ QDeclarativeJSGrammar::T_READONLY,
+ QDeclarativeJSGrammar::T_ON,
+ QDeclarativeJSGrammar::T_BREAK,
+ QDeclarativeJSGrammar::T_CASE,
+ QDeclarativeJSGrammar::T_CATCH,
+ QDeclarativeJSGrammar::T_CONTINUE,
+ QDeclarativeJSGrammar::T_DEFAULT,
+ QDeclarativeJSGrammar::T_DELETE,
+ QDeclarativeJSGrammar::T_DO,
+ QDeclarativeJSGrammar::T_ELSE,
+ QDeclarativeJSGrammar::T_FALSE,
+ QDeclarativeJSGrammar::T_FINALLY,
+ QDeclarativeJSGrammar::T_FOR,
+ QDeclarativeJSGrammar::T_FUNCTION,
+ QDeclarativeJSGrammar::T_IF,
+ QDeclarativeJSGrammar::T_IN,
+ QDeclarativeJSGrammar::T_INSTANCEOF,
+ QDeclarativeJSGrammar::T_NEW,
+ QDeclarativeJSGrammar::T_NULL,
+ QDeclarativeJSGrammar::T_RETURN,
+ QDeclarativeJSGrammar::T_SWITCH,
+ QDeclarativeJSGrammar::T_THIS,
+ QDeclarativeJSGrammar::T_THROW,
+ QDeclarativeJSGrammar::T_TRUE,
+ QDeclarativeJSGrammar::T_TRY,
+ QDeclarativeJSGrammar::T_TYPEOF,
+ QDeclarativeJSGrammar::T_VAR,
+ QDeclarativeJSGrammar::T_VOID,
+ QDeclarativeJSGrammar::T_WHILE,
+ QDeclarativeJSGrammar::T_CONST,
+ QDeclarativeJSGrammar::T_DEBUGGER,
+ QDeclarativeJSGrammar::T_RESERVED_WORD,
+ QDeclarativeJSGrammar::T_WITH,
+
+ QDeclarativeJSGrammar::EOF_SYMBOL
+};
+static inline bool isUriToken(int token)
+{
+ const int *current = uriTokens;
+ while (*current != QDeclarativeJSGrammar::EOF_SYMBOL) {
+ if (*current == token)
+ return true;
+ ++current;
+ }
+ return false;
+}
+
+QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMetaData(QString &script)
+{
+ JavaScriptMetaData rv;
+
+ QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
+
+ const QString pragma(QLatin1String("pragma"));
+ const QString js(QLatin1String(".js"));
+ const QString library(QLatin1String("library"));
+
+ QDeclarativeJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QDeclarativeJSGrammar::T_DOT)
+ return rv;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.currentLineNo();
+
+ token = l.lex();
+
+ CHECK_LINE;
+
+ if (token == QDeclarativeJSGrammar::T_IMPORT) {
+
+ // .import <URI> <Version> as <Identifier>
+ // .import <file.js> as <Identifier>
+
+ token = l.lex();
+
+ CHECK_LINE;
+
+ if (token == QDeclarativeJSGrammar::T_STRING_LITERAL) {
+
+ QString file(l.characterBuffer(), l.characterCount());
+ if (!file.endsWith(js))
+ return rv;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_AS);
+ CHECK_LINE;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ if (!importId.at(0).isUpper())
+ return rv;
+
+ token = l.lex();
+ if (l.currentLineNo() == startLine)
+ return rv;
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ Import import;
+ import.type = Import::Script;
+ import.uri = file;
+ import.qualifier = importId;
+
+ rv.imports << import;
+
+ } else {
+ // URI
+ QString uri;
+ QString version;
+
+ while (true) {
+ if (!isUriToken(token))
+ return rv;
+
+ uri.append(QString(l.characterBuffer(), l.characterCount()));
+
+ token = l.lex();
+ CHECK_LINE;
+ if (token != QDeclarativeJSGrammar::T_DOT)
+ break;
+
+ uri.append(QLatin1Char('.'));
+
+ token = l.lex();
+ CHECK_LINE;
+ }
+
+ CHECK_TOKEN(T_NUMERIC_LITERAL);
+ version = script.mid(l.tokenOffset(), l.tokenLength());
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_AS);
+ CHECK_LINE;
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ QString importId = script.mid(l.tokenOffset(), l.tokenLength());
+
+ if (!importId.at(0).isUpper())
+ return rv;
+
+ token = l.lex();
+ if (l.currentLineNo() == startLine)
+ return rv;
+
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+
+ Import import;
+ import.type = Import::Library;
+ import.uri = uri;
+ import.version = version;
+ import.qualifier = importId;
+
+ rv.imports << import;
+ }
+
+ } else if (token == QDeclarativeJSGrammar::T_IDENTIFIER &&
+ script.mid(l.tokenOffset(), l.tokenLength()) == pragma) {
+
+ token = l.lex();
+
+ CHECK_TOKEN(T_IDENTIFIER);
+ CHECK_LINE;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ if (pragmaValue == QLatin1String("library")) {
+ pragmas |= QDeclarativeParser::Object::ScriptBlock::Shared;
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ } else {
+ return rv;
+ }
+
+ token = l.lex();
+ if (l.currentLineNo() == startLine)
+ return rv;
+
+ } else {
+ return rv;
+ }
+ }
+ return rv;
+}
+
+void QDeclarativeScriptParser::clear()
+{
+ if (root) {
+ root->release();
+ root = 0;
+ }
+ _imports.clear();
+ qDeleteAll(_refTypes);
+ _refTypes.clear();
+ _errors.clear();
+
+ if (data) {
+ delete data;
+ data = 0;
+ }
+}
+
+QDeclarativeScriptParser::TypeReference *QDeclarativeScriptParser::findOrCreateType(const QString &name)
+{
+ TypeReference *type = 0;
+ int i = 0;
+ for (; i < _refTypes.size(); ++i) {
+ if (_refTypes.at(i)->name == name) {
+ type = _refTypes.at(i);
+ break;
+ }
+ }
+ if (!type) {
+ type = new TypeReference(i, name);
+ _refTypes.append(type);
+ }
+
+ return type;
+}
+
+void QDeclarativeScriptParser::setTree(QDeclarativeParser::Object *tree)
+{
+ Q_ASSERT(! root);
+
+ root = tree;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h
new file mode 100644
index 0000000000..e5e0d7075d
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescriptparser_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESCRIPTPARSER_P_H
+#define QDECLARATIVESCRIPTPARSER_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 "private/qdeclarativeparser_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QUrl>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QByteArray;
+
+class QDeclarativeScriptParserJsASTData;
+class QDeclarativeScriptParser
+{
+public:
+ class Import
+ {
+ public:
+ Import() : type(Library) {}
+
+ enum Type { Library, File, Script };
+ Type type;
+
+ QString uri;
+ QString qualifier;
+ QString version;
+
+ QDeclarativeParser::LocationSpan location;
+ };
+
+ class TypeReference
+ {
+ public:
+ TypeReference(int typeId, const QString &typeName) : id(typeId), name(typeName) {}
+
+ int id;
+ // type as it has been referenced in Qml
+ QString name;
+ // objects in parse tree referencing the type
+ QList<QDeclarativeParser::Object*> refObjects;
+ };
+
+ QDeclarativeScriptParser();
+ ~QDeclarativeScriptParser();
+
+ bool parse(const QByteArray &data, const QUrl &url = QUrl());
+
+ QList<TypeReference*> referencedTypes() const;
+
+ QDeclarativeParser::Object *tree() const;
+ QList<Import> imports() const;
+
+ void clear();
+
+ QList<QDeclarativeError> errors() const;
+
+ class JavaScriptMetaData {
+ public:
+ JavaScriptMetaData()
+ : pragmas(QDeclarativeParser::Object::ScriptBlock::None) {}
+
+ QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas;
+ QList<Import> imports;
+ };
+
+ static QDeclarativeParser::Object::ScriptBlock::Pragmas extractPragmas(QString &);
+ static JavaScriptMetaData extractMetaData(QString &);
+
+
+// ### private:
+ TypeReference *findOrCreateType(const QString &name);
+ void setTree(QDeclarativeParser::Object *tree);
+
+ void setScriptFile(const QString &filename) {_scriptFile = filename; }
+ QString scriptFile() const { return _scriptFile; }
+
+// ### private:
+ QList<QDeclarativeError> _errors;
+
+ QDeclarativeParser::Object *root;
+ QList<Import> _imports;
+ QList<TypeReference*> _refTypes;
+ QString _scriptFile;
+ QDeclarativeScriptParserJsASTData *data;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESCRIPTPARSER_P_H
diff --git a/src/declarative/qml/qdeclarativescriptstring.cpp b/src/declarative/qml/qdeclarativescriptstring.cpp
new file mode 100644
index 0000000000..c39e47b18e
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescriptstring.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativescriptstring.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeScriptStringPrivate : public QSharedData
+{
+public:
+ QDeclarativeScriptStringPrivate() : context(0), scope(0) {}
+
+ QDeclarativeContext *context;
+ QObject *scope;
+ QString script;
+};
+
+/*!
+\class QDeclarativeScriptString
+\since 4.7
+\brief The QDeclarativeScriptString class encapsulates a script and its context.
+
+QDeclarativeScriptString is used to create QObject properties that accept a script "assignment" from QML.
+
+Normally, the following QML would result in a binding being established for the \c script
+property; i.e. \c script would be assigned the value obtained from running \c {myObj.value = Math.max(myValue, 100)}
+
+\qml
+MyType {
+ script: myObj.value = Math.max(myValue, 100)
+}
+\endqml
+
+If instead the property had a type of QDeclarativeScriptString,
+the script itself -- \e {myObj.value = Math.max(myValue, 100)} -- would be passed to the \c script property
+and the class could choose how to handle it. Typically, the class will evaluate
+the script at some later time using a QDeclarativeExpression.
+
+\code
+QDeclarativeExpression expr(scriptString.context(), scriptString.script(), scriptStr.scopeObject());
+expr.value();
+\endcode
+
+\sa QDeclarativeExpression
+*/
+
+/*!
+Constructs an empty instance.
+*/
+QDeclarativeScriptString::QDeclarativeScriptString()
+: d(new QDeclarativeScriptStringPrivate)
+{
+}
+
+/*!
+Copies \a other.
+*/
+QDeclarativeScriptString::QDeclarativeScriptString(const QDeclarativeScriptString &other)
+: d(other.d)
+{
+}
+
+/*!
+\internal
+*/
+QDeclarativeScriptString::~QDeclarativeScriptString()
+{
+}
+
+/*!
+Assigns \a other to this.
+*/
+QDeclarativeScriptString &QDeclarativeScriptString::operator=(const QDeclarativeScriptString &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+Returns the context for the script.
+*/
+QDeclarativeContext *QDeclarativeScriptString::context() const
+{
+ return d->context;
+}
+
+/*!
+Sets the \a context for the script.
+*/
+void QDeclarativeScriptString::setContext(QDeclarativeContext *context)
+{
+ d->context = context;
+}
+
+/*!
+Returns the scope object for the script.
+*/
+QObject *QDeclarativeScriptString::scopeObject() const
+{
+ return d->scope;
+}
+
+/*!
+Sets the scope \a object for the script.
+*/
+void QDeclarativeScriptString::setScopeObject(QObject *object)
+{
+ d->scope = object;
+}
+
+/*!
+Returns the script text.
+*/
+QString QDeclarativeScriptString::script() const
+{
+ return d->script;
+}
+
+/*!
+Sets the \a script text.
+*/
+void QDeclarativeScriptString::setScript(const QString &script)
+{
+ d->script = script;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativescriptstring.h b/src/declarative/qml/qdeclarativescriptstring.h
new file mode 100644
index 0000000000..fba0961192
--- /dev/null
+++ b/src/declarative/qml/qdeclarativescriptstring.h
@@ -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 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 QDECLARATIVESCRIPTSTRING_H
+#define QDECLARATIVESCRIPTSTRING_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QObject;
+class QDeclarativeContext;
+class QDeclarativeScriptStringPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeScriptString
+{
+public:
+ QDeclarativeScriptString();
+ QDeclarativeScriptString(const QDeclarativeScriptString &);
+ ~QDeclarativeScriptString();
+
+ QDeclarativeScriptString &operator=(const QDeclarativeScriptString &);
+
+ QDeclarativeContext *context() const;
+ void setContext(QDeclarativeContext *);
+
+ QObject *scopeObject() const;
+ void setScopeObject(QObject *);
+
+ QString script() const;
+ void setScript(const QString &);
+
+private:
+ QSharedDataPointer<QDeclarativeScriptStringPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeScriptString)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESCRIPTSTRING_H
+
diff --git a/src/declarative/qml/qdeclarativesqldatabase.cpp b/src/declarative/qml/qdeclarativesqldatabase.cpp
new file mode 100644
index 0000000000..4ed2bba525
--- /dev/null
+++ b/src/declarative/qml/qdeclarativesqldatabase.cpp
@@ -0,0 +1,448 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativesqldatabase_p.h"
+
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativerefcount_p.h"
+#include "private/qdeclarativeengine_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptvalueiterator.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+#include <QtScript/qscriptclasspropertyiterator.h>
+#include <QtSql/qsqldatabase.h>
+#include <QtSql/qsqlquery.h>
+#include <QtSql/qsqlerror.h>
+#include <QtSql/qsqlrecord.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdebug.h>
+
+Q_DECLARE_METATYPE(QSqlDatabase)
+Q_DECLARE_METATYPE(QSqlQuery)
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSqlQueryScriptClass: public QScriptClass {
+public:
+ QDeclarativeSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine)
+ {
+ str_length = engine->toStringHandle(QLatin1String("length"));
+ str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization)
+ }
+
+ QueryFlags queryProperty(const QScriptValue &,
+ const QScriptString &name,
+ QueryFlags flags, uint *)
+ {
+ if (flags & HandlesReadAccess) {
+ if (name == str_length) {
+ return HandlesReadAccess;
+ } else if (name == str_forwardOnly) {
+ return flags;
+ }
+ }
+ if (flags & HandlesWriteAccess)
+ if (name == str_forwardOnly)
+ return flags;
+ return 0;
+ }
+
+ QScriptValue property(const QScriptValue &object,
+ const QScriptString &name, uint)
+ {
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
+ if (name == str_length) {
+ int s = query.size();
+ if (s<0) {
+ // Inefficient.
+ if (query.last()) {
+ return query.at()+1;
+ } else {
+ return 0;
+ }
+ } else {
+ return s;
+ }
+ } else if (name == str_forwardOnly) {
+ return query.isForwardOnly();
+ }
+ return engine()->undefinedValue();
+ }
+
+ void setProperty(QScriptValue &object,
+ const QScriptString &name, uint, const QScriptValue & value)
+ {
+ if (name == str_forwardOnly) {
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
+ query.setForwardOnly(value.toBool());
+ }
+ }
+
+ QScriptValue::PropertyFlags propertyFlags(const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/)
+ {
+ if (name == str_length) {
+ return QScriptValue::Undeletable
+ | QScriptValue::SkipInEnumeration;
+ }
+ return QScriptValue::Undeletable;
+ }
+
+private:
+ QScriptString str_length;
+ QScriptString str_forwardOnly;
+};
+
+// If the spec changes to allow iteration, check git history...
+// class QDeclarativeSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator
+
+
+
+enum SqlException {
+ UNKNOWN_ERR,
+ DATABASE_ERR,
+ VERSION_ERR,
+ TOO_LARGE_ERR,
+ QUOTA_ERR,
+ SYNTAX_ERR,
+ CONSTRAINT_ERR,
+ TIMEOUT_ERR
+};
+
+static const char* sqlerror[] = {
+ "UNKNOWN_ERR",
+ "DATABASE_ERR",
+ "VERSION_ERR",
+ "TOO_LARGE_ERR",
+ "QUOTA_ERR",
+ "SYNTAX_ERR",
+ "CONSTRAINT_ERR",
+ "TIMEOUT_ERR",
+ 0
+};
+
+#define THROW_SQL(error, desc) \
+{ \
+ QScriptValue errorValue = context->throwError(desc); \
+ errorValue.setProperty(QLatin1String("code"), error); \
+ return errorValue; \
+}
+
+static QString qmlsqldatabase_databasesPath(QScriptEngine *engine)
+{
+ QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
+ return qmlengine->offlineStoragePath
+ + QDir::separator() + QLatin1String("Databases");
+}
+
+static void qmlsqldatabase_initDatabasesPath(QScriptEngine *engine)
+{
+ QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+}
+
+static QString qmlsqldatabase_databaseFile(const QString& connectionName, QScriptEngine *engine)
+{
+ return qmlsqldatabase_databasesPath(engine) + QDir::separator()
+ + connectionName;
+}
+
+
+static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine)
+{
+ QSqlQuery query = qscriptvalue_cast<QSqlQuery>(context->thisObject().data());
+ int i = context->argument(0).toNumber();
+ if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at())
+ QSqlRecord r = query.record();
+ QScriptValue row = engine->newObject();
+ for (int j=0; j<r.count(); ++j) {
+ row.setProperty(r.fieldName(j), QScriptValue(engine,r.value(j).toString()));
+ }
+ return row;
+ }
+ return engine->undefinedValue();
+}
+
+static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/)
+{
+ THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
+}
+
+static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine)
+{
+ QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
+ QString sql = context->argument(0).toString();
+ QSqlQuery query(db);
+ bool err = false;
+
+ QScriptValue result;
+
+ if (query.prepare(sql)) {
+ if (context->argumentCount() > 1) {
+ QScriptValue values = context->argument(1);
+ if (values.isObject()) {
+ if (values.isArray()) {
+ int size = values.property(QLatin1String("length")).toInt32();
+ for (int i = 0; i < size; ++i)
+ query.bindValue(i, values.property(i).toVariant());
+ } else {
+ for (QScriptValueIterator it(values); it.hasNext();) {
+ it.next();
+ query.bindValue(it.name(),it.value().toVariant());
+ }
+ }
+ } else {
+ query.bindValue(0,values.toVariant());
+ }
+ }
+ if (query.exec()) {
+ result = engine->newObject();
+ QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
+ if (!qmlengine->sqlQueryClass)
+ qmlengine->sqlQueryClass = new QDeclarativeSqlQueryScriptClass(engine);
+ QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass);
+ rows.setData(engine->newVariant(QVariant::fromValue(query)));
+ rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration);
+ result.setProperty(QLatin1String("rows"),rows);
+ result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected());
+ result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString());
+ } else {
+ err = true;
+ }
+ } else {
+ err = true;
+ }
+ if (err)
+ THROW_SQL(DATABASE_ERR,query.lastError().text());
+ return result;
+}
+
+static QScriptValue qmlsqldatabase_executeSql_readonly(QScriptContext *context, QScriptEngine *engine)
+{
+ QString sql = context->argument(0).toString();
+ if (sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
+ return qmlsqldatabase_executeSql(context,engine);
+ } else {
+ THROW_SQL(SYNTAX_ERR,QDeclarativeEngine::tr("Read-only Transaction"))
+ }
+}
+
+static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->argumentCount() < 2)
+ return engine->undefinedValue();
+
+ QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
+ QString from_version = context->argument(0).toString();
+ QString to_version = context->argument(1).toString();
+ QScriptValue callback = context->argument(2);
+
+ QScriptValue instance = engine->newObject();
+ instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1));
+ QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
+
+ QString foundvers = context->thisObject().property(QLatin1String("version")).toString();
+ if (from_version!=foundvers) {
+ THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers));
+ return engine->undefinedValue();
+ }
+
+ bool ok = true;
+ if (callback.isFunction()) {
+ ok = false;
+ db.transaction();
+ callback.call(QScriptValue(), QScriptValueList() << tx);
+ if (engine->hasUncaughtException()) {
+ db.rollback();
+ } else {
+ if (!db.commit()) {
+ db.rollback();
+ THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
+ } else {
+ ok = true;
+ }
+ }
+ }
+
+ if (ok) {
+ context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly);
+#ifndef QT_NO_SETTINGS
+ QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
+ ini.setValue(QLatin1String("Version"), to_version);
+#endif
+ }
+
+ return engine->undefinedValue();
+}
+
+static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly)
+{
+ QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
+ QScriptValue callback = context->argument(0);
+ if (!callback.isFunction())
+ THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));
+
+ QScriptValue instance = engine->newObject();
+ instance.setProperty(QLatin1String("executeSql"),
+ engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1));
+ QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
+
+ db.transaction();
+ callback.call(QScriptValue(), QScriptValueList() << tx);
+ instance.setProperty(QLatin1String("executeSql"),
+ engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction));
+ if (engine->hasUncaughtException()) {
+ db.rollback();
+ } else {
+ if (!db.commit())
+ db.rollback();
+ }
+ return engine->undefinedValue();
+}
+
+static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine)
+{
+ return qmlsqldatabase_transaction_shared(context,engine,false);
+}
+static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QScriptEngine *engine)
+{
+ return qmlsqldatabase_transaction_shared(context,engine,true);
+}
+
+/*
+ Currently documented in doc/src/declarative/globalobject.qdoc
+*/
+static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef QT_NO_SETTINGS
+ qmlsqldatabase_initDatabasesPath(engine);
+
+ QSqlDatabase database;
+
+ QString dbname = context->argument(0).toString();
+ QString dbversion = context->argument(1).toString();
+ QString dbdescription = context->argument(2).toString();
+ int dbestimatedsize = context->argument(3).toNumber();
+ QScriptValue dbcreationCallback = context->argument(4);
+
+ QCryptographicHash md5(QCryptographicHash::Md5);
+ md5.addData(dbname.toUtf8());
+ QString dbid(QLatin1String(md5.result().toHex()));
+
+ QString basename = qmlsqldatabase_databaseFile(dbid, engine);
+ bool created = false;
+ QString version = dbversion;
+
+ {
+ QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
+
+ if (QSqlDatabase::connectionNames().contains(dbid)) {
+ database = QSqlDatabase::database(dbid);
+ version = ini.value(QLatin1String("Version")).toString();
+ if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
+ THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ } else {
+ created = !QFile::exists(basename+QLatin1String(".sqlite"));
+ database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
+ if (created) {
+ ini.setValue(QLatin1String("Name"), dbname);
+ if (dbcreationCallback.isFunction())
+ version = QString();
+ ini.setValue(QLatin1String("Version"), version);
+ ini.setValue(QLatin1String("Description"), dbdescription);
+ ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
+ ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
+ } else {
+ if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
+ // Incompatible
+ THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ }
+ version = ini.value(QLatin1String("Version")).toString();
+ }
+ database.setDatabaseName(basename+QLatin1String(".sqlite"));
+ }
+ if (!database.isOpen())
+ database.open();
+ }
+
+ QScriptValue instance = engine->newObject();
+ instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1));
+ instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1));
+ instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly);
+ instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3));
+
+ QScriptValue result = engine->newVariant(instance,QVariant::fromValue(database));
+
+ if (created && dbcreationCallback.isFunction()) {
+ dbcreationCallback.call(QScriptValue(), QScriptValueList() << result);
+ }
+
+ return result;
+#else
+ return engine->undefinedValue();
+#endif // QT_NO_SETTINGS
+}
+
+void qt_add_qmlsqldatabase(QScriptEngine *engine)
+{
+ QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open_sync, 4);
+ engine->globalObject().setProperty(QLatin1String("openDatabaseSync"), openDatabase);
+
+ QScriptValue sqlExceptionPrototype = engine->newObject();
+ for (int i=0; sqlerror[i]; ++i)
+ sqlExceptionPrototype.setProperty(QLatin1String(sqlerror[i]),
+ i,QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+
+ engine->globalObject().setProperty(QLatin1String("SQLException"), sqlExceptionPrototype);
+}
+
+/*
+HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator).
+We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward
+through the data.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativesqldatabase_p.h b/src/declarative/qml/qdeclarativesqldatabase_p.h
new file mode 100644
index 0000000000..671bd3062c
--- /dev/null
+++ b/src/declarative/qml/qdeclarativesqldatabase_p.h
@@ -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 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 QDECLARATIVESQLDATABASE_P_H
+#define QDECLARATIVESQLDATABASE_P_H
+
+#include <QtScript/qscriptengine.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 QScriptEngine;
+void qt_add_qmlsqldatabase(QScriptEngine *engine);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESQLDATABASE_P_H
+
diff --git a/src/declarative/qml/qdeclarativestringconverters.cpp b/src/declarative/qml/qdeclarativestringconverters.cpp
new file mode 100644
index 0000000000..aa1de43afa
--- /dev/null
+++ b/src/declarative/qml/qdeclarativestringconverters.cpp
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativestringconverters_p.h"
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+static uchar fromHex(const uchar c, const uchar c2)
+{
+ uchar rv = 0;
+ if (c >= '0' && c <= '9')
+ rv += (c - '0') * 16;
+ else if (c >= 'A' && c <= 'F')
+ rv += (c - 'A' + 10) * 16;
+ else if (c >= 'a' && c <= 'f')
+ rv += (c - 'a' + 10) * 16;
+
+ if (c2 >= '0' && c2 <= '9')
+ rv += (c2 - '0');
+ else if (c2 >= 'A' && c2 <= 'F')
+ rv += (c2 - 'A' + 10);
+ else if (c2 >= 'a' && c2 <= 'f')
+ rv += (c2 - 'a' + 10);
+
+ return rv;
+}
+
+static uchar fromHex(const QString &s, int idx)
+{
+ uchar c = s.at(idx).toAscii();
+ uchar c2 = s.at(idx + 1).toAscii();
+ return fromHex(c, c2);
+}
+
+QVariant QDeclarativeStringConverters::variantFromString(const QString &s)
+{
+ if (s.isEmpty())
+ return QVariant(s);
+ bool ok = false;
+ QRectF r = rectFFromString(s, &ok);
+ if (ok) return QVariant(r);
+ QColor c = colorFromString(s, &ok);
+ if (ok) return QVariant(c);
+ QPointF p = pointFFromString(s, &ok);
+ if (ok) return QVariant(p);
+ QSizeF sz = sizeFFromString(s, &ok);
+ if (ok) return QVariant(sz);
+ QVector3D v = vector3DFromString(s, &ok);
+ if (ok) return QVariant::fromValue(v);
+
+ return QVariant(s);
+}
+
+QVariant QDeclarativeStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
+{
+ switch (preferredType) {
+ case QMetaType::Int:
+ return QVariant(int(qRound(s.toDouble(ok))));
+ case QMetaType::UInt:
+ return QVariant(uint(qRound(s.toDouble(ok))));
+ case QMetaType::QColor:
+ return QVariant::fromValue(colorFromString(s, ok));
+#ifndef QT_NO_DATESTRING
+ case QMetaType::QDate:
+ return QVariant::fromValue(dateFromString(s, ok));
+ case QMetaType::QTime:
+ return QVariant::fromValue(timeFromString(s, ok));
+ case QMetaType::QDateTime:
+ return QVariant::fromValue(dateTimeFromString(s, ok));
+#endif // QT_NO_DATESTRING
+ case QMetaType::QPointF:
+ return QVariant::fromValue(pointFFromString(s, ok));
+ case QMetaType::QPoint:
+ return QVariant::fromValue(pointFFromString(s, ok).toPoint());
+ case QMetaType::QSizeF:
+ return QVariant::fromValue(sizeFFromString(s, ok));
+ case QMetaType::QSize:
+ return QVariant::fromValue(sizeFFromString(s, ok).toSize());
+ case QMetaType::QRectF:
+ return QVariant::fromValue(rectFFromString(s, ok));
+ case QMetaType::QRect:
+ return QVariant::fromValue(rectFFromString(s, ok).toRect());
+ case QMetaType::QVector3D:
+ return QVariant::fromValue(vector3DFromString(s, ok));
+ default:
+ if (ok) *ok = false;
+ return QVariant();
+ }
+}
+
+QColor QDeclarativeStringConverters::colorFromString(const QString &s, bool *ok)
+{
+ if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) {
+ uchar a = fromHex(s, 1);
+ uchar r = fromHex(s, 3);
+ uchar g = fromHex(s, 5);
+ uchar b = fromHex(s, 7);
+ if (ok) *ok = true;
+ return QColor(r, g, b, a);
+ } else {
+ QColor rv(s);
+ if (ok) *ok = rv.isValid();
+ return rv;
+ }
+}
+
+#ifndef QT_NO_DATESTRING
+QDate QDeclarativeStringConverters::dateFromString(const QString &s, bool *ok)
+{
+ QDate d = QDate::fromString(s, Qt::ISODate);
+ if (ok) *ok = d.isValid();
+ return d;
+}
+
+QTime QDeclarativeStringConverters::timeFromString(const QString &s, bool *ok)
+{
+ QTime t = QTime::fromString(s, Qt::ISODate);
+ if (ok) *ok = t.isValid();
+ return t;
+}
+
+QDateTime QDeclarativeStringConverters::dateTimeFromString(const QString &s, bool *ok)
+{
+ QDateTime d = QDateTime::fromString(s, Qt::ISODate);
+ if (ok) *ok = d.isValid();
+ return d;
+}
+#endif // QT_NO_DATESTRING
+
+//expects input of "x,y"
+QPointF QDeclarativeStringConverters::pointFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 1) {
+ if (ok)
+ *ok = false;
+ return QPointF();
+ }
+
+ bool xGood, yGood;
+ int index = s.indexOf(QLatin1Char(','));
+ qreal xCoord = s.left(index).toDouble(&xGood);
+ qreal yCoord = s.mid(index+1).toDouble(&yGood);
+ if (!xGood || !yGood) {
+ if (ok)
+ *ok = false;
+ return QPointF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QPointF(xCoord, yCoord);
+}
+
+//expects input of "widthxheight"
+QSizeF QDeclarativeStringConverters::sizeFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char('x')) != 1) {
+ if (ok)
+ *ok = false;
+ return QSizeF();
+ }
+
+ bool wGood, hGood;
+ int index = s.indexOf(QLatin1Char('x'));
+ qreal width = s.left(index).toDouble(&wGood);
+ qreal height = s.mid(index+1).toDouble(&hGood);
+ if (!wGood || !hGood) {
+ if (ok)
+ *ok = false;
+ return QSizeF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QSizeF(width, height);
+}
+
+//expects input of "x,y,widthxheight" //### use space instead of second comma?
+QRectF QDeclarativeStringConverters::rectFFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) {
+ if (ok)
+ *ok = false;
+ return QRectF();
+ }
+
+ bool xGood, yGood, wGood, hGood;
+ int index = s.indexOf(QLatin1Char(','));
+ qreal x = s.left(index).toDouble(&xGood);
+ int index2 = s.indexOf(QLatin1Char(','), index+1);
+ qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood);
+ index = s.indexOf(QLatin1Char('x'), index2+1);
+ qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood);
+ qreal height = s.mid(index+1).toDouble(&hGood);
+ if (!xGood || !yGood || !wGood || !hGood) {
+ if (ok)
+ *ok = false;
+ return QRectF();
+ }
+
+ if (ok)
+ *ok = true;
+ return QRectF(x, y, width, height);
+}
+
+//expects input of "x,y,z"
+QVector3D QDeclarativeStringConverters::vector3DFromString(const QString &s, bool *ok)
+{
+ if (s.count(QLatin1Char(',')) != 2) {
+ if (ok)
+ *ok = false;
+ return QVector3D();
+ }
+
+ bool xGood, yGood, zGood;
+ int index = s.indexOf(QLatin1Char(','));
+ int index2 = s.indexOf(QLatin1Char(','), index+1);
+ qreal xCoord = s.left(index).toDouble(&xGood);
+ qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood);
+ qreal zCoord = s.mid(index2+1).toDouble(&zGood);
+ if (!xGood || !yGood || !zGood) {
+ if (ok)
+ *ok = false;
+ return QVector3D();
+ }
+
+ if (ok)
+ *ok = true;
+ return QVector3D(xCoord, yCoord, zCoord);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativestringconverters_p.h b/src/declarative/qml/qdeclarativestringconverters_p.h
new file mode 100644
index 0000000000..b875980bd4
--- /dev/null
+++ b/src/declarative/qml/qdeclarativestringconverters_p.h
@@ -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 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 QDECLARATIVESTRINGCONVERTERS_P_H
+#define QDECLARATIVESTRINGCONVERTERS_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/qvariant.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColor;
+class QPointF;
+class QSizeF;
+class QRectF;
+class QString;
+class QByteArray;
+class QVector3D;
+
+// XXX - Bauhaus currently uses these methods which is why they're exported
+namespace QDeclarativeStringConverters
+{
+ QVariant Q_DECLARATIVE_PRIVATE_EXPORT variantFromString(const QString &);
+ QVariant Q_DECLARATIVE_PRIVATE_EXPORT variantFromString(const QString &, int preferredType, bool *ok = 0);
+
+ QColor Q_DECLARATIVE_PRIVATE_EXPORT colorFromString(const QString &, bool *ok = 0);
+#ifndef QT_NO_DATESTRING
+ QDate Q_DECLARATIVE_PRIVATE_EXPORT dateFromString(const QString &, bool *ok = 0);
+ QTime Q_DECLARATIVE_PRIVATE_EXPORT timeFromString(const QString &, bool *ok = 0);
+ QDateTime Q_DECLARATIVE_PRIVATE_EXPORT dateTimeFromString(const QString &, bool *ok = 0);
+#endif
+ QPointF Q_DECLARATIVE_PRIVATE_EXPORT pointFFromString(const QString &, bool *ok = 0);
+ QSizeF Q_DECLARATIVE_PRIVATE_EXPORT sizeFFromString(const QString &, bool *ok = 0);
+ QRectF Q_DECLARATIVE_PRIVATE_EXPORT rectFFromString(const QString &, bool *ok = 0);
+ QVector3D Q_DECLARATIVE_PRIVATE_EXPORT vector3DFromString(const QString &, bool *ok = 0);
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESTRINGCONVERTERS_P_H
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
new file mode 100644
index 0000000000..26f3996871
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -0,0 +1,1089 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativetypeloader_p.h"
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecompiler_p.h>
+#include <private/qdeclarativecomponent_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativedebugtrace_p.h>
+
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QDeclarativeDataBlob
+\brief The QDeclarativeDataBlob encapsulates a data request that can be issued to a QDeclarativeDataLoader.
+\internal
+
+QDeclarativeDataBlob's are loaded by a QDeclarativeDataLoader. The user creates the QDeclarativeDataBlob
+and then calls QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() to load it.
+The QDeclarativeDataLoader invokes callbacks on the QDeclarativeDataBlob as data becomes available.
+*/
+
+/*!
+\enum QDeclarativeDataBlob::Status
+
+This enum describes the status of the data blob.
+
+\list
+\o Null The blob has not yet been loaded by a QDeclarativeDataLoader
+\o Loading The blob is loading network data. The QDeclarativeDataBlob::setData() callback has not yet been
+invoked or has not yet returned.
+\o WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
+only occurs after the QDeclarativeDataBlob::setData() callback has been made, and when the blob has outstanding
+dependencies.
+\o Complete The blob's data has been loaded and all dependencies are done.
+\o Error An error has been set on this blob.
+\endlist
+*/
+
+/*!
+\enum QDeclarativeDataBlob::Type
+
+This enum describes the type of the data blob.
+
+\list
+\o QmlFile This is a QDeclarativeTypeData
+\o JavaScriptFile This is a QDeclarativeScriptData
+\o QmldirFile This is a QDeclarativeQmldirData
+\endlist
+*/
+
+/*!
+Create a new QDeclarativeDataBlob for \a url and of the provided \a type.
+*/
+QDeclarativeDataBlob::QDeclarativeDataBlob(const QUrl &url, Type type)
+: m_type(type), m_status(Null), m_progress(0), m_url(url), m_finalUrl(url), m_manager(0),
+ m_redirectCount(0), m_inCallback(false), m_isDone(false)
+{
+}
+
+/*! \internal */
+QDeclarativeDataBlob::~QDeclarativeDataBlob()
+{
+ Q_ASSERT(m_waitingOnMe.isEmpty());
+
+ cancelAllWaitingFor();
+}
+
+/*!
+Returns the type provided to the constructor.
+*/
+QDeclarativeDataBlob::Type QDeclarativeDataBlob::type() const
+{
+ return m_type;
+}
+
+/*!
+Returns the blob's status.
+*/
+QDeclarativeDataBlob::Status QDeclarativeDataBlob::status() const
+{
+ return m_status;
+}
+
+/*!
+Returns true if the status is Null.
+*/
+bool QDeclarativeDataBlob::isNull() const
+{
+ return m_status == Null;
+}
+
+/*!
+Returns true if the status is Loading.
+*/
+bool QDeclarativeDataBlob::isLoading() const
+{
+ return m_status == Loading;
+}
+
+/*!
+Returns true if the status is WaitingForDependencies.
+*/
+bool QDeclarativeDataBlob::isWaiting() const
+{
+ return m_status == WaitingForDependencies;
+}
+
+/*!
+Returns true if the status is Complete.
+*/
+bool QDeclarativeDataBlob::isComplete() const
+{
+ return m_status == Complete;
+}
+
+/*!
+Returns true if the status is Error.
+*/
+bool QDeclarativeDataBlob::isError() const
+{
+ return m_status == Error;
+}
+
+/*!
+Returns true if the status is Complete or Error.
+*/
+bool QDeclarativeDataBlob::isCompleteOrError() const
+{
+ return isComplete() || isError();
+}
+
+/*!
+Returns the data download progress from 0 to 1.
+*/
+qreal QDeclarativeDataBlob::progress() const
+{
+ return m_progress;
+}
+
+/*!
+Returns the blob url passed to the constructor. If a network redirect
+happens while fetching the data, this url remains the same.
+
+\sa finalUrl()
+*/
+QUrl QDeclarativeDataBlob::url() const
+{
+ return m_url;
+}
+
+/*!
+Returns the final url of the data. Initially this is the same as
+url(), but if a network redirect happens while fetching the data, this url
+is updated to reflect the new location.
+*/
+QUrl QDeclarativeDataBlob::finalUrl() const
+{
+ return m_finalUrl;
+}
+
+/*!
+Return the errors on this blob.
+*/
+QList<QDeclarativeError> QDeclarativeDataBlob::errors() const
+{
+ return m_errors;
+}
+
+/*!
+Mark this blob as having \a errors.
+
+All outstanding dependencies will be cancelled. Requests to add new dependencies
+will be ignored. Entry into the Error state is irreversable, although you can change the
+specific errors by additional calls to setError.
+*/
+void QDeclarativeDataBlob::setError(const QDeclarativeError &errors)
+{
+ QList<QDeclarativeError> l;
+ l << errors;
+ setError(l);
+}
+
+/*!
+\overload
+*/
+void QDeclarativeDataBlob::setError(const QList<QDeclarativeError> &errors)
+{
+ m_status = Error;
+ m_errors = errors;
+
+ cancelAllWaitingFor();
+
+ if (!m_inCallback)
+ tryDone();
+}
+
+/*!
+Wait for \a blob to become complete or to error. If \a blob is already
+complete or in error, or this blob is already complete, this has no effect.
+*/
+void QDeclarativeDataBlob::addDependency(QDeclarativeDataBlob *blob)
+{
+ Q_ASSERT(status() != Null);
+
+ if (!blob ||
+ blob->status() == Error || blob->status() == Complete ||
+ status() == Error || status() == Complete ||
+ m_waitingFor.contains(blob))
+ return;
+
+ blob->addref();
+ m_status = WaitingForDependencies;
+ m_waitingFor.append(blob);
+ blob->m_waitingOnMe.append(this);
+}
+
+/*!
+\fn void QDeclarativeDataBlob::dataReceived(const QByteArray &data)
+
+Invoked when data for the blob is received. Implementors should use this callback
+to determine a blob's dependencies. Within this callback you may call setError()
+or addDependency().
+*/
+
+/*!
+Invoked once data has either been received or a network error occurred, and all
+dependencies are complete.
+
+You can set an error in this method, but you cannot add new dependencies. Implementors
+should use this callback to finalize processing of data.
+
+The default implementation does nothing.
+*/
+void QDeclarativeDataBlob::done()
+{
+}
+
+/*!
+Invoked if there is a network error while fetching this blob.
+
+The default implementation sets an appropriate QDeclarativeError.
+*/
+void QDeclarativeDataBlob::networkError(QNetworkReply::NetworkError networkError)
+{
+ Q_UNUSED(networkError);
+
+ QDeclarativeError error;
+ error.setUrl(m_finalUrl);
+
+ const char *errorString = 0;
+ switch (networkError) {
+ default:
+ errorString = "Network error";
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ errorString = "Connection refused";
+ break;
+ case QNetworkReply::RemoteHostClosedError:
+ errorString = "Remote host closed the connection";
+ break;
+ case QNetworkReply::HostNotFoundError:
+ errorString = "Host not found";
+ break;
+ case QNetworkReply::TimeoutError:
+ errorString = "Timeout";
+ break;
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ errorString = "Proxy error";
+ break;
+ case QNetworkReply::ContentAccessDenied:
+ errorString = "Access denied";
+ break;
+ case QNetworkReply::ContentNotFoundError:
+ errorString = "File not found";
+ break;
+ case QNetworkReply::AuthenticationRequiredError:
+ errorString = "Authentication required";
+ break;
+ };
+
+ error.setDescription(QLatin1String(errorString));
+
+ setError(error);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has an error.
+
+The default implementation does nothing.
+*/
+void QDeclarativeDataBlob::dependencyError(QDeclarativeDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has completed.
+
+The default implementation does nothing.
+*/
+void QDeclarativeDataBlob::dependencyComplete(QDeclarativeDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called when all blobs waited for have completed. This occurs regardless of
+whether they are in error, or complete state.
+
+The default implementation does nothing.
+*/
+void QDeclarativeDataBlob::allDependenciesDone()
+{
+}
+
+/*!
+Called when the download progress of this blob changes. \a progress goes
+from 0 to 1.
+*/
+void QDeclarativeDataBlob::downloadProgressChanged(qreal progress)
+{
+ Q_UNUSED(progress);
+}
+
+void QDeclarativeDataBlob::tryDone()
+{
+ if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
+ if (status() != Error)
+ m_status = Complete;
+
+ m_isDone = true;
+ done();
+ notifyAllWaitingOnMe();
+ }
+}
+
+void QDeclarativeDataBlob::cancelAllWaitingFor()
+{
+ while (m_waitingFor.count()) {
+ QDeclarativeDataBlob *blob = m_waitingFor.takeLast();
+
+ Q_ASSERT(blob->m_waitingOnMe.contains(this));
+
+ blob->m_waitingOnMe.removeOne(this);
+
+ blob->release();
+ }
+}
+
+void QDeclarativeDataBlob::notifyAllWaitingOnMe()
+{
+ while (m_waitingOnMe.count()) {
+ QDeclarativeDataBlob *blob = m_waitingOnMe.takeLast();
+
+ Q_ASSERT(blob->m_waitingFor.contains(this));
+
+ blob->notifyComplete(this);
+ }
+}
+
+void QDeclarativeDataBlob::notifyComplete(QDeclarativeDataBlob *blob)
+{
+ Q_ASSERT(m_waitingFor.contains(blob));
+ Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+
+ m_inCallback = true;
+
+ if (blob->status() == Error) {
+ dependencyError(blob);
+ } else if (blob->status() == Complete) {
+ dependencyComplete(blob);
+ }
+
+ m_waitingFor.removeOne(blob);
+ blob->release();
+
+ if (!isError() && m_waitingFor.isEmpty())
+ allDependenciesDone();
+
+ m_inCallback = false;
+
+ tryDone();
+}
+
+/*!
+\class QDeclarativeDataLoader
+\brief The QDeclarativeDataLoader class abstracts loading files and their dependecies over the network.
+\internal
+
+The QDeclarativeDataLoader class is provided for the exclusive use of the QDeclarativeTypeLoader class.
+
+Clients create QDeclarativeDataBlob instances and submit them to the QDeclarativeDataLoader class
+through the QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() methods.
+The loader then fetches the data over the network or from the local file system in an efficient way.
+QDeclarativeDataBlob is an abstract class, so should always be specialized.
+
+Once data is received, the QDeclarativeDataBlob::dataReceived() method is invoked on the blob. The
+derived class should use this callback to process the received data. Processing of the data can
+result in an error being set (QDeclarativeDataBlob::setError()), or one or more dependencies being
+created (QDeclarativeDataBlob::addDependency()). Dependencies are other QDeclarativeDataBlob's that
+are required before processing can fully complete.
+
+To complete processing, the QDeclarativeDataBlob::done() callback is invoked. done() is called when
+one of these three preconditions are met.
+
+1. The QDeclarativeDataBlob has no dependencies.
+2. The QDeclarativeDataBlob has an error set.
+3. All the QDeclarativeDataBlob's dependencies are themselves "done()".
+
+Thus QDeclarativeDataBlob::done() will always eventually be called, even if the blob has an error set.
+*/
+
+/*!
+Create a new QDeclarativeDataLoader for \a engine.
+*/
+QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine)
+: m_engine(engine)
+{
+}
+
+/*! \internal */
+QDeclarativeDataLoader::~QDeclarativeDataLoader()
+{
+ for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
+ (*iter)->release();
+}
+
+/*!
+Load the provided \a blob from the network or filesystem.
+*/
+void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob)
+{
+ Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
+ Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_status = QDeclarativeDataBlob::Loading;
+
+ if (blob->m_url.isEmpty()) {
+ QDeclarativeError error;
+ error.setDescription(QLatin1String("Invalid null URL"));
+ blob->setError(error);
+ return;
+ }
+
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url);
+
+ if (!lf.isEmpty()) {
+ if (!QDeclarative_isFileCaseCorrect(lf)) {
+ QDeclarativeError error;
+ error.setUrl(blob->m_url);
+ error.setDescription(QLatin1String("File name case mismatch"));
+ blob->setError(error);
+ return;
+ }
+ QFile file(lf);
+ if (file.open(QFile::ReadOnly)) {
+ QByteArray data = file.readAll();
+
+ blob->m_progress = 1.;
+ blob->downloadProgressChanged(1.);
+
+ setData(blob, data);
+ } else {
+ blob->networkError(QNetworkReply::ContentNotFoundError);
+ }
+
+ } else {
+
+ blob->m_manager = this;
+ QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url));
+ QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(networkReplyProgress(qint64,qint64)));
+ QObject::connect(reply, SIGNAL(finished()),
+ this, SLOT(networkReplyFinished()));
+ m_networkReplies.insert(reply, blob);
+
+ blob->addref();
+ }
+}
+
+#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
+
+void QDeclarativeDataLoader::networkReplyFinished()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reply->deleteLater();
+
+ QDeclarativeDataBlob *blob = m_networkReplies.take(reply);
+
+ Q_ASSERT(blob);
+
+ blob->m_redirectCount++;
+
+ if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ blob->m_finalUrl = url;
+
+ QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url));
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ m_networkReplies.insert(reply, blob);
+ return;
+ }
+ }
+
+ if (reply->error()) {
+ blob->networkError(reply->error());
+ } else {
+ QByteArray data = reply->readAll();
+ setData(blob, data);
+ }
+
+ blob->release();
+}
+
+void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ QDeclarativeDataBlob *blob = m_networkReplies.value(reply);
+
+ Q_ASSERT(blob);
+
+ if (bytesTotal != 0) {
+ blob->m_progress = bytesReceived / bytesTotal;
+ blob->downloadProgressChanged(blob->m_progress);
+ }
+}
+
+/*!
+Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case.
+*/
+void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data)
+{
+ Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null);
+ Q_ASSERT(blob->m_manager == 0);
+
+ blob->m_status = QDeclarativeDataBlob::Loading;
+
+ setData(blob, data);
+}
+
+/*!
+Return the QDeclarativeEngine associated with this loader
+*/
+QDeclarativeEngine *QDeclarativeDataLoader::engine() const
+{
+ return m_engine;
+}
+
+void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data)
+{
+ blob->m_inCallback = true;
+
+ blob->dataReceived(data);
+
+ if (!blob->isError() && !blob->isWaiting())
+ blob->allDependenciesDone();
+
+ if (blob->status() != QDeclarativeDataBlob::Error)
+ blob->m_status = QDeclarativeDataBlob::WaitingForDependencies;
+
+ blob->m_inCallback = false;
+
+ blob->tryDone();
+}
+
+/*!
+\class QDeclarativeTypeLoader
+*/
+QDeclarativeTypeLoader::QDeclarativeTypeLoader(QDeclarativeEngine *engine)
+: QDeclarativeDataLoader(engine)
+{
+}
+
+QDeclarativeTypeLoader::~QDeclarativeTypeLoader()
+{
+ clearCache();
+}
+
+/*!
+\enum QDeclarativeTypeLoader::Option
+
+This enum defines the options that control the way type data is handled.
+
+\value None The default value, indicating that no other options
+ are enabled.
+\value PreserveParser The parser used to handle the type data is preserved
+ after the data has been parsed.
+*/
+
+/*!
+Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached.
+*/
+QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ QDeclarativeTypeData *typeData = m_typeCache.value(url);
+
+ if (!typeData) {
+ typeData = new QDeclarativeTypeData(url, None, this);
+ m_typeCache.insert(url, typeData);
+ QDeclarativeDataLoader::load(typeData);
+ }
+
+ typeData->addref();
+ return typeData;
+}
+
+/*!
+Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The
+QDeclarativeTypeData will not be cached.
+
+The specified \a options control how the loader handles type data.
+*/
+QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options)
+{
+ QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this);
+ QDeclarativeDataLoader::loadWithStaticData(typeData, data);
+ return typeData;
+}
+
+/*!
+Return a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached.
+*/
+QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ QDeclarativeScriptData *scriptData = m_scriptCache.value(url);
+
+ if (!scriptData) {
+ scriptData = new QDeclarativeScriptData(url);
+ m_scriptCache.insert(url, scriptData);
+ QDeclarativeDataLoader::load(scriptData);
+ }
+
+ scriptData->addref();
+ return scriptData;
+}
+
+/*!
+Return a QDeclarativeQmldirData for \a url. The QDeclarativeQmldirData may be cached.
+*/
+QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
+{
+ Q_ASSERT(!url.isRelative() &&
+ (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() ||
+ !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url))));
+
+ QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url);
+
+ if (!qmldirData) {
+ qmldirData = new QDeclarativeQmldirData(url);
+ m_qmldirCache.insert(url, qmldirData);
+ QDeclarativeDataLoader::load(qmldirData);
+ }
+
+ qmldirData->addref();
+ return qmldirData;
+}
+
+void QDeclarativeTypeLoader::clearCache()
+{
+ for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter)
+ (*iter)->release();
+ for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter)
+ (*iter)->release();
+ for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter)
+ (*iter)->release();
+
+ m_typeCache.clear();
+ m_scriptCache.clear();
+ m_qmldirCache.clear();
+}
+
+
+QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options,
+ QDeclarativeTypeLoader *manager)
+: QDeclarativeDataBlob(url, QmlFile), m_options(options), m_typesResolved(false),
+ m_compiledData(0), m_typeLoader(manager)
+{
+}
+
+QDeclarativeTypeData::~QDeclarativeTypeData()
+{
+ for (int ii = 0; ii < m_scripts.count(); ++ii)
+ m_scripts.at(ii).script->release();
+ for (int ii = 0; ii < m_qmldirs.count(); ++ii)
+ m_qmldirs.at(ii)->release();
+ for (int ii = 0; ii < m_types.count(); ++ii)
+ if (m_types.at(ii).typeData) m_types.at(ii).typeData->release();
+ if (m_compiledData)
+ m_compiledData->release();
+}
+
+QDeclarativeTypeLoader *QDeclarativeTypeData::typeLoader() const
+{
+ return m_typeLoader;
+}
+
+const QDeclarativeImports &QDeclarativeTypeData::imports() const
+{
+ return m_imports;
+}
+
+const QDeclarativeScriptParser &QDeclarativeTypeData::parser() const
+{
+ return scriptParser;
+}
+
+const QList<QDeclarativeTypeData::TypeReference> &QDeclarativeTypeData::resolvedTypes() const
+{
+ return m_types;
+}
+
+const QList<QDeclarativeTypeData::ScriptReference> &QDeclarativeTypeData::resolvedScripts() const
+{
+ return m_scripts;
+}
+
+QDeclarativeCompiledData *QDeclarativeTypeData::compiledData() const
+{
+ if (m_compiledData)
+ m_compiledData->addref();
+
+ return m_compiledData;
+}
+
+void QDeclarativeTypeData::registerCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(!m_callbacks.contains(callback));
+ m_callbacks.append(callback);
+}
+
+void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(m_callbacks.contains(callback));
+ m_callbacks.removeOne(callback);
+ Q_ASSERT(!m_callbacks.contains(callback));
+}
+
+void QDeclarativeTypeData::done()
+{
+ addref();
+
+ // 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(QDeclarativeTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString()));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ // Check all type dependencies for errors
+ for (int ii = 0; !isError() && ii < m_types.count(); ++ii) {
+ const TypeReference &type = m_types.at(ii);
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = scriptParser.referencedTypes().at(ii)->name;
+
+ QList<QDeclarativeError> errors = type.typeData->errors();
+ QDeclarativeError error;
+ error.setUrl(finalUrl());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QDeclarativeTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ // Compile component
+ if (!isError())
+ compile();
+
+ if (!(m_options & QDeclarativeTypeLoader::PreserveParser))
+ scriptParser.clear();
+
+ // Notify callbacks
+ while (!m_callbacks.isEmpty()) {
+ TypeDataCallback *callback = m_callbacks.takeFirst();
+ callback->typeDataReady(this);
+ }
+
+ release();
+}
+
+void QDeclarativeTypeData::dataReceived(const QByteArray &data)
+{
+ if (!scriptParser.parse(data, finalUrl())) {
+ setError(scriptParser.errors());
+ return;
+ }
+
+ m_imports.setBaseUrl(finalUrl());
+
+ foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
+ if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
+ QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
+ if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
+ QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
+ addDependency(data);
+ m_qmldirs << data;
+ }
+ } else if (import.type == QDeclarativeScriptParser::Import::Script) {
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri));
+ QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl);
+ addDependency(data);
+
+ ScriptReference ref;
+ ref.location = import.location.start;
+ ref.qualifier = import.qualifier;
+ ref.script = data;
+ m_scripts << ref;
+
+ }
+ }
+
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) {
+ QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl);
+ addDependency(data);
+ m_qmldirs << data;
+ }
+ }
+}
+
+void QDeclarativeTypeData::allDependenciesDone()
+{
+ if (!m_typesResolved) {
+ resolveTypes();
+ m_typesResolved = true;
+ }
+}
+
+void QDeclarativeTypeData::downloadProgressChanged(qreal p)
+{
+ for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ TypeDataCallback *callback = m_callbacks.at(ii);
+ callback->typeDataProgress(this, p);
+ }
+}
+
+void QDeclarativeTypeData::compile()
+{
+ Q_ASSERT(m_compiledData == 0);
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling);
+
+ m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine());
+ m_compiledData->url = m_imports.baseUrl();
+ m_compiledData->name = m_compiledData->url.toString();
+ QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name);
+
+ QDeclarativeCompiler compiler;
+ if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) {
+ setError(compiler.errors());
+ m_compiledData->release();
+ m_compiledData = 0;
+ }
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling);
+}
+
+void QDeclarativeTypeData::resolveTypes()
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine());
+ QDeclarativeImportDatabase *importDatabase = &ep->importDatabase;
+
+ // 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.
+ if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) {
+ m_imports.addImport(importDatabase, QLatin1String("."),
+ QString(), -1, -1, QDeclarativeScriptParser::Import::File,
+ qmldir->dirComponents(), 0);
+ } else {
+ m_imports.addImport(importDatabase, QLatin1String("."),
+ QString(), -1, -1, QDeclarativeScriptParser::Import::File,
+ QDeclarativeDirComponents(), 0);
+ }
+
+ foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) {
+ QDeclarativeDirComponents qmldircomponentsnetwork;
+ if (import.type == QDeclarativeScriptParser::Import::Script)
+ continue;
+
+ if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir")));
+ if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl))
+ qmldircomponentsnetwork = qmldir->dirComponents();
+ }
+
+ int vmaj = -1;
+ int vmin = -1;
+
+ 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;
+ if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
+ vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) {
+ QDeclarativeError error;
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(errorString);
+ error.setLine(import.location.start.line);
+ error.setColumn(import.location.start.column);
+
+ setError(error);
+ return;
+ }
+ }
+
+ foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) {
+ QByteArray typeName = parserRef->name.toUtf8();
+
+ TypeReference ref;
+
+ QUrl url;
+ int majorVersion;
+ int minorVersion;
+ QDeclarativeImportedNamespace *typeNamespace = 0;
+ QString errorString;
+
+ if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion,
+ &typeNamespace, &errorString) || 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)
+ 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));
+
+ if (!parserRef->refObjects.isEmpty()) {
+ QDeclarativeParser::Object *obj = parserRef->refObjects.first();
+ error.setLine(obj->location.start.line);
+ error.setColumn(obj->location.start.column);
+ }
+
+ setError(error);
+ return;
+ }
+
+ if (ref.type) {
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
+ foreach (QDeclarativeParser::Object *obj, parserRef->refObjects) {
+ // store namespace for DOM
+ obj->majorVersion = majorVersion;
+ obj->minorVersion = minorVersion;
+ }
+ } else {
+ ref.typeData = typeLoader()->get(url);
+ addDependency(ref.typeData);
+ }
+
+ if (parserRef->refObjects.count())
+ ref.location = parserRef->refObjects.first()->location.start;
+
+ m_types << ref;
+ }
+}
+
+QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url)
+{
+ for (int ii = 0; ii < m_qmldirs.count(); ++ii) {
+ if (m_qmldirs.at(ii)->url() == url)
+ return m_qmldirs.at(ii);
+ }
+ return 0;
+}
+
+QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url)
+: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None)
+{
+}
+
+QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const
+{
+ return m_pragmas;
+}
+
+QString QDeclarativeScriptData::scriptSource() const
+{
+ return m_source;
+}
+
+void QDeclarativeScriptData::dataReceived(const QByteArray &data)
+{
+ m_source = QString::fromUtf8(data);
+ m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source);
+}
+
+QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
+: QDeclarativeDataBlob(url, QmldirFile)
+{
+}
+
+const QDeclarativeDirComponents &QDeclarativeQmldirData::dirComponents() const
+{
+ return m_components;
+}
+
+void QDeclarativeQmldirData::dataReceived(const QByteArray &data)
+{
+ QDeclarativeDirParser parser;
+ parser.setSource(QString::fromUtf8(data));
+ parser.parse();
+ m_components = parser.components();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
new file mode 100644
index 0000000000..7f487a0e24
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVETYPELOADER_P_H
+#define QDECLARATIVETYPELOADER_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/qobject.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtDeclarative/qdeclarativeerror.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <private/qdeclarativescriptparser_p.h>
+#include <private/qdeclarativedirparser_p.h>
+#include <private/qdeclarativeimport_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeScriptData;
+class QDeclarativeQmldirData;
+class QDeclarativeTypeLoader;
+class QDeclarativeCompiledData;
+class QDeclarativeComponentPrivate;
+class QDeclarativeTypeData;
+class QDeclarativeDataLoader;
+
+class Q_AUTOTEST_EXPORT QDeclarativeDataBlob : public QDeclarativeRefCount
+{
+public:
+ enum Status {
+ Null, // Prior to QDeclarativeDataLoader::load()
+ Loading, // Prior to data being received and dataReceived() being called
+ WaitingForDependencies, // While there are outstanding addDependency()s
+ Complete, // Finished
+ Error // Error
+ };
+
+ enum Type {
+ QmlFile,
+ JavaScriptFile,
+ QmldirFile
+ };
+
+ QDeclarativeDataBlob(const QUrl &, Type);
+ virtual ~QDeclarativeDataBlob();
+
+ Type type() const;
+
+ Status status() const;
+ bool isNull() const;
+ bool isLoading() const;
+ bool isWaiting() const;
+ bool isComplete() const;
+ bool isError() const;
+ bool isCompleteOrError() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+ QUrl finalUrl() const;
+
+ QList<QDeclarativeError> errors() const;
+
+ void setError(const QDeclarativeError &);
+ void setError(const QList<QDeclarativeError> &errors);
+
+ void addDependency(QDeclarativeDataBlob *);
+
+protected:
+ virtual void dataReceived(const QByteArray &) = 0;
+
+ virtual void done();
+ virtual void networkError(QNetworkReply::NetworkError);
+
+ virtual void dependencyError(QDeclarativeDataBlob *);
+ virtual void dependencyComplete(QDeclarativeDataBlob *);
+ virtual void allDependenciesDone();
+
+ virtual void downloadProgressChanged(qreal);
+
+private:
+ friend class QDeclarativeDataLoader;
+ void tryDone();
+ void cancelAllWaitingFor();
+ void notifyAllWaitingOnMe();
+ void notifyComplete(QDeclarativeDataBlob *);
+
+ Type m_type;
+ Status m_status;
+ qreal m_progress;
+
+ QUrl m_url;
+ QUrl m_finalUrl;
+
+ // List of QDeclarativeDataBlob's that are waiting for me to complete.
+ QList<QDeclarativeDataBlob *> m_waitingOnMe;
+
+ // List of QDeclarativeDataBlob's that I am waiting for to complete.
+ QList<QDeclarativeDataBlob *> m_waitingFor;
+
+ // Manager that is currently fetching data for me
+ QDeclarativeDataLoader *m_manager;
+ int m_redirectCount:30;
+ bool m_inCallback:1;
+ bool m_isDone:1;
+
+ QList<QDeclarativeError> m_errors;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeDataLoader : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeDataLoader(QDeclarativeEngine *);
+ ~QDeclarativeDataLoader();
+
+ void load(QDeclarativeDataBlob *);
+ void loadWithStaticData(QDeclarativeDataBlob *, const QByteArray &);
+
+ QDeclarativeEngine *engine() const;
+
+private slots:
+ void networkReplyFinished();
+ void networkReplyProgress(qint64,qint64);
+
+private:
+ void setData(QDeclarativeDataBlob *, const QByteArray &);
+
+ QDeclarativeEngine *m_engine;
+ typedef QHash<QNetworkReply *, QDeclarativeDataBlob *> NetworkReplies;
+ NetworkReplies m_networkReplies;
+};
+
+
+class Q_AUTOTEST_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader
+{
+ Q_OBJECT
+public:
+ QDeclarativeTypeLoader(QDeclarativeEngine *);
+ ~QDeclarativeTypeLoader();
+
+ enum Option {
+ None,
+ PreserveParser
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ QDeclarativeTypeData *get(const QUrl &url);
+ QDeclarativeTypeData *get(const QByteArray &, const QUrl &url, Options = None);
+ void clearCache();
+
+ QDeclarativeScriptData *getScript(const QUrl &);
+ QDeclarativeQmldirData *getQmldir(const QUrl &);
+private:
+ typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
+ typedef QHash<QUrl, QDeclarativeScriptData *> ScriptCache;
+ typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache;
+
+ TypeCache m_typeCache;
+ ScriptCache m_scriptCache;
+ QmldirCache m_qmldirCache;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeTypeLoader::Options)
+
+class Q_AUTOTEST_EXPORT QDeclarativeTypeData : public QDeclarativeDataBlob
+{
+public:
+ struct TypeReference
+ {
+ TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
+
+ QDeclarativeParser::Location location;
+ QDeclarativeType *type;
+ int majorVersion;
+ int minorVersion;
+ QDeclarativeTypeData *typeData;
+ };
+
+ struct ScriptReference
+ {
+ ScriptReference() : script(0) {}
+
+ QDeclarativeParser::Location location;
+ QString qualifier;
+ QDeclarativeScriptData *script;
+ };
+
+ QDeclarativeTypeData(const QUrl &, QDeclarativeTypeLoader::Options, QDeclarativeTypeLoader *);
+ ~QDeclarativeTypeData();
+
+ QDeclarativeTypeLoader *typeLoader() const;
+
+ const QDeclarativeImports &imports() const;
+ const QDeclarativeScriptParser &parser() const;
+
+ const QList<TypeReference> &resolvedTypes() const;
+ const QList<ScriptReference> &resolvedScripts() const;
+
+ QDeclarativeCompiledData *compiledData() const;
+
+ // Used by QDeclarativeComponent to get notifications
+ struct TypeDataCallback {
+ ~TypeDataCallback() {}
+ virtual void typeDataProgress(QDeclarativeTypeData *, qreal) {}
+ virtual void typeDataReady(QDeclarativeTypeData *) {}
+ };
+ void registerCallback(TypeDataCallback *);
+ void unregisterCallback(TypeDataCallback *);
+
+protected:
+ virtual void done();
+ virtual void dataReceived(const QByteArray &);
+ virtual void allDependenciesDone();
+ virtual void downloadProgressChanged(qreal);
+
+private:
+ void resolveTypes();
+ void compile();
+
+ QDeclarativeTypeLoader::Options m_options;
+
+ QDeclarativeQmldirData *qmldirForUrl(const QUrl &);
+
+ QDeclarativeScriptParser scriptParser;
+ QDeclarativeImports m_imports;
+
+ QList<ScriptReference> m_scripts;
+ QList<QDeclarativeQmldirData *> m_qmldirs;
+
+ QList<TypeReference> m_types;
+ bool m_typesResolved:1;
+
+ QDeclarativeCompiledData *m_compiledData;
+
+ QList<TypeDataCallback *> m_callbacks;
+
+ QDeclarativeTypeLoader *m_typeLoader;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeDataBlob
+{
+public:
+ QDeclarativeScriptData(const QUrl &);
+
+ QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas() const;
+ QString scriptSource() const;
+
+protected:
+ virtual void dataReceived(const QByteArray &);
+
+private:
+ QDeclarativeParser::Object::ScriptBlock::Pragmas m_pragmas;
+ QString m_source;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeQmldirData : public QDeclarativeDataBlob
+{
+public:
+ QDeclarativeQmldirData(const QUrl &);
+
+ const QDeclarativeDirComponents &dirComponents() const;
+
+protected:
+ virtual void dataReceived(const QByteArray &);
+
+private:
+ QDeclarativeDirComponents m_components;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETYPELOADER_P_H
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
new file mode 100644
index 0000000000..48c72a7fef
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -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 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/qdeclarativetypenamecache_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e)
+: QDeclarativeCleanup(e), engine(e)
+{
+}
+
+QDeclarativeTypeNameCache::~QDeclarativeTypeNameCache()
+{
+ clear();
+}
+
+void QDeclarativeTypeNameCache::clear()
+{
+ qDeleteAll(stringCache);
+ stringCache.clear();
+ identifierCache.clear();
+ engine = 0;
+}
+
+void QDeclarativeTypeNameCache::add(const QString &name, int importedScriptIndex)
+{
+ if (stringCache.contains(name))
+ return;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ RData *data = new RData;
+ // ### Use typename class
+ data->identifier = ep->objectClass->createPersistentIdentifier(name);
+ data->importedScriptIndex = importedScriptIndex;
+ stringCache.insert(name, data);
+ identifierCache.insert(data->identifier.identifier, data);
+}
+
+void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeType *type)
+{
+ if (stringCache.contains(name))
+ return;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ RData *data = new RData;
+ // ### Use typename class
+ data->identifier = ep->objectClass->createPersistentIdentifier(name);
+ data->type = type;
+ stringCache.insert(name, data);
+ identifierCache.insert(data->identifier.identifier, data);
+}
+
+void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeTypeNameCache *typeNamespace)
+{
+ if (stringCache.contains(name))
+ return;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ RData *data = new RData;
+ // ### Use typename class
+ data->identifier = ep->objectClass->createPersistentIdentifier(name);
+ data->typeNamespace = typeNamespace;
+ stringCache.insert(name, data);
+ identifierCache.insert(data->identifier.identifier, data);
+ typeNamespace->addref();
+}
+
+QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &id) const
+{
+ return stringCache.value(id);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
new file mode 100644
index 0000000000..f2562da777
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -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 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 QDECLARATIVETYPENAMECACHE_P_H
+#define QDECLARATIVETYPENAMECACHE_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/qdeclarativerefcount_p.h"
+#include "private/qdeclarativecleanup_p.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeType;
+class QDeclarativeEngine;
+class QDeclarativeTypeNameCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+{
+public:
+ QDeclarativeTypeNameCache(QDeclarativeEngine *);
+ virtual ~QDeclarativeTypeNameCache();
+
+ struct Data {
+ inline Data();
+ inline ~Data();
+ QDeclarativeType *type;
+ QDeclarativeTypeNameCache *typeNamespace;
+ int importedScriptIndex;
+ };
+
+ void add(const QString &, int);
+ void add(const QString &, QDeclarativeType *);
+ void add(const QString &, QDeclarativeTypeNameCache *);
+
+ Data *data(const QString &) const;
+ inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+
+protected:
+ virtual void clear();
+
+private:
+ struct RData : public Data {
+ QScriptDeclarativeClass::PersistentIdentifier identifier;
+ };
+ typedef QHash<QString, RData *> StringCache;
+ typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+
+ StringCache stringCache;
+ IdentifierCache identifierCache;
+ QDeclarativeEngine *engine;
+};
+
+QDeclarativeTypeNameCache::Data::Data()
+: type(0), typeNamespace(0), importedScriptIndex(-1)
+{
+}
+
+QDeclarativeTypeNameCache::Data::~Data()
+{
+ if (typeNamespace) typeNamespace->release();
+}
+
+QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const
+{
+ return identifierCache.value(id);
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETYPENAMECACHE_P_H
+
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
new file mode 100644
index 0000000000..a7c0b2cfbe
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetypenamescriptclass_p.h"
+
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativetypenamecache_p.h"
+
+QT_BEGIN_NAMESPACE
+
+struct TypeNameData : public QScriptDeclarativeClass::Object {
+ TypeNameData(QObject *o, QDeclarativeType *t, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {}
+ TypeNameData(QObject *o, QDeclarativeTypeNameCache *n, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) {
+ if (typeNamespace) typeNamespace->addref();
+ }
+ ~TypeNameData() {
+ if (typeNamespace) typeNamespace->release();
+ }
+
+ QObject *object;
+ QDeclarativeType *type;
+ QDeclarativeTypeNameCache *typeNamespace;
+ QDeclarativeTypeNameScriptClass::TypeNameMode mode;
+};
+
+QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
+ engine(bindEngine), object(0), type(0)
+{
+}
+
+QDeclarativeTypeNameScriptClass::~QDeclarativeTypeNameScriptClass()
+{
+}
+
+QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeType *type, TypeNameMode mode)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode));
+}
+
+QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeTypeNameCache *ns, TypeNameMode mode)
+{
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode));
+}
+
+QScriptClass::QueryFlags
+QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name,
+ QScriptClass::QueryFlags flags)
+{
+ Q_UNUSED(flags);
+
+ TypeNameData *data = (TypeNameData *)obj;
+
+ object = 0;
+ type = 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 {
+ return 0;
+ }
+
+ } else if (data->type) {
+
+ if (startsWithUpper(name)) {
+ QString strName = toString(name);
+ // Must be an enum
+ if (data->mode == IncludeEnums) {
+ // ### Optimize
+ QByteArray enumName = strName.toUtf8();
+ const QMetaObject *metaObject = data->type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ int value = e.keyToValue(enumName.constData());
+ if (value != -1) {
+ enumValue = value;
+ return QScriptClass::HandlesReadAccess;
+ }
+ }
+ }
+ return 0;
+ } else if (data->object) {
+ // Must be an attached property
+ object = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), data->object);
+ if (!object) return 0;
+ return ep->objectClass->queryProperty(object, name, flags, 0);
+ }
+
+ }
+
+ return 0;
+}
+
+QDeclarativeTypeNameScriptClass::Value
+QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
+{
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ if (type) {
+ return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
+ } else if (object) {
+ return ep->objectClass->property(object, name);
+ } else {
+ return Value(scriptEngine, enumValue);
+ }
+}
+
+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());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
new file mode 100644
index 0000000000..cf7dbc8480
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass_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 QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+#define QDECLARATIVETYPENAMESCRIPTCLASS_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/qdeclarativeengine_p.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+#include <QtScript/qscriptclass.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeType;
+class QDeclarativeTypeNameCache;
+class QDeclarativeTypeNameScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeTypeNameScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeTypeNameScriptClass();
+
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
+ QScriptValue newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums);
+ QScriptValue newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums);
+
+protected:
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+
+ virtual Value property(Object *, const Identifier &);
+ virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+
+private:
+ QDeclarativeEngine *engine;
+ QObject *object;
+ QDeclarativeType *type;
+ quint32 enumValue;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+
diff --git a/src/declarative/qml/qdeclarativetypenotavailable.cpp b/src/declarative/qml/qdeclarativetypenotavailable.cpp
new file mode 100644
index 0000000000..9b79d70afd
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenotavailable.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** 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 "qdeclarativetypenotavailable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
+{
+ return qmlRegisterUncreatableType<QDeclarativeTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message);
+}
+
+QDeclarativeTypeNotAvailable::QDeclarativeTypeNotAvailable() { }
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenotavailable_p.h b/src/declarative/qml/qdeclarativetypenotavailable_p.h
new file mode 100644
index 0000000000..69408e4162
--- /dev/null
+++ b/src/declarative/qml/qdeclarativetypenotavailable_p.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 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 QDECLARATIVETYPENOTAVAILABLE_H
+#define QDECLARATIVETYPENOTAVAILABLE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeTypeNotAvailable : public QObject {
+ Q_OBJECT
+public:
+ QDeclarativeTypeNotAvailable();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTypeNotAvailable)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVETYPENOTAVAILABLE_H
diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp
new file mode 100644
index 0000000000..5b83b4e7a0
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevaluetype.cpp
@@ -0,0 +1,1011 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativevaluetype_p.h"
+
+#include "private/qdeclarativemetatype_p.h"
+#include "private/qfont_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QByteArray name(T::staticMetaObject.className());
+
+ QByteArray pointerName(name + '*');
+
+ QDeclarativePrivate::RegisterType type = {
+ 0,
+
+ qRegisterMetaType<T *>(pointerName.constData()), 0, 0, 0,
+
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ 0, 0,
+
+ 0, 0, 0,
+
+ 0, 0,
+
+ 0,
+ 0
+ };
+
+ return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type);
+}
+
+QDeclarativeValueTypeFactory::QDeclarativeValueTypeFactory()
+{
+ // ### Optimize
+ for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ valueTypes[ii] = valueType(ii);
+}
+
+QDeclarativeValueTypeFactory::~QDeclarativeValueTypeFactory()
+{
+ for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii)
+ delete valueTypes[ii];
+}
+
+bool QDeclarativeValueTypeFactory::isValueType(int idx)
+{
+ if ((uint)idx < QVariant::UserType)
+ return true;
+ return false;
+}
+
+void QDeclarativeValueTypeFactory::registerValueTypes()
+{
+ qmlRegisterValueTypeEnums<QDeclarativeEasingValueType>("QtQuick",1,0,"Easing");
+ qmlRegisterValueTypeEnums<QDeclarativeFontValueType>("QtQuick",1,0,"Font");
+#ifndef QT_NO_IMPORT_QT47_QML
+ qmlRegisterValueTypeEnums<QDeclarativeEasingValueType>("Qt",4,7,"Easing");
+ qmlRegisterValueTypeEnums<QDeclarativeFontValueType>("Qt",4,7,"Font");
+#endif
+}
+
+QDeclarativeValueType *QDeclarativeValueTypeFactory::valueType(int t)
+{
+ QDeclarativeValueType *rv = 0;
+
+ switch (t) {
+ case QVariant::Point:
+ rv = new QDeclarativePointValueType;
+ break;
+ case QVariant::PointF:
+ rv = new QDeclarativePointFValueType;
+ break;
+ case QVariant::Size:
+ rv = new QDeclarativeSizeValueType;
+ break;
+ case QVariant::SizeF:
+ rv = new QDeclarativeSizeFValueType;
+ break;
+ case QVariant::Rect:
+ rv = new QDeclarativeRectValueType;
+ break;
+ case QVariant::RectF:
+ rv = new QDeclarativeRectFValueType;
+ break;
+ case QVariant::Vector2D:
+ rv = new QDeclarativeVector2DValueType;
+ break;
+ case QVariant::Vector3D:
+ rv = new QDeclarativeVector3DValueType;
+ break;
+ case QVariant::Vector4D:
+ rv = new QDeclarativeVector4DValueType;
+ break;
+ case QVariant::Quaternion:
+ rv = new QDeclarativeQuaternionValueType;
+ break;
+ case QVariant::Matrix4x4:
+ rv = new QDeclarativeMatrix4x4ValueType;
+ break;
+ case QVariant::EasingCurve:
+ rv = new QDeclarativeEasingValueType;
+ break;
+ case QVariant::Font:
+ rv = new QDeclarativeFontValueType;
+ break;
+ default:
+ break;
+ }
+
+ Q_ASSERT(!rv || rv->metaObject()->propertyCount() < 32);
+ return rv;
+}
+
+QDeclarativeValueType::QDeclarativeValueType(QObject *parent)
+: QObject(parent)
+{
+}
+
+QDeclarativePointFValueType::QDeclarativePointFValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativePointFValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &point, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativePointFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &point, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativePointFValueType::value()
+{
+ return QVariant(point);
+}
+
+void QDeclarativePointFValueType::setValue(QVariant value)
+{
+ point = qvariant_cast<QPointF>(value);
+}
+
+qreal QDeclarativePointFValueType::x() const
+{
+ return point.x();
+}
+
+qreal QDeclarativePointFValueType::y() const
+{
+ return point.y();
+}
+
+void QDeclarativePointFValueType::setX(qreal x)
+{
+ point.setX(x);
+}
+
+void QDeclarativePointFValueType::setY(qreal y)
+{
+ point.setY(y);
+}
+
+QDeclarativePointValueType::QDeclarativePointValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativePointValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &point, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativePointValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &point, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativePointValueType::value()
+{
+ return QVariant(point);
+}
+
+void QDeclarativePointValueType::setValue(QVariant value)
+{
+ point = qvariant_cast<QPoint>(value);
+}
+
+int QDeclarativePointValueType::x() const
+{
+ return point.x();
+}
+
+int QDeclarativePointValueType::y() const
+{
+ return point.y();
+}
+
+void QDeclarativePointValueType::setX(int x)
+{
+ point.setX(x);
+}
+
+void QDeclarativePointValueType::setY(int y)
+{
+ point.setY(y);
+}
+
+QDeclarativeSizeFValueType::QDeclarativeSizeFValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeSizeFValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &size, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeSizeFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &size, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeSizeFValueType::value()
+{
+ return QVariant(size);
+}
+
+void QDeclarativeSizeFValueType::setValue(QVariant value)
+{
+ size = qvariant_cast<QSizeF>(value);
+}
+
+qreal QDeclarativeSizeFValueType::width() const
+{
+ return size.width();
+}
+
+qreal QDeclarativeSizeFValueType::height() const
+{
+ return size.height();
+}
+
+void QDeclarativeSizeFValueType::setWidth(qreal w)
+{
+ size.setWidth(w);
+}
+
+void QDeclarativeSizeFValueType::setHeight(qreal h)
+{
+ size.setHeight(h);
+}
+
+QDeclarativeSizeValueType::QDeclarativeSizeValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeSizeValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &size, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeSizeValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &size, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeSizeValueType::value()
+{
+ return QVariant(size);
+}
+
+void QDeclarativeSizeValueType::setValue(QVariant value)
+{
+ size = qvariant_cast<QSize>(value);
+}
+
+int QDeclarativeSizeValueType::width() const
+{
+ return size.width();
+}
+
+int QDeclarativeSizeValueType::height() const
+{
+ return size.height();
+}
+
+void QDeclarativeSizeValueType::setWidth(int w)
+{
+ size.setWidth(w);
+}
+
+void QDeclarativeSizeValueType::setHeight(int h)
+{
+ size.setHeight(h);
+}
+
+QDeclarativeRectFValueType::QDeclarativeRectFValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeRectFValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &rect, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeRectFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &rect, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeRectFValueType::value()
+{
+ return QVariant(rect);
+}
+
+void QDeclarativeRectFValueType::setValue(QVariant value)
+{
+ rect = qvariant_cast<QRectF>(value);
+}
+
+qreal QDeclarativeRectFValueType::x() const
+{
+ return rect.x();
+}
+
+qreal QDeclarativeRectFValueType::y() const
+{
+ return rect.y();
+}
+
+void QDeclarativeRectFValueType::setX(qreal x)
+{
+ rect.moveLeft(x);
+}
+
+void QDeclarativeRectFValueType::setY(qreal y)
+{
+ rect.moveTop(y);
+}
+
+qreal QDeclarativeRectFValueType::width() const
+{
+ return rect.width();
+}
+
+qreal QDeclarativeRectFValueType::height() const
+{
+ return rect.height();
+}
+
+void QDeclarativeRectFValueType::setWidth(qreal w)
+{
+ rect.setWidth(w);
+}
+
+void QDeclarativeRectFValueType::setHeight(qreal h)
+{
+ rect.setHeight(h);
+}
+
+QDeclarativeRectValueType::QDeclarativeRectValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeRectValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &rect, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeRectValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &rect, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeRectValueType::value()
+{
+ return QVariant(rect);
+}
+
+void QDeclarativeRectValueType::setValue(QVariant value)
+{
+ rect = qvariant_cast<QRect>(value);
+}
+
+int QDeclarativeRectValueType::x() const
+{
+ return rect.x();
+}
+
+int QDeclarativeRectValueType::y() const
+{
+ return rect.y();
+}
+
+void QDeclarativeRectValueType::setX(int x)
+{
+ rect.moveLeft(x);
+}
+
+void QDeclarativeRectValueType::setY(int y)
+{
+ rect.moveTop(y);
+}
+
+int QDeclarativeRectValueType::width() const
+{
+ return rect.width();
+}
+
+int QDeclarativeRectValueType::height() const
+{
+ return rect.height();
+}
+
+void QDeclarativeRectValueType::setWidth(int w)
+{
+ rect.setWidth(w);
+}
+
+void QDeclarativeRectValueType::setHeight(int h)
+{
+ rect.setHeight(h);
+}
+
+QDeclarativeVector2DValueType::QDeclarativeVector2DValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeVector2DValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &vector, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeVector2DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &vector, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeVector2DValueType::value()
+{
+ return QVariant(vector);
+}
+
+void QDeclarativeVector2DValueType::setValue(QVariant value)
+{
+ vector = qvariant_cast<QVector2D>(value);
+}
+
+qreal QDeclarativeVector2DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QDeclarativeVector2DValueType::y() const
+{
+ return vector.y();
+}
+
+void QDeclarativeVector2DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QDeclarativeVector2DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+QDeclarativeVector3DValueType::QDeclarativeVector3DValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeVector3DValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &vector, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeVector3DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &vector, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeVector3DValueType::value()
+{
+ return QVariant(vector);
+}
+
+void QDeclarativeVector3DValueType::setValue(QVariant value)
+{
+ vector = qvariant_cast<QVector3D>(value);
+}
+
+qreal QDeclarativeVector3DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QDeclarativeVector3DValueType::y() const
+{
+ return vector.y();
+}
+
+qreal QDeclarativeVector3DValueType::z() const
+{
+ return vector.z();
+}
+
+void QDeclarativeVector3DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QDeclarativeVector3DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+void QDeclarativeVector3DValueType::setZ(qreal z)
+{
+ vector.setZ(z);
+}
+
+QDeclarativeVector4DValueType::QDeclarativeVector4DValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeVector4DValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &vector, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeVector4DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &vector, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeVector4DValueType::value()
+{
+ return QVariant(vector);
+}
+
+void QDeclarativeVector4DValueType::setValue(QVariant value)
+{
+ vector = qvariant_cast<QVector4D>(value);
+}
+
+qreal QDeclarativeVector4DValueType::x() const
+{
+ return vector.x();
+}
+
+qreal QDeclarativeVector4DValueType::y() const
+{
+ return vector.y();
+}
+
+qreal QDeclarativeVector4DValueType::z() const
+{
+ return vector.z();
+}
+
+qreal QDeclarativeVector4DValueType::w() const
+{
+ return vector.w();
+}
+
+void QDeclarativeVector4DValueType::setX(qreal x)
+{
+ vector.setX(x);
+}
+
+void QDeclarativeVector4DValueType::setY(qreal y)
+{
+ vector.setY(y);
+}
+
+void QDeclarativeVector4DValueType::setZ(qreal z)
+{
+ vector.setZ(z);
+}
+
+void QDeclarativeVector4DValueType::setW(qreal w)
+{
+ vector.setW(w);
+}
+
+QDeclarativeQuaternionValueType::QDeclarativeQuaternionValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeQuaternionValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &quaternion, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeQuaternionValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &quaternion, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeQuaternionValueType::value()
+{
+ return QVariant(quaternion);
+}
+
+void QDeclarativeQuaternionValueType::setValue(QVariant value)
+{
+ quaternion = qvariant_cast<QQuaternion>(value);
+}
+
+qreal QDeclarativeQuaternionValueType::scalar() const
+{
+ return quaternion.scalar();
+}
+
+qreal QDeclarativeQuaternionValueType::x() const
+{
+ return quaternion.x();
+}
+
+qreal QDeclarativeQuaternionValueType::y() const
+{
+ return quaternion.y();
+}
+
+qreal QDeclarativeQuaternionValueType::z() const
+{
+ return quaternion.z();
+}
+
+void QDeclarativeQuaternionValueType::setScalar(qreal scalar)
+{
+ quaternion.setScalar(scalar);
+}
+
+void QDeclarativeQuaternionValueType::setX(qreal x)
+{
+ quaternion.setX(x);
+}
+
+void QDeclarativeQuaternionValueType::setY(qreal y)
+{
+ quaternion.setY(y);
+}
+
+void QDeclarativeQuaternionValueType::setZ(qreal z)
+{
+ quaternion.setZ(z);
+}
+
+QDeclarativeMatrix4x4ValueType::QDeclarativeMatrix4x4ValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeMatrix4x4ValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &matrix, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeMatrix4x4ValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &matrix, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeMatrix4x4ValueType::value()
+{
+ return QVariant(matrix);
+}
+
+void QDeclarativeMatrix4x4ValueType::setValue(QVariant value)
+{
+ matrix = qvariant_cast<QMatrix4x4>(value);
+}
+
+QDeclarativeEasingValueType::QDeclarativeEasingValueType(QObject *parent)
+: QDeclarativeValueType(parent)
+{
+}
+
+void QDeclarativeEasingValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &easing, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+}
+
+void QDeclarativeEasingValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &easing, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeEasingValueType::value()
+{
+ return QVariant(easing);
+}
+
+void QDeclarativeEasingValueType::setValue(QVariant value)
+{
+ easing = qvariant_cast<QEasingCurve>(value);
+}
+
+QDeclarativeEasingValueType::Type QDeclarativeEasingValueType::type() const
+{
+ return (QDeclarativeEasingValueType::Type)easing.type();
+}
+
+qreal QDeclarativeEasingValueType::amplitude() const
+{
+ return easing.amplitude();
+}
+
+qreal QDeclarativeEasingValueType::overshoot() const
+{
+ return easing.overshoot();
+}
+
+qreal QDeclarativeEasingValueType::period() const
+{
+ return easing.period();
+}
+
+void QDeclarativeEasingValueType::setType(QDeclarativeEasingValueType::Type type)
+{
+ easing.setType((QEasingCurve::Type)type);
+}
+
+void QDeclarativeEasingValueType::setAmplitude(qreal amplitude)
+{
+ easing.setAmplitude(amplitude);
+}
+
+void QDeclarativeEasingValueType::setOvershoot(qreal overshoot)
+{
+ easing.setOvershoot(overshoot);
+}
+
+void QDeclarativeEasingValueType::setPeriod(qreal period)
+{
+ easing.setPeriod(period);
+}
+
+QDeclarativeFontValueType::QDeclarativeFontValueType(QObject *parent)
+: QDeclarativeValueType(parent), pixelSizeSet(false), pointSizeSet(false)
+{
+}
+
+void QDeclarativeFontValueType::read(QObject *obj, int idx)
+{
+ void *a[] = { &font, 0 };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+ pixelSizeSet = false;
+ pointSizeSet = false;
+}
+
+void QDeclarativeFontValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags)
+{
+ int status = -1;
+ void *a[] = { &font, 0, &status, &flags };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+}
+
+QVariant QDeclarativeFontValueType::value()
+{
+ return QVariant(font);
+}
+
+void QDeclarativeFontValueType::setValue(QVariant value)
+{
+ font = qvariant_cast<QFont>(value);
+}
+
+
+QString QDeclarativeFontValueType::family() const
+{
+ return font.family();
+}
+
+void QDeclarativeFontValueType::setFamily(const QString &family)
+{
+ font.setFamily(family);
+}
+
+bool QDeclarativeFontValueType::bold() const
+{
+ return font.bold();
+}
+
+void QDeclarativeFontValueType::setBold(bool b)
+{
+ font.setBold(b);
+}
+
+QDeclarativeFontValueType::FontWeight QDeclarativeFontValueType::weight() const
+{
+ return (QDeclarativeFontValueType::FontWeight)font.weight();
+}
+
+void QDeclarativeFontValueType::setWeight(QDeclarativeFontValueType::FontWeight w)
+{
+ font.setWeight((QFont::Weight)w);
+}
+
+bool QDeclarativeFontValueType::italic() const
+{
+ return font.italic();
+}
+
+void QDeclarativeFontValueType::setItalic(bool b)
+{
+ font.setItalic(b);
+}
+
+bool QDeclarativeFontValueType::underline() const
+{
+ return font.underline();
+}
+
+void QDeclarativeFontValueType::setUnderline(bool b)
+{
+ font.setUnderline(b);
+}
+
+bool QDeclarativeFontValueType::overline() const
+{
+ return font.overline();
+}
+
+void QDeclarativeFontValueType::setOverline(bool b)
+{
+ font.setOverline(b);
+}
+
+bool QDeclarativeFontValueType::strikeout() const
+{
+ return font.strikeOut();
+}
+
+void QDeclarativeFontValueType::setStrikeout(bool b)
+{
+ font.setStrikeOut(b);
+}
+
+qreal QDeclarativeFontValueType::pointSize() const
+{
+ if (font.pointSizeF() == -1) {
+ if (dpi.isNull)
+ dpi = qt_defaultDpi();
+ return font.pixelSize() * qreal(72.) / qreal(dpi);
+ }
+ return font.pointSizeF();
+}
+
+void QDeclarativeFontValueType::setPointSize(qreal size)
+{
+ if (pixelSizeSet) {
+ qWarning() << "Both point size and pixel size set. Using pixel size.";
+ return;
+ }
+
+ if (size >= 0.0) {
+ pointSizeSet = true;
+ font.setPointSizeF(size);
+ } else {
+ pointSizeSet = false;
+ }
+}
+
+int QDeclarativeFontValueType::pixelSize() const
+{
+ if (font.pixelSize() == -1) {
+ if (dpi.isNull)
+ dpi = qt_defaultDpi();
+ return (font.pointSizeF() * dpi) / qreal(72.);
+ }
+ return font.pixelSize();
+}
+
+void QDeclarativeFontValueType::setPixelSize(int size)
+{
+ if (size >0) {
+ if (pointSizeSet)
+ qWarning() << "Both point size and pixel size set. Using pixel size.";
+ font.setPixelSize(size);
+ pixelSizeSet = true;
+ } else {
+ pixelSizeSet = false;
+ }
+}
+
+QDeclarativeFontValueType::Capitalization QDeclarativeFontValueType::capitalization() const
+{
+ return (QDeclarativeFontValueType::Capitalization)font.capitalization();
+}
+
+void QDeclarativeFontValueType::setCapitalization(QDeclarativeFontValueType::Capitalization c)
+{
+ font.setCapitalization((QFont::Capitalization)c);
+}
+
+qreal QDeclarativeFontValueType::letterSpacing() const
+{
+ return font.letterSpacing();
+}
+
+void QDeclarativeFontValueType::setLetterSpacing(qreal size)
+{
+ font.setLetterSpacing(QFont::AbsoluteSpacing, size);
+}
+
+qreal QDeclarativeFontValueType::wordSpacing() const
+{
+ return font.wordSpacing();
+}
+
+void QDeclarativeFontValueType::setWordSpacing(qreal size)
+{
+ font.setWordSpacing(size);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevaluetype_p.h b/src/declarative/qml/qdeclarativevaluetype_p.h
new file mode 100644
index 0000000000..3dee8a197b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevaluetype_p.h
@@ -0,0 +1,556 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEVALUETYPE_P_H
+#define QDECLARATIVEVALUETYPE_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 "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativenullablevalue_p_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeValueType : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeValueType(QObject *parent = 0);
+ virtual void read(QObject *, int) = 0;
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags flags) = 0;
+ virtual QVariant value() = 0;
+ virtual void setValue(QVariant) = 0;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeValueTypeFactory
+{
+public:
+ QDeclarativeValueTypeFactory();
+ ~QDeclarativeValueTypeFactory();
+ static bool isValueType(int);
+ static QDeclarativeValueType *valueType(int);
+
+ static void registerValueTypes();
+
+ QDeclarativeValueType *operator[](int idx) const {
+ if (idx >= (int)QVariant::UserType) return 0;
+ else return valueTypes[idx];
+ }
+
+private:
+ QDeclarativeValueType *valueTypes[QVariant::UserType - 1];
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePointFValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QDeclarativePointFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+private:
+ QPointF point;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePointValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(int x READ x WRITE setX)
+ Q_PROPERTY(int y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QDeclarativePointValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ int x() const;
+ int y() const;
+ void setX(int);
+ void setY(int);
+
+private:
+ QPoint point;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeSizeFValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+ Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QDeclarativeSizeFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal width() const;
+ qreal height() const;
+ void setWidth(qreal);
+ void setHeight(qreal);
+
+private:
+ QSizeF size;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeSizeValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(int width READ width WRITE setWidth)
+ Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QDeclarativeSizeValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ int width() const;
+ int height() const;
+ void setWidth(int);
+ void setHeight(int);
+
+private:
+ QSize size;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeRectFValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+ Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QDeclarativeRectFValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+ qreal width() const;
+ qreal height() const;
+ void setWidth(qreal);
+ void setHeight(qreal);
+
+private:
+ QRectF rect;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeRectValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(int x READ x WRITE setX)
+ Q_PROPERTY(int y READ y WRITE setY)
+ Q_PROPERTY(int width READ width WRITE setWidth)
+ Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_OBJECT
+public:
+ QDeclarativeRectValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ int x() const;
+ int y() const;
+ void setX(int);
+ void setY(int);
+
+ int width() const;
+ int height() const;
+ void setWidth(int);
+ void setHeight(int);
+
+private:
+ QRect rect;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeVector2DValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_OBJECT
+public:
+ QDeclarativeVector2DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal x() const;
+ qreal y() const;
+ void setX(qreal);
+ void setY(qreal);
+
+private:
+ QVector2D vector;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeVector3DValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_OBJECT
+public:
+ QDeclarativeVector3DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+
+private:
+ QVector3D vector;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeVector4DValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_PROPERTY(qreal w READ w WRITE setW)
+ Q_OBJECT
+public:
+ QDeclarativeVector4DValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ qreal w() const;
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+ void setW(qreal);
+
+private:
+ QVector4D vector;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeQuaternionValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal scalar READ scalar WRITE setScalar)
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_OBJECT
+public:
+ QDeclarativeQuaternionValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal scalar() const;
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ void setScalar(qreal);
+ void setX(qreal);
+ void setY(qreal);
+ void setZ(qreal);
+
+private:
+ QQuaternion quaternion;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeMatrix4x4ValueType : public QDeclarativeValueType
+{
+ Q_PROPERTY(qreal m11 READ m11 WRITE setM11)
+ Q_PROPERTY(qreal m12 READ m12 WRITE setM12)
+ Q_PROPERTY(qreal m13 READ m13 WRITE setM13)
+ Q_PROPERTY(qreal m14 READ m14 WRITE setM14)
+ Q_PROPERTY(qreal m21 READ m21 WRITE setM21)
+ Q_PROPERTY(qreal m22 READ m22 WRITE setM22)
+ Q_PROPERTY(qreal m23 READ m23 WRITE setM23)
+ Q_PROPERTY(qreal m24 READ m24 WRITE setM24)
+ Q_PROPERTY(qreal m31 READ m31 WRITE setM31)
+ Q_PROPERTY(qreal m32 READ m32 WRITE setM32)
+ Q_PROPERTY(qreal m33 READ m33 WRITE setM33)
+ Q_PROPERTY(qreal m34 READ m34 WRITE setM34)
+ Q_PROPERTY(qreal m41 READ m41 WRITE setM41)
+ Q_PROPERTY(qreal m42 READ m42 WRITE setM42)
+ Q_PROPERTY(qreal m43 READ m43 WRITE setM43)
+ Q_PROPERTY(qreal m44 READ m44 WRITE setM44)
+ Q_OBJECT
+public:
+ QDeclarativeMatrix4x4ValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ qreal m11() const { return matrix(0, 0); }
+ qreal m12() const { return matrix(0, 1); }
+ qreal m13() const { return matrix(0, 2); }
+ qreal m14() const { return matrix(0, 3); }
+ qreal m21() const { return matrix(1, 0); }
+ qreal m22() const { return matrix(1, 1); }
+ qreal m23() const { return matrix(1, 2); }
+ qreal m24() const { return matrix(1, 3); }
+ qreal m31() const { return matrix(2, 0); }
+ qreal m32() const { return matrix(2, 1); }
+ qreal m33() const { return matrix(2, 2); }
+ qreal m34() const { return matrix(2, 3); }
+ qreal m41() const { return matrix(3, 0); }
+ qreal m42() const { return matrix(3, 1); }
+ qreal m43() const { return matrix(3, 2); }
+ qreal m44() const { return matrix(3, 3); }
+
+ void setM11(qreal value) { matrix(0, 0) = value; }
+ void setM12(qreal value) { matrix(0, 1) = value; }
+ void setM13(qreal value) { matrix(0, 2) = value; }
+ void setM14(qreal value) { matrix(0, 3) = value; }
+ void setM21(qreal value) { matrix(1, 0) = value; }
+ void setM22(qreal value) { matrix(1, 1) = value; }
+ void setM23(qreal value) { matrix(1, 2) = value; }
+ void setM24(qreal value) { matrix(1, 3) = value; }
+ void setM31(qreal value) { matrix(2, 0) = value; }
+ void setM32(qreal value) { matrix(2, 1) = value; }
+ void setM33(qreal value) { matrix(2, 2) = value; }
+ void setM34(qreal value) { matrix(2, 3) = value; }
+ void setM41(qreal value) { matrix(3, 0) = value; }
+ void setM42(qreal value) { matrix(3, 1) = value; }
+ void setM43(qreal value) { matrix(3, 2) = value; }
+ void setM44(qreal value) { matrix(3, 3) = value; }
+
+private:
+ QMatrix4x4 matrix;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeEasingValueType : public QDeclarativeValueType
+{
+ Q_OBJECT
+ Q_ENUMS(Type)
+
+ Q_PROPERTY(QDeclarativeEasingValueType::Type type READ type WRITE setType)
+ Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude)
+ Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot)
+ Q_PROPERTY(qreal period READ period WRITE setPeriod)
+public:
+ enum Type {
+ Linear = QEasingCurve::Linear,
+ InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
+ InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
+ InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
+ InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
+ InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
+ InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
+ InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
+ InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
+ InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
+ InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
+ InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
+ InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
+ InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
+ InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
+ InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
+ InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
+ InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
+ InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
+ InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
+ InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
+ InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
+ SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve
+ };
+
+ QDeclarativeEasingValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ Type type() const;
+ qreal amplitude() const;
+ qreal overshoot() const;
+ qreal period() const;
+ void setType(Type);
+ void setAmplitude(qreal);
+ void setOvershoot(qreal);
+ void setPeriod(qreal);
+
+private:
+ QEasingCurve easing;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeFontValueType : public QDeclarativeValueType
+{
+ Q_OBJECT
+ Q_ENUMS(FontWeight)
+ Q_ENUMS(Capitalization)
+
+ Q_PROPERTY(QString family READ family WRITE setFamily)
+ Q_PROPERTY(bool bold READ bold WRITE setBold)
+ Q_PROPERTY(FontWeight weight READ weight WRITE setWeight)
+ Q_PROPERTY(bool italic READ italic WRITE setItalic)
+ Q_PROPERTY(bool underline READ underline WRITE setUnderline)
+ Q_PROPERTY(bool overline READ overline WRITE setOverline)
+ Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout)
+ Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize)
+ Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize)
+ Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization)
+ Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing)
+ Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing)
+
+public:
+ enum FontWeight { Light = QFont::Light,
+ Normal = QFont::Normal,
+ DemiBold = QFont::DemiBold,
+ Bold = QFont::Bold,
+ Black = QFont::Black };
+ enum Capitalization { MixedCase = QFont::MixedCase,
+ AllUppercase = QFont::AllUppercase,
+ AllLowercase = QFont::AllLowercase,
+ SmallCaps = QFont::SmallCaps,
+ Capitalize = QFont::Capitalize };
+
+ QDeclarativeFontValueType(QObject *parent = 0);
+
+ virtual void read(QObject *, int);
+ virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags);
+ virtual QVariant value();
+ virtual void setValue(QVariant value);
+
+ QString family() const;
+ void setFamily(const QString &);
+
+ bool bold() const;
+ void setBold(bool b);
+
+ FontWeight weight() const;
+ void setWeight(FontWeight);
+
+ bool italic() const;
+ void setItalic(bool b);
+
+ bool underline() const;
+ void setUnderline(bool b);
+
+ bool overline() const;
+ void setOverline(bool b);
+
+ bool strikeout() const;
+ void setStrikeout(bool b);
+
+ qreal pointSize() const;
+ void setPointSize(qreal size);
+
+ int pixelSize() const;
+ void setPixelSize(int size);
+
+ Capitalization capitalization() const;
+ void setCapitalization(Capitalization);
+
+ qreal letterSpacing() const;
+ void setLetterSpacing(qreal spacing);
+
+ qreal wordSpacing() const;
+ void setWordSpacing(qreal spacing);
+
+private:
+ QFont font;
+ bool pixelSizeSet;
+ bool pointSizeSet;
+ mutable QDeclarativeNullableValue<int> dpi;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEVALUETYPE_P_H
diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp
new file mode 100644
index 0000000000..4c312b52a8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "private/qdeclarativevaluetypescriptclass_p.h"
+
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeguard_p.h"
+
+#include <QtScript/qscriptcontextinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeValueTypeObject : public QScriptDeclarativeClass::Object {
+ enum Type { Reference, Copy };
+ QDeclarativeValueTypeObject(Type t) : objectType(t) {}
+ Type objectType;
+ QDeclarativeValueType *type;
+};
+
+struct QDeclarativeValueTypeReference : public QDeclarativeValueTypeObject {
+ QDeclarativeValueTypeReference() : QDeclarativeValueTypeObject(Reference) {}
+ QDeclarativeGuard<QObject> object;
+ int property;
+};
+
+struct QDeclarativeValueTypeCopy : public QDeclarativeValueTypeObject {
+ QDeclarativeValueTypeCopy() : QDeclarativeValueTypeObject(Copy) {}
+ QVariant value;
+};
+
+QDeclarativeValueTypeScriptClass::QDeclarativeValueTypeScriptClass(QDeclarativeEngine *bindEngine)
+: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
+{
+}
+
+QDeclarativeValueTypeScriptClass::~QDeclarativeValueTypeScriptClass()
+{
+}
+
+QScriptValue QDeclarativeValueTypeScriptClass::newObject(QObject *object, int coreIndex, QDeclarativeValueType *type)
+{
+ QDeclarativeValueTypeReference *ref = new QDeclarativeValueTypeReference;
+ ref->type = type;
+ ref->object = object;
+ ref->property = coreIndex;
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, ref);
+}
+
+QScriptValue QDeclarativeValueTypeScriptClass::newObject(const QVariant &v, QDeclarativeValueType *type)
+{
+ QDeclarativeValueTypeCopy *copy = new QDeclarativeValueTypeCopy;
+ copy->type = type;
+ copy->value = v;
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return QScriptDeclarativeClass::newObject(scriptEngine, this, copy);
+}
+
+QScriptClass::QueryFlags
+QDeclarativeValueTypeScriptClass::queryProperty(Object *obj, const Identifier &name,
+ QScriptClass::QueryFlags)
+{
+ QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
+
+ m_lastIndex = -1;
+
+ QByteArray propName = toString(name).toUtf8();
+
+ m_lastIndex = o->type->metaObject()->indexOfProperty(propName.constData());
+ if (m_lastIndex == -1)
+ return 0;
+
+ QScriptClass::QueryFlags rv = 0;
+
+ if (o->objectType == QDeclarativeValueTypeObject::Reference) {
+ QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(o);
+
+ if (!ref->object)
+ return 0;
+
+ QMetaProperty prop = ref->object->metaObject()->property(m_lastIndex);
+
+ rv = QScriptClass::HandlesReadAccess;
+ if (prop.isWritable())
+ rv |= QScriptClass::HandlesWriteAccess;
+ } else {
+ rv = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
+ }
+
+ return rv;
+}
+
+QDeclarativeValueTypeScriptClass::Value QDeclarativeValueTypeScriptClass::property(Object *obj, const Identifier &)
+{
+ QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
+
+ QVariant rv;
+ if (o->objectType == QDeclarativeValueTypeObject::Reference) {
+ QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
+
+ QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
+ ref->type->read(ref->object, ref->property);
+ rv = p.read(ref->type);
+ } else {
+ QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
+
+ QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
+ copy->type->setValue(copy->value);
+ rv = p.read(copy->type);
+ }
+
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ return Value(scriptEngine, static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv));
+}
+
+void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier &,
+ const QScriptValue &value)
+{
+ QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
+
+ QVariant v = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value);
+
+ if (o->objectType == QDeclarativeValueTypeObject::Reference) {
+ QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
+
+ ref->type->read(ref->object, ref->property);
+ QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
+
+ QDeclarativeBinding *newBinding = 0;
+ if (value.isFunction() && !value.isRegExp()) {
+ QDeclarativeContextData *ctxt = QDeclarativeEnginePrivate::get(engine)->getContext(context());
+
+ QDeclarativePropertyCache::Data cacheData;
+ cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
+ cacheData.propType = ref->object->metaObject()->property(ref->property).userType();
+ cacheData.coreIndex = ref->property;
+
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+ valueTypeData.valueTypeCoreIdx = m_lastIndex;
+ valueTypeData.valueTypePropType = p.userType();
+
+ newBinding = new QDeclarativeBinding(value, ref->object, ctxt);
+ QScriptContextInfo ctxtInfo(context());
+ newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
+ QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt);
+ newBinding->setTarget(prop);
+ if (newBinding->expression().contains(QLatin1String("this")))
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *delBinding =
+ QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, newBinding);
+ if (delBinding)
+ delBinding->destroy();
+
+ if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ v = v.toInt();
+ p.write(ref->type, v);
+ ref->type->write(ref->object, ref->property, 0);
+
+ } else {
+ QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
+ copy->type->setValue(copy->value);
+ QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
+ p.write(copy->type, v);
+ copy->value = copy->type->value();
+ }
+}
+
+QVariant QDeclarativeValueTypeScriptClass::toVariant(Object *obj, bool *ok)
+{
+ QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
+
+ if (o->objectType == QDeclarativeValueTypeObject::Reference) {
+ QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
+
+ if (ok) *ok = true;
+
+ if (ref->object) {
+ ref->type->read(ref->object, ref->property);
+ return ref->type->value();
+ }
+ } else {
+ QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
+
+ if (ok) *ok = true;
+
+ return copy->value;
+ }
+
+ return QVariant();
+}
+
+QVariant QDeclarativeValueTypeScriptClass::toVariant(const QScriptValue &value)
+{
+ Q_ASSERT(scriptClass(value) == this);
+
+ return toVariant(object(value), 0);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h b/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h
new file mode 100644
index 0000000000..8988c0be6a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h
@@ -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 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 QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+#define QDECLARATIVEVALUETYPESCRIPTCLASS_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/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeValueType;
+class QDeclarativeValueTypeScriptClass : public QScriptDeclarativeClass
+{
+public:
+ QDeclarativeValueTypeScriptClass(QDeclarativeEngine *);
+ ~QDeclarativeValueTypeScriptClass();
+
+ QScriptValue newObject(QObject *object, int coreIndex, QDeclarativeValueType *);
+ QScriptValue newObject(const QVariant &, QDeclarativeValueType *);
+
+ virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
+ QScriptClass::QueryFlags flags);
+ virtual Value property(Object *, const Identifier &);
+ virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+
+ virtual QVariant toVariant(Object *, bool *ok = 0);
+ QVariant toVariant(const QScriptValue &);
+private:
+ QDeclarativeEngine *engine;
+ int m_lastIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
new file mode 100644
index 0000000000..781e1b8ea3
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevme.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 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/qdeclarativevme_p.h"
+
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativeboundsignal_p.h"
+#include "private/qdeclarativestringconverters_p.h"
+#include "private/qmetaobjectbuilder_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "qdeclarative.h"
+#include "private/qdeclarativecustomparser_p.h"
+#include "qdeclarativeengine.h"
+#include "qdeclarativecontext.h"
+#include "qdeclarativecomponent.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecomponent_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativebinding_p_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativecompiledbindings_p.h"
+#include "private/qdeclarativeglobal_p.h"
+#include "qdeclarativescriptstring.h"
+
+#include <QStack>
+#include <QWidget>
+#include <QColor>
+#include <QPointF>
+#include <QSizeF>
+#include <QRectF>
+#include <QtCore/qdebug.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeVME::QDeclarativeVME()
+{
+}
+
+#define VME_EXCEPTION(desc) \
+ { \
+ QDeclarativeError error; \
+ error.setDescription(desc.trimmed()); \
+ error.setLine(instr.line); \
+ error.setUrl(comp->url); \
+ vmeErrors << error; \
+ break; \
+ }
+
+struct ListInstance
+{
+ ListInstance()
+ : type(0) {}
+ ListInstance(int t)
+ : type(t) {}
+
+ int type;
+ QDeclarativeListProperty<void> qListProperty;
+};
+
+QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp,
+ int start, int count, const QBitField &bindingSkipList)
+{
+ QDeclarativeVMEStack<QObject *> stack;
+
+ if (start == -1) start = 0;
+ if (count == -1) count = comp->bytecode.count();
+
+ return run(stack, ctxt, comp, start, count, bindingSkipList);
+}
+
+void QDeclarativeVME::runDeferred(QObject *object)
+{
+ QDeclarativeData *data = QDeclarativeData::get(object);
+
+ if (!data || !data->context || !data->deferredComponent)
+ return;
+
+ QDeclarativeContextData *ctxt = data->context;
+ QDeclarativeCompiledData *comp = data->deferredComponent;
+ int start = data->deferredIdx + 1;
+ int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount;
+ QDeclarativeVMEStack<QObject *> stack;
+ stack.push(object);
+
+ run(stack, ctxt, comp, start, count, QBitField());
+}
+
+inline bool fastHasBinding(QObject *o, int index)
+{
+ QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData);
+
+ return ddata && (ddata->bindingBitsSize > index) &&
+ (ddata->bindingBits[index / 32] & (1 << (index % 32)));
+}
+
+static void removeBindingOnProperty(QObject *o, int index)
+{
+ QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0);
+ if (binding) binding->destroy();
+}
+
+#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index)
+
+QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
+ QDeclarativeContextData *ctxt,
+ QDeclarativeCompiledData *comp,
+ int start, int count,
+ const QBitField &bindingSkipList)
+{
+ Q_ASSERT(comp);
+ Q_ASSERT(ctxt);
+ const QList<QDeclarativeCompiledData::TypeReference> &types = comp->types;
+ const QList<QString> &primitives = comp->primitives;
+ const QList<QByteArray> &datas = comp->datas;
+ const QList<QDeclarativeCompiledData::CustomTypeData> &customTypeData = comp->customTypeData;
+ 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<QUrl> &urls = comp->urls;
+
+ QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues;
+ QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> parserStatus;
+
+ QDeclarativeVMEStack<ListInstance> qliststack;
+
+ vmeErrors.clear();
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+
+ int status = -1; //for dbus
+ QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor |
+ QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite;
+
+ for (int ii = start; !isError() && ii < (start + count); ++ii) {
+ const QDeclarativeInstruction &instr = comp->bytecode.at(ii);
+
+ switch(instr.type) {
+ case QDeclarativeInstruction::Init:
+ {
+ if (instr.init.bindingsSize)
+ bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.init.bindingsSize);
+ if (instr.init.parserStatusSize)
+ parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.init.parserStatusSize);
+ 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);
+ }
+ break;
+
+ case QDeclarativeInstruction::CreateObject:
+ {
+ QBitField bindings;
+ if (instr.create.bindingBits != -1) {
+ const QByteArray &bits = datas.at(instr.create.bindingBits);
+ bindings = QBitField((const quint32*)bits.constData(),
+ bits.size() * 8);
+ }
+ if (stack.isEmpty())
+ bindings = bindings.united(bindingSkipList);
+
+ QObject *o =
+ types.at(instr.create.type).createInstance(ctxt, bindings, &vmeErrors);
+
+ if (!o) {
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.create.type).className)));
+ }
+
+ QDeclarativeData *ddata = QDeclarativeData::get(o);
+ Q_ASSERT(ddata);
+
+ if (stack.isEmpty()) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != ctxt);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != ctxt);
+ QDeclarativeContextData *c = ddata->context;
+ while (c->linkedContext) c = c->linkedContext;
+ c->linkedContext = ctxt;
+ } else {
+ ctxt->addObject(o);
+ }
+
+ ddata->ownContext = true;
+ } else if (!ddata->context) {
+ ctxt->addObject(o);
+ }
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = ctxt;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.create.column;
+
+ if (instr.create.data != -1) {
+ QDeclarativeCustomParser *customParser =
+ types.at(instr.create.type).type->customParser();
+ customParser->setCustomData(o, datas.at(instr.create.data));
+ }
+ if (!stack.isEmpty()) {
+ QObject *parent = stack.top();
+ if (o->isWidgetType()) {
+ QWidget *widget = static_cast<QWidget*>(o);
+ if (parent->isWidgetType()) {
+ QWidget *parentWidget = static_cast<QWidget*>(parent);
+ widget->setParent(parentWidget);
+ } else {
+ // TODO: parent might be a layout
+ }
+ } else {
+ QDeclarative_setParent_noEvent(o, parent);
+ }
+ }
+ stack.push(o);
+ }
+ break;
+
+ case QDeclarativeInstruction::CreateSimpleObject:
+ {
+ QObject *o = (QObject *)operator new(instr.createSimple.typeSize +
+ sizeof(QDeclarativeData));
+ ::memset(o, 0, instr.createSimple.typeSize + sizeof(QDeclarativeData));
+ instr.createSimple.create(o);
+
+ QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.createSimple.typeSize);
+ const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.createSimple.type);
+ if (!ddata->propertyCache && ref.typePropertyCache) {
+ ddata->propertyCache = ref.typePropertyCache;
+ ddata->propertyCache->addref();
+ }
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.createSimple.column;
+
+ QObjectPrivate::get(o)->declarativeData = ddata;
+ ddata->context = ddata->outerContext = ctxt;
+ ddata->nextContextObject = ctxt->contextObjects;
+ if (ddata->nextContextObject)
+ ddata->nextContextObject->prevContextObject = &ddata->nextContextObject;
+ ddata->prevContextObject = &ctxt->contextObjects;
+ ctxt->contextObjects = ddata;
+
+ QObject *parent = stack.top();
+ QDeclarative_setParent_noEvent(o, parent);
+
+ stack.push(o);
+ }
+ break;
+
+ case QDeclarativeInstruction::SetId:
+ {
+ QObject *target = stack.top();
+ ctxt->setIdProperty(instr.setId.index, target);
+ }
+ break;
+
+
+ case QDeclarativeInstruction::SetDefault:
+ {
+ ctxt->contextObject = stack.top();
+ }
+ break;
+
+ case QDeclarativeInstruction::CreateComponent:
+ {
+ QDeclarativeComponent *qcomp =
+ new QDeclarativeComponent(ctxt->engine, comp, ii + 1, instr.createComponent.count,
+ stack.isEmpty() ? 0 : stack.top());
+
+ QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true);
+ Q_ASSERT(ddata);
+
+ ctxt->addObject(qcomp);
+
+ if (stack.isEmpty())
+ ddata->ownContext = true;
+
+ ddata->setImplicitDestructible();
+ ddata->outerContext = ctxt;
+ ddata->lineNumber = instr.line;
+ ddata->columnNumber = instr.create.column;
+
+ QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt;
+
+ stack.push(qcomp);
+ ii += instr.createComponent.count;
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreMetaObject:
+ {
+ QObject *target = stack.top();
+
+ QMetaObject mo;
+ const QByteArray &metadata = datas.at(instr.storeMeta.data);
+ QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata);
+
+ const QDeclarativeVMEMetaData *data =
+ (const QDeclarativeVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData();
+
+ (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp);
+
+ if (instr.storeMeta.propertyCache != -1) {
+ QDeclarativeData *ddata = QDeclarativeData::get(target, true);
+ if (ddata->propertyCache) ddata->propertyCache->release();
+ ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache);
+ ddata->propertyCache->addref();
+ }
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVariant:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
+ // XXX - can be more efficient
+ QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value));
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVariantInteger:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
+ QVariant v(instr.storeInteger.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVariantDouble:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
+ QVariant v(instr.storeDouble.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVariantBool:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
+ QVariant v(instr.storeBool.value);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreString:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
+ void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreUrl:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex);
+
+ void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeUrl.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreFloat:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex);
+
+ float f = instr.storeFloat.value;
+ void *a[] = { &f, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeFloat.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreDouble:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex);
+
+ double d = instr.storeDouble.value;
+ void *a[] = { &d, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeDouble.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreBool:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeBool.propertyIndex);
+
+ void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeBool.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreInteger:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex);
+
+ void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeInteger.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreColor:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeColor.propertyIndex);
+
+ QColor c = QColor::fromRgba(instr.storeColor.value);
+ void *a[] = { &c, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeColor.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreDate:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDate.propertyIndex);
+
+ QDate d = QDate::fromJulianDay(instr.storeDate.value);
+ void *a[] = { &d, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeDate.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreTime:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeTime.propertyIndex);
+
+ QTime t;
+ t.setHMS(intData.at(instr.storeTime.valueIndex),
+ intData.at(instr.storeTime.valueIndex+1),
+ intData.at(instr.storeTime.valueIndex+2),
+ intData.at(instr.storeTime.valueIndex+3));
+ void *a[] = { &t, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeTime.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreDateTime:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex);
+
+ QTime t;
+ t.setHMS(intData.at(instr.storeDateTime.valueIndex+1),
+ intData.at(instr.storeDateTime.valueIndex+2),
+ intData.at(instr.storeDateTime.valueIndex+3),
+ intData.at(instr.storeDateTime.valueIndex+4));
+ QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t);
+ void *a[] = { &dt, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeDateTime.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StorePoint:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
+ QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex),
+ floatData.at(instr.storeRealPair.valueIndex+1)).toPoint();
+ void *a[] = { &p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRealPair.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StorePointF:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
+ QPointF p(floatData.at(instr.storeRealPair.valueIndex),
+ floatData.at(instr.storeRealPair.valueIndex+1));
+ void *a[] = { &p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRealPair.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreSize:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
+ QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex),
+ floatData.at(instr.storeRealPair.valueIndex+1)).toSize();
+ void *a[] = { &p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRealPair.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreSizeF:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
+ QSizeF s(floatData.at(instr.storeRealPair.valueIndex),
+ floatData.at(instr.storeRealPair.valueIndex+1));
+ void *a[] = { &s, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRealPair.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreRect:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
+
+ QRect r = QRectF(floatData.at(instr.storeRect.valueIndex),
+ floatData.at(instr.storeRect.valueIndex+1),
+ floatData.at(instr.storeRect.valueIndex+2),
+ floatData.at(instr.storeRect.valueIndex+3)).toRect();
+ void *a[] = { &r, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRect.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreRectF:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
+
+ QRectF r(floatData.at(instr.storeRect.valueIndex),
+ floatData.at(instr.storeRect.valueIndex+1),
+ floatData.at(instr.storeRect.valueIndex+2),
+ floatData.at(instr.storeRect.valueIndex+3));
+ void *a[] = { &r, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeRect.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVector3D:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex);
+
+ QVector3D p(floatData.at(instr.storeVector3D.valueIndex),
+ floatData.at(instr.storeVector3D.valueIndex+1),
+ floatData.at(instr.storeVector3D.valueIndex+2));
+ void *a[] = { &p, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeVector3D.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreObject:
+ {
+ QObject *assignObj = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
+
+ void *a[] = { (void *)&assignObj, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeObject.propertyIndex, a);
+ }
+ break;
+
+
+ case QDeclarativeInstruction::AssignCustomType:
+ {
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex);
+
+ QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex);
+ const QString &primitive = primitives.at(data.index);
+ QDeclarativeMetaType::StringConverter converter =
+ QDeclarativeMetaType::customStringConverter(data.type);
+ QVariant v = (*converter)(primitive);
+
+ QMetaProperty prop =
+ target->metaObject()->property(instr.assignCustomType.propertyIndex);
+ if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type))
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name())));
+
+ void *a[] = { (void *)v.data(), 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.assignCustomType.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::AssignSignalObject:
+ {
+ // XXX optimize
+
+ QObject *assign = stack.pop();
+ QObject *target = stack.top();
+ int sigIdx = instr.assignSignalObject.signal;
+ const QByteArray &pr = datas.at(sigIdx);
+
+ QDeclarativeProperty prop(target, QString::fromUtf8(pr));
+ if (prop.type() & QDeclarativeProperty::SignalProperty) {
+
+ QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign);
+ if (method.signature() == 0)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())));
+
+ if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature()))
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())));
+
+ QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex());
+
+ } else {
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr)));
+ }
+
+
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreSignal:
+ {
+ QObject *target = stack.top();
+ QObject *context = stack.at(stack.count() - 1 - instr.storeSignal.context);
+
+ QMetaMethod signal = target->metaObject()->method(instr.storeSignal.signalIndex);
+
+ QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target);
+ QDeclarativeExpression *expr =
+ new QDeclarativeExpression(ctxt, context, primitives.at(instr.storeSignal.value));
+ expr->setSourceLocation(comp->name, instr.line);
+ static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.storeSignal.name);
+ bs->setExpression(expr);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreImportedScript:
+ {
+ ctxt->addImportedScript(scripts.at(instr.storeScript.value));
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreScriptString:
+ {
+ QObject *target = stack.top();
+ QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope);
+ QDeclarativeScriptString ss;
+ ss.setContext(ctxt->asQDeclarativeContext());
+ ss.setScopeObject(scope);
+ ss.setScript(primitives.at(instr.storeScriptString.value));
+
+ void *a[] = { &ss, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeScriptString.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::BeginObject:
+ {
+ QObject *target = stack.top();
+ QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue);
+ parserStatus.append(status);
+ status->d = &parserStatus.values[parserStatus.count - 1];
+
+ status->classBegin();
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreBinding:
+ case QDeclarativeInstruction::StoreBindingOnAlias:
+ {
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.assignBinding.owner);
+ QObject *context =
+ stack.at(stack.count() - 1 - instr.assignBinding.context);
+
+ QDeclarativeProperty mp =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.assignBinding.property), target, ctxt);
+
+ int coreIndex = mp.index();
+
+ if ((stack.count() - instr.assignBinding.owner) == 1 && bindingSkipList.testBit(coreIndex))
+ break;
+
+ QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->name, instr.line, 0);
+ bindValues.append(bind);
+ bind->m_mePtr = &bindValues.values[bindValues.count - 1];
+ bind->setTarget(mp);
+
+ if (instr.type == QDeclarativeInstruction::StoreBindingOnAlias) {
+ QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind);
+ if (old) { old->destroy(); }
+ } else {
+ bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp));
+ }
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreCompiledBinding:
+ {
+ QObject *target =
+ stack.at(stack.count() - 1 - instr.assignBinding.owner);
+ QObject *scope =
+ stack.at(stack.count() - 1 - instr.assignBinding.context);
+
+ int property = instr.assignBinding.property;
+ if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF))
+ break;
+
+ QDeclarativeAbstractBinding *binding =
+ ctxt->optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property);
+ bindValues.append(binding);
+ binding->m_mePtr = &bindValues.values[bindValues.count - 1];
+ binding->addToObject(target, property);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreValueSource:
+ {
+ QObject *obj = stack.pop();
+ QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.assignValueSource.castValue);
+ QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner);
+
+ QDeclarativeProperty prop =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueSource.property), target, ctxt);
+ obj->setParent(target);
+ vs->setTarget(prop);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreValueInterceptor:
+ {
+ QObject *obj = stack.pop();
+ QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.assignValueInterceptor.castValue);
+ QObject *target = stack.at(stack.count() - 1 - instr.assignValueInterceptor.owner);
+ QDeclarativeProperty prop =
+ QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueInterceptor.property), target, ctxt);
+ obj->setParent(target);
+ vi->setTarget(prop);
+ QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject());
+ mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreObjectQList:
+ {
+ QObject *assign = stack.pop();
+
+ const ListInstance &list = qliststack.top();
+ list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign);
+ }
+ break;
+
+ case QDeclarativeInstruction::AssignObjectList:
+ {
+ // This is only used for assigning interfaces
+ QObject *assign = stack.pop();
+ const ListInstance &list = qliststack.top();
+
+ int type = list.type;
+
+ void *ptr = 0;
+
+ const char *iid = QDeclarativeMetaType::interfaceIId(type);
+ if (iid)
+ ptr = assign->qt_metacast(iid);
+ if (!ptr)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list"));
+
+
+ list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreVariantObject:
+ {
+ QObject *assign = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
+
+ QVariant v = QVariant::fromValue(assign);
+ void *a[] = { &v, 0, &status, &flags };
+ QMetaObject::metacall(target, QMetaObject::WriteProperty,
+ instr.storeObject.propertyIndex, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::StoreInterface:
+ {
+ QObject *assign = stack.pop();
+ QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
+
+ int coreIdx = instr.storeObject.propertyIndex;
+ QMetaProperty prop = target->metaObject()->property(coreIdx);
+ int t = prop.userType();
+ const char *iid = QDeclarativeMetaType::interfaceIId(t);
+ bool ok = false;
+ if (iid) {
+ void *ptr = assign->qt_metacast(iid);
+ if (ptr) {
+ void *a[] = { &ptr, 0, &status, &flags };
+ QMetaObject::metacall(target,
+ QMetaObject::WriteProperty,
+ coreIdx, a);
+ ok = true;
+ }
+ }
+
+ if (!ok)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property"));
+ }
+ break;
+
+ case QDeclarativeInstruction::FetchAttached:
+ {
+ QObject *target = stack.top();
+
+ QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.fetchAttached.id, target);
+
+ if (!qmlObject)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object"));
+
+ stack.push(qmlObject);
+ }
+ break;
+
+ case QDeclarativeInstruction::FetchQList:
+ {
+ QObject *target = stack.top();
+
+ qliststack.push(ListInstance(instr.fetchQmlList.type));
+
+ void *a[1];
+ a[0] = (void *)&(qliststack.top().qListProperty);
+ QMetaObject::metacall(target, QMetaObject::ReadProperty,
+ instr.fetchQmlList.property, a);
+ }
+ break;
+
+ case QDeclarativeInstruction::FetchObject:
+ {
+ QObject *target = stack.top();
+
+ QObject *obj = 0;
+ // NOTE: This assumes a cast to QObject does not alter the
+ // object pointer
+ void *a[1];
+ a[0] = &obj;
+ QMetaObject::metacall(target, QMetaObject::ReadProperty,
+ instr.fetch.property, a);
+
+ if (!obj)
+ VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.fetch.property).name())));
+
+ stack.push(obj);
+ }
+ break;
+
+ case QDeclarativeInstruction::PopQList:
+ {
+ qliststack.pop();
+ }
+ break;
+
+ case QDeclarativeInstruction::Defer:
+ {
+ if (instr.defer.deferCount) {
+ QObject *target = stack.top();
+ QDeclarativeData *data =
+ QDeclarativeData::get(target, true);
+ comp->addref();
+ data->deferredComponent = comp;
+ data->deferredIdx = ii;
+ ii += instr.defer.deferCount;
+ }
+ }
+ break;
+
+ case QDeclarativeInstruction::PopFetchedObject:
+ {
+ stack.pop();
+ }
+ break;
+
+ case QDeclarativeInstruction::FetchValueType:
+ {
+ QObject *target = stack.top();
+
+ if (instr.fetchValue.bindingSkipList != 0) {
+ // Possibly need to clear bindings
+ QDeclarativeData *targetData = QDeclarativeData::get(target);
+ if (targetData) {
+ QDeclarativeAbstractBinding *binding =
+ QDeclarativePropertyPrivate::binding(target, instr.fetchValue.property, -1);
+
+ if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) {
+ QDeclarativePropertyPrivate::setBinding(target, instr.fetchValue.property, -1, 0);
+ binding->destroy();
+ } else if (binding) {
+ QDeclarativeValueTypeProxyBinding *proxy =
+ static_cast<QDeclarativeValueTypeProxyBinding *>(binding);
+ proxy->removeBindings(instr.fetchValue.bindingSkipList);
+ }
+ }
+ }
+
+ QDeclarativeValueType *valueHandler = ep->valueTypes[instr.fetchValue.type];
+ valueHandler->read(target, instr.fetchValue.property);
+ stack.push(valueHandler);
+ }
+ break;
+
+ case QDeclarativeInstruction::PopValueType:
+ {
+ QDeclarativeValueType *valueHandler =
+ static_cast<QDeclarativeValueType *>(stack.pop());
+ QObject *target = stack.top();
+ valueHandler->write(target, instr.fetchValue.property,
+ QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ break;
+
+ default:
+ qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", instr.type);
+ break;
+ }
+ }
+
+ if (isError()) {
+ if (!stack.isEmpty()) {
+ delete stack.at(0); // ### What about failures in deferred creation?
+ } else {
+ ctxt->destroy();
+ }
+
+ QDeclarativeEnginePrivate::clear(bindValues);
+ QDeclarativeEnginePrivate::clear(parserStatus);
+ return 0;
+ }
+
+ if (bindValues.count)
+ ep->bindValues << bindValues;
+ else if (bindValues.values)
+ bindValues.clear();
+
+ if (parserStatus.count)
+ ep->parserStatus << parserStatus;
+ else if (parserStatus.values)
+ parserStatus.clear();
+
+ Q_ASSERT(stack.count() == 1);
+ return stack.top();
+}
+
+bool QDeclarativeVME::isError() const
+{
+ return !vmeErrors.isEmpty();
+}
+
+QList<QDeclarativeError> QDeclarativeVME::errors() const
+{
+ return vmeErrors;
+}
+
+QObject *
+QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData *ctxt,
+ const QBitField &bindings,
+ QList<QDeclarativeError> *errors) const
+{
+ if (type) {
+ QObject *rv = 0;
+ void *memory = 0;
+
+ type->create(&rv, &memory, sizeof(QDeclarativeData));
+ QDeclarativeData *ddata = new (memory) QDeclarativeData;
+ ddata->ownMemory = false;
+ QObjectPrivate::get(rv)->declarativeData = ddata;
+
+ if (typePropertyCache && !ddata->propertyCache) {
+ ddata->propertyCache = typePropertyCache;
+ ddata->propertyCache->addref();
+ }
+
+ return rv;
+ } else {
+ Q_ASSERT(component);
+ return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, -1, 0, errors, bindings);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
new file mode 100644
index 0000000000..77c016c1a8
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevme_p.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 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 QDECLARATIVEVME_P_H
+#define QDECLARATIVEVME_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 "private/qbitfield_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QStack>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QDeclarativeInstruction;
+class QDeclarativeCompiledData;
+class QDeclarativeCompiledData;
+class QDeclarativeContextData;
+
+template<typename T, int N = 128>
+class QDeclarativeVMEStack {
+public:
+ QDeclarativeVMEStack() : index(-1), maxSize(N), data((T *)fixedData) {}
+ ~QDeclarativeVMEStack() { if (data != (T *)fixedData) qFree(data); }
+
+ bool isEmpty() const { return index == -1; }
+ const T &top() const { return data[index]; }
+ void push(const T &i) { ++index; if (index == maxSize) realloc(); data[index] = i; }
+ const T &pop() { --index; return data[index + 1]; }
+ int count() const { return index + 1; }
+ const T &at(int idx) { return data[idx]; }
+
+private:
+ void realloc() {
+ maxSize += N;
+ if (data != (T *)fixedData) {
+ data = (T*)qRealloc(data, maxSize * sizeof(T));
+ } else {
+ data = (T*)qMalloc(maxSize * sizeof(T));
+ }
+ }
+ int index;
+ int maxSize;
+ T *data;
+ char fixedData[N * sizeof(T)];
+};
+
+class QDeclarativeVME
+{
+public:
+ QDeclarativeVME();
+
+ QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
+ int start = -1, int count = -1,
+ const QBitField & = QBitField());
+ void runDeferred(QObject *);
+
+ bool isError() const;
+ QList<QDeclarativeError> errors() const;
+
+private:
+ QObject *run(QDeclarativeVMEStack<QObject *> &,
+ QDeclarativeContextData *, QDeclarativeCompiledData *,
+ int start, int count,
+ const QBitField &);
+ QList<QDeclarativeError> vmeErrors;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEVME_P_H
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
new file mode 100644
index 0000000000..ad1bf0dd3a
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -0,0 +1,903 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativevmemetaobject_p.h"
+
+#include "qdeclarative.h"
+#include "private/qdeclarativerefcount_p.h"
+#include "qdeclarativeexpression.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativebinding_p.h"
+
+Q_DECLARE_METATYPE(QScriptValue);
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeVMEVariant
+{
+public:
+ inline QDeclarativeVMEVariant();
+ inline ~QDeclarativeVMEVariant();
+
+ inline const void *dataPtr() const;
+ inline void *dataPtr();
+ inline int dataType() const;
+
+ inline QObject *asQObject();
+ inline const QVariant &asQVariant();
+ inline int asInt();
+ inline bool asBool();
+ inline double asDouble();
+ inline const QString &asQString();
+ inline const QUrl &asQUrl();
+ inline const QColor &asQColor();
+ inline const QTime &asQTime();
+ inline const QDate &asQDate();
+ inline const QDateTime &asQDateTime();
+ inline const QScriptValue &asQScriptValue();
+
+ inline void setValue(QObject *);
+ inline void setValue(const QVariant &);
+ inline void setValue(int);
+ inline void setValue(bool);
+ inline void setValue(double);
+ inline void setValue(const QString &);
+ inline void setValue(const QUrl &);
+ inline void setValue(const QColor &);
+ inline void setValue(const QTime &);
+ inline void setValue(const QDate &);
+ inline void setValue(const QDateTime &);
+ inline void setValue(const QScriptValue &);
+private:
+ int type;
+ void *data[4]; // Large enough to hold all types
+
+ inline void cleanup();
+};
+
+QDeclarativeVMEVariant::QDeclarativeVMEVariant()
+: type(QVariant::Invalid)
+{
+}
+
+QDeclarativeVMEVariant::~QDeclarativeVMEVariant()
+{
+ cleanup();
+}
+
+void QDeclarativeVMEVariant::cleanup()
+{
+ if (type == QVariant::Invalid) {
+ } else if (type == QMetaType::Int ||
+ type == QMetaType::Bool ||
+ type == QMetaType::Double) {
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QObjectStar) {
+ ((QDeclarativeGuard<QObject>*)dataPtr())->~QDeclarativeGuard<QObject>();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QString) {
+ ((QString *)dataPtr())->~QString();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QUrl) {
+ ((QUrl *)dataPtr())->~QUrl();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QColor) {
+ ((QColor *)dataPtr())->~QColor();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QTime) {
+ ((QTime *)dataPtr())->~QTime();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QDate) {
+ ((QDate *)dataPtr())->~QDate();
+ type = QVariant::Invalid;
+ } else if (type == QMetaType::QDateTime) {
+ ((QDateTime *)dataPtr())->~QDateTime();
+ type = QVariant::Invalid;
+ } else if (type == qMetaTypeId<QVariant>()) {
+ ((QVariant *)dataPtr())->~QVariant();
+ type = QVariant::Invalid;
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ ((QScriptValue *)dataPtr())->~QScriptValue();
+ type = QVariant::Invalid;
+ }
+
+}
+
+int QDeclarativeVMEVariant::dataType() const
+{
+ return type;
+}
+
+const void *QDeclarativeVMEVariant::dataPtr() const
+{
+ return &data;
+}
+
+void *QDeclarativeVMEVariant::dataPtr()
+{
+ return &data;
+}
+
+QObject *QDeclarativeVMEVariant::asQObject()
+{
+ if (type != QMetaType::QObjectStar)
+ setValue((QObject *)0);
+
+ return *(QDeclarativeGuard<QObject> *)(dataPtr());
+}
+
+const QVariant &QDeclarativeVMEVariant::asQVariant()
+{
+ if (type != QMetaType::QVariant)
+ setValue(QVariant());
+
+ return *(QVariant *)(dataPtr());
+}
+
+int QDeclarativeVMEVariant::asInt()
+{
+ if (type != QMetaType::Int)
+ setValue(int(0));
+
+ return *(int *)(dataPtr());
+}
+
+bool QDeclarativeVMEVariant::asBool()
+{
+ if (type != QMetaType::Bool)
+ setValue(bool(false));
+
+ return *(bool *)(dataPtr());
+}
+
+double QDeclarativeVMEVariant::asDouble()
+{
+ if (type != QMetaType::Double)
+ setValue(double(0));
+
+ return *(double *)(dataPtr());
+}
+
+const QString &QDeclarativeVMEVariant::asQString()
+{
+ if (type != QMetaType::QString)
+ setValue(QString());
+
+ return *(QString *)(dataPtr());
+}
+
+const QUrl &QDeclarativeVMEVariant::asQUrl()
+{
+ if (type != QMetaType::QUrl)
+ setValue(QUrl());
+
+ return *(QUrl *)(dataPtr());
+}
+
+const QColor &QDeclarativeVMEVariant::asQColor()
+{
+ if (type != QMetaType::QColor)
+ setValue(QColor());
+
+ return *(QColor *)(dataPtr());
+}
+
+const QTime &QDeclarativeVMEVariant::asQTime()
+{
+ if (type != QMetaType::QTime)
+ setValue(QTime());
+
+ return *(QTime *)(dataPtr());
+}
+
+const QDate &QDeclarativeVMEVariant::asQDate()
+{
+ if (type != QMetaType::QDate)
+ setValue(QDate());
+
+ return *(QDate *)(dataPtr());
+}
+
+const QDateTime &QDeclarativeVMEVariant::asQDateTime()
+{
+ if (type != QMetaType::QDateTime)
+ setValue(QDateTime());
+
+ return *(QDateTime *)(dataPtr());
+}
+
+const QScriptValue &QDeclarativeVMEVariant::asQScriptValue()
+{
+ if (type != qMetaTypeId<QScriptValue>())
+ setValue(QScriptValue());
+
+ return *(QScriptValue *)(dataPtr());
+}
+
+void QDeclarativeVMEVariant::setValue(QObject *v)
+{
+ if (type != QMetaType::QObjectStar) {
+ cleanup();
+ type = QMetaType::QObjectStar;
+ new (dataPtr()) QDeclarativeGuard<QObject>();
+ }
+ *(QDeclarativeGuard<QObject>*)(dataPtr()) = v;
+}
+
+void QDeclarativeVMEVariant::setValue(const QVariant &v)
+{
+ if (type != qMetaTypeId<QVariant>()) {
+ cleanup();
+ type = qMetaTypeId<QVariant>();
+ new (dataPtr()) QVariant(v);
+ } else {
+ *(QVariant *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(int v)
+{
+ if (type != QMetaType::Int) {
+ cleanup();
+ type = QMetaType::Int;
+ }
+ *(int *)(dataPtr()) = v;
+}
+
+void QDeclarativeVMEVariant::setValue(bool v)
+{
+ if (type != QMetaType::Bool) {
+ cleanup();
+ type = QMetaType::Bool;
+ }
+ *(bool *)(dataPtr()) = v;
+}
+
+void QDeclarativeVMEVariant::setValue(double v)
+{
+ if (type != QMetaType::Double) {
+ cleanup();
+ type = QMetaType::Double;
+ }
+ *(double *)(dataPtr()) = v;
+}
+
+void QDeclarativeVMEVariant::setValue(const QString &v)
+{
+ if (type != QMetaType::QString) {
+ cleanup();
+ type = QMetaType::QString;
+ new (dataPtr()) QString(v);
+ } else {
+ *(QString *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QUrl &v)
+{
+ if (type != QMetaType::QUrl) {
+ cleanup();
+ type = QMetaType::QUrl;
+ new (dataPtr()) QUrl(v);
+ } else {
+ *(QUrl *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QColor &v)
+{
+ if (type != QMetaType::QColor) {
+ cleanup();
+ type = QMetaType::QColor;
+ new (dataPtr()) QColor(v);
+ } else {
+ *(QColor *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QTime &v)
+{
+ if (type != QMetaType::QTime) {
+ cleanup();
+ type = QMetaType::QTime;
+ new (dataPtr()) QTime(v);
+ } else {
+ *(QTime *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QDate &v)
+{
+ if (type != QMetaType::QDate) {
+ cleanup();
+ type = QMetaType::QDate;
+ new (dataPtr()) QDate(v);
+ } else {
+ *(QDate *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QDateTime &v)
+{
+ if (type != QMetaType::QDateTime) {
+ cleanup();
+ type = QMetaType::QDateTime;
+ new (dataPtr()) QDateTime(v);
+ } else {
+ *(QDateTime *)(dataPtr()) = v;
+ }
+}
+
+void QDeclarativeVMEVariant::setValue(const QScriptValue &v)
+{
+ if (type != qMetaTypeId<QScriptValue>()) {
+ cleanup();
+ type = qMetaTypeId<QScriptValue>();
+ new (dataPtr()) QScriptValue(v);
+ } else {
+ *(QScriptValue *)(dataPtr()) = v;
+ }
+}
+
+QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj,
+ const QMetaObject *other,
+ const QDeclarativeVMEMetaData *meta,
+ QDeclarativeCompiledData *cdata)
+: object(obj), compiledData(cdata), ctxt(QDeclarativeData::get(obj, true)->outerContext),
+ metaData(meta), data(0), methods(0), parent(0)
+{
+ compiledData->addref();
+
+ *static_cast<QMetaObject *>(this) = *other;
+ this->d.superdata = obj->metaObject();
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ if (op->metaObject)
+ parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ op->metaObject = this;
+
+ propOffset = QAbstractDynamicMetaObject::propertyOffset();
+ methodOffset = QAbstractDynamicMetaObject::methodOffset();
+
+ data = new QDeclarativeVMEVariant[metaData->propertyCount];
+
+ aConnected.resize(metaData->aliasCount);
+ int list_type = qMetaTypeId<QDeclarativeListProperty<QObject> >();
+
+ // ### Optimize
+ for (int ii = 0; ii < metaData->propertyCount; ++ii) {
+ int t = (metaData->propertyData() + ii)->propertyType;
+ if (t == list_type) {
+ listProperties.append(List(methodOffset + ii));
+ data[ii].setValue(listProperties.count() - 1);
+ }
+ }
+}
+
+QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
+{
+ compiledData->release();
+ delete parent;
+ delete [] data;
+ delete [] methods;
+}
+
+int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
+{
+ int id = _id;
+ if(c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor)
+ && !aInterceptors.isEmpty()
+ && aInterceptors.testBit(id)) {
+ QPair<int, QDeclarativePropertyValueInterceptor*> pair = interceptors.value(id);
+ int valueIndex = pair.first;
+ QDeclarativePropertyValueInterceptor *vi = pair.second;
+ int type = property(id).userType();
+
+ if (type != QVariant::Invalid) {
+ if (valueIndex != -1) {
+ QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0;
+ QDeclarativeValueType *valueType = 0;
+ if (ep) valueType = ep->valueTypes[type];
+ else valueType = QDeclarativeValueTypeFactory::valueType(type);
+ Q_ASSERT(valueType);
+
+ valueType->setValue(QVariant(type, a[0]));
+ QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
+ vi->write(valueProp.read(valueType));
+
+ if (!ep) delete valueType;
+ return -1;
+ } else {
+ vi->write(QVariant(type, a[0]));
+ return -1;
+ }
+ }
+ }
+ }
+ if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) {
+ if (id >= propOffset) {
+ id -= propOffset;
+
+ if (id < metaData->propertyCount) {
+ int t = (metaData->propertyData() + id)->propertyType;
+ bool needActivate = false;
+
+ if (t == -1) {
+
+ if (c == QMetaObject::ReadProperty) {
+ *reinterpret_cast<QVariant *>(a[0]) = readVarPropertyAsVariant(id);
+ } else if (c == QMetaObject::WriteProperty) {
+ writeVarProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ }
+
+ } else {
+
+ if (c == QMetaObject::ReadProperty) {
+ switch(t) {
+ case QVariant::Int:
+ *reinterpret_cast<int *>(a[0]) = data[id].asInt();
+ break;
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
+ break;
+ case QVariant::Double:
+ *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
+ break;
+ case QVariant::String:
+ *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
+ break;
+ case QVariant::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
+ break;
+ case QVariant::Color:
+ *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor();
+ break;
+ case QVariant::Date:
+ *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
+ break;
+ case QVariant::DateTime:
+ *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
+ break;
+ case QMetaType::QObjectStar:
+ *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
+ break;
+ default:
+ break;
+ }
+ if (t == qMetaTypeId<QDeclarativeListProperty<QObject> >()) {
+ int listIndex = data[id].asInt();
+ const List *list = &listProperties.at(listIndex);
+ *reinterpret_cast<QDeclarativeListProperty<QObject> *>(a[0]) =
+ QDeclarativeListProperty<QObject>(object, (void *)list,
+ list_append, list_count, list_at,
+ list_clear);
+ }
+
+ } else if (c == QMetaObject::WriteProperty) {
+
+ switch(t) {
+ case QVariant::Int:
+ needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
+ data[id].setValue(*reinterpret_cast<int *>(a[0]));
+ break;
+ case QVariant::Bool:
+ needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
+ data[id].setValue(*reinterpret_cast<bool *>(a[0]));
+ break;
+ case QVariant::Double:
+ needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
+ data[id].setValue(*reinterpret_cast<double *>(a[0]));
+ break;
+ case QVariant::String:
+ needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
+ data[id].setValue(*reinterpret_cast<QString *>(a[0]));
+ break;
+ case QVariant::Url:
+ needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
+ data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
+ break;
+ case QVariant::Color:
+ needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor();
+ data[id].setValue(*reinterpret_cast<QColor *>(a[0]));
+ break;
+ case QVariant::Date:
+ needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
+ data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
+ break;
+ case QVariant::DateTime:
+ needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
+ data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
+ break;
+ case QMetaType::QObjectStar:
+ needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
+ data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ if (c == QMetaObject::WriteProperty && needActivate) {
+ activate(object, methodOffset + id, 0);
+ }
+
+ return -1;
+ }
+
+ id -= metaData->propertyCount;
+
+ if (id < metaData->aliasCount) {
+
+ QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id;
+
+ if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
+ *reinterpret_cast<void **>(a[0]) = 0;
+
+ if (!ctxt) return -1;
+
+ QDeclarativeContext *context = ctxt->asQDeclarativeContext();
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
+
+ QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ if (!target)
+ return -1;
+
+ connectAlias(id);
+
+ if (d->isObjectAlias()) {
+ *reinterpret_cast<QObject **>(a[0]) = target;
+ return -1;
+ }
+
+ // Remove binding (if any) on write
+ if(c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (flags & QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite) {
+ QDeclarativeData *targetData = QDeclarativeData::get(target);
+ if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
+ QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
+ if (binding) binding->destroy();
+ }
+ }
+ }
+
+ if (d->isValueTypeAlias()) {
+ // Value type property
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+
+ QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()];
+ Q_ASSERT(valueType);
+
+ valueType->read(target, d->propertyIndex());
+ int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
+
+ if (c == QMetaObject::WriteProperty)
+ valueType->write(target, d->propertyIndex(), 0x00);
+
+ return rv;
+
+ } else {
+ return QMetaObject::metacall(target, c, d->propertyIndex(), a);
+ }
+
+ }
+ return -1;
+
+ }
+
+ } else if(c == QMetaObject::InvokeMetaMethod) {
+
+ if (id >= methodOffset) {
+
+ id -= methodOffset;
+ int plainSignals = metaData->signalCount + metaData->propertyCount +
+ metaData->aliasCount;
+ if (id < plainSignals) {
+ QMetaObject::activate(object, _id, a);
+ return -1;
+ }
+
+ id -= plainSignals;
+
+ if (id < metaData->methodCount) {
+ if (!ctxt->engine)
+ return -1; // We can't run the method
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
+
+ QScriptValue function = method(id);
+
+ QScriptValueList args;
+ QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
+ if (data->parameterCount) {
+ for (int ii = 0; ii < data->parameterCount; ++ii) {
+ args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
+ }
+ }
+ QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
+
+ if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
+
+ return -1;
+ }
+ return -1;
+ }
+ }
+
+ if (parent)
+ return parent->metaCall(c, _id, a);
+ else
+ return object->qt_metacall(c, _id, a);
+}
+
+QScriptValue QDeclarativeVMEMetaObject::method(int index)
+{
+ if (!methods)
+ methods = new QScriptValue[metaData->methodCount];
+
+ if (!methods[index].isValid()) {
+ QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
+
+ const QChar *body =
+ (const QChar *)(((const char*)metaData) + data->bodyOffset);
+
+ QString code = QString::fromRawData(body, data->bodyLength);
+
+ // XXX Use QScriptProgram
+ // XXX We should evaluate all methods in a single big script block to
+ // improve the call time between dynamic methods defined on the same
+ // object
+ methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(),
+ data->lineNumber, 0);
+ }
+
+ return methods[index];
+}
+
+QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id)
+{
+ if (data[id].dataType() == qMetaTypeId<QScriptValue>())
+ return data[id].asQScriptValue();
+ else if (data[id].dataType() == QMetaType::QObjectStar)
+ return QDeclarativeEnginePrivate::get(ctxt->engine)->objectClass->newQObject(data[id].asQObject());
+ else
+ return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant());
+}
+
+QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id)
+{
+ if (data[id].dataType() == qMetaTypeId<QScriptValue>())
+ return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue());
+ else if (data[id].dataType() == QMetaType::QObjectStar)
+ return QVariant::fromValue(data[id].asQObject());
+ else
+ return data[id].asQVariant();
+}
+
+void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value)
+{
+ data[id].setValue(value);
+ activate(object, methodOffset + id, 0);
+}
+
+void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value)
+{
+ bool needActivate = false;
+ if (value.userType() == QMetaType::QObjectStar) {
+ QObject *o = qvariant_cast<QObject *>(value);
+ needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
+ data[id].setValue(qvariant_cast<QObject *>(value));
+ } else {
+ needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
+ data[id].asQVariant().userType() != value.userType() ||
+ data[id].asQVariant() != value);
+ data[id].setValue(value);
+ }
+ if (needActivate)
+ activate(object, methodOffset + id, 0);
+}
+
+void QDeclarativeVMEMetaObject::listChanged(int id)
+{
+ activate(object, methodOffset + id, 0);
+}
+
+void QDeclarativeVMEMetaObject::list_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
+{
+ List *list = static_cast<List *>(prop->data);
+ list->append(o);
+ QMetaObject::activate(prop->object, list->notifyIndex, 0);
+}
+
+int QDeclarativeVMEMetaObject::list_count(QDeclarativeListProperty<QObject> *prop)
+{
+ return static_cast<List *>(prop->data)->count();
+}
+
+QObject *QDeclarativeVMEMetaObject::list_at(QDeclarativeListProperty<QObject> *prop, int index)
+{
+ return static_cast<List *>(prop->data)->at(index);
+}
+
+void QDeclarativeVMEMetaObject::list_clear(QDeclarativeListProperty<QObject> *prop)
+{
+ List *list = static_cast<List *>(prop->data);
+ list->clear();
+ QMetaObject::activate(prop->object, list->notifyIndex, 0);
+}
+
+void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor)
+{
+ if (aInterceptors.isEmpty())
+ aInterceptors.resize(propertyCount() + metaData->propertyCount);
+ aInterceptors.setBit(index);
+ interceptors.insert(index, qMakePair(valueIndex, interceptor));
+}
+
+int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
+ }
+
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ int rawIndex = index - methodOffset - plainSignals;
+
+ QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
+ return data->lineNumber;
+}
+
+QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethod(index);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+ return method(index - methodOffset - plainSignals);
+}
+
+void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &value)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->setVmeMethod(index, value);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ if (!methods)
+ methods = new QScriptValue[metaData->methodCount];
+ methods[index - methodOffset - plainSignals] = value;
+}
+
+QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index)
+{
+ if (index < propOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeProperty(index);
+ }
+ return readVarProperty(index - propOffset);
+}
+
+void QDeclarativeVMEMetaObject::setVMEProperty(int index, const QScriptValue &v)
+{
+ if (index < propOffset) {
+ Q_ASSERT(parent);
+ static_cast<QDeclarativeVMEMetaObject *>(parent)->setVMEProperty(index, v);
+ }
+ return writeVarProperty(index - propOffset, v);
+}
+
+bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
+{
+ Q_ASSERT(index >= propOffset + metaData->propertyCount);
+
+ *target = 0;
+ *coreIndex = -1;
+ *valueTypeIndex = -1;
+
+ if (!ctxt)
+ return false;
+
+ QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
+ QDeclarativeContext *context = ctxt->asQDeclarativeContext();
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
+
+ *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ if (!*target)
+ return false;
+
+ if (d->isObjectAlias()) {
+ } else if (d->isValueTypeAlias()) {
+ *coreIndex = d->propertyIndex();
+ *valueTypeIndex = d->valueTypeIndex();
+ } else {
+ *coreIndex = d->propertyIndex();
+ }
+
+ return true;
+}
+
+void QDeclarativeVMEMetaObject::connectAlias(int aliasId)
+{
+ if (!aConnected.testBit(aliasId)) {
+ aConnected.setBit(aliasId);
+
+ QDeclarativeContext *context = ctxt->asQDeclarativeContext();
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
+
+ QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
+
+ QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
+ if (!target)
+ return;
+
+ int sigIdx = methodOffset + aliasId + metaData->propertyCount;
+ QMetaObject::connect(context, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx);
+
+ if (!d->isObjectAlias()) {
+ QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
+ if (prop.hasNotifySignal())
+ QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(), object, sigIdx);
+ }
+ }
+}
+
+void QDeclarativeVMEMetaObject::connectAliasSignal(int index)
+{
+ int aliasId = (index - methodOffset) - metaData->propertyCount;
+ if (aliasId < 0 || aliasId >= metaData->aliasCount)
+ return;
+
+ connectAlias(aliasId);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h
new file mode 100644
index 0000000000..318ac4aa77
--- /dev/null
+++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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 QDECLARATIVEVMEMETAOBJECT_P_H
+#define QDECLARATIVEVMEMETAOBJECT_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/QMetaObject>
+#include <QtCore/QBitArray>
+#include <QtCore/QPair>
+#include <QtGui/QColor>
+#include <QtCore/QDate>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+#include "private/qdeclarativeguard_p.h"
+#include "private/qdeclarativecompiler_p.h"
+#include "private/qdeclarativecontext_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define QML_ALIAS_FLAG_PTR 0x00000001
+
+struct QDeclarativeVMEMetaData
+{
+ short propertyCount;
+ short aliasCount;
+ short signalCount;
+ short methodCount;
+
+ struct AliasData {
+ int contextIdx;
+ int propertyIdx;
+ int flags;
+
+ bool isObjectAlias() const {
+ return propertyIdx == -1;
+ }
+ bool isPropertyAlias() const {
+ return !isObjectAlias() && !(propertyIdx & 0xFF000000);
+ }
+ bool isValueTypeAlias() const {
+ return !isObjectAlias() && (propertyIdx & 0xFF000000);
+ }
+ int propertyIndex() const {
+ return propertyIdx & 0x0000FFFF;
+ }
+ int valueTypeIndex() const {
+ return (propertyIdx & 0x00FF0000) >> 16;
+ }
+ int valueType() const {
+ return ((unsigned int)propertyIdx) >> 24;
+ }
+ };
+
+ struct PropertyData {
+ int propertyType;
+ };
+
+ struct MethodData {
+ int parameterCount;
+ int bodyOffset;
+ int bodyLength;
+ int lineNumber;
+ };
+
+ PropertyData *propertyData() const {
+ return (PropertyData *)(((const char *)this) + sizeof(QDeclarativeVMEMetaData));
+ }
+
+ AliasData *aliasData() const {
+ return (AliasData *)(propertyData() + propertyCount);
+ }
+
+ MethodData *methodData() const {
+ return (MethodData *)(aliasData() + aliasCount);
+ }
+};
+
+class QDeclarativeVMEVariant;
+class QDeclarativeRefCount;
+class QDeclarativeVMEMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QDeclarativeVMEMetaObject(QObject *obj, const QMetaObject *other, const QDeclarativeVMEMetaData *data,
+ QDeclarativeCompiledData *compiledData);
+ ~QDeclarativeVMEMetaObject();
+
+ bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
+ void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor);
+ QScriptValue vmeMethod(int index);
+ int vmeMethodLineNumber(int index);
+ void setVmeMethod(int index, const QScriptValue &);
+ QScriptValue vmeProperty(int index);
+ void setVMEProperty(int index, const QScriptValue &);
+
+ void connectAliasSignal(int index);
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+
+private:
+ QObject *object;
+ QDeclarativeCompiledData *compiledData;
+ QDeclarativeGuardedContextData ctxt;
+
+ const QDeclarativeVMEMetaData *metaData;
+ int propOffset;
+ int methodOffset;
+
+ QDeclarativeVMEVariant *data;
+
+ void connectAlias(int aliasId);
+ QBitArray aConnected;
+ QBitArray aInterceptors;
+ QHash<int, QPair<int, QDeclarativePropertyValueInterceptor*> > interceptors;
+
+ QScriptValue *methods;
+ QScriptValue method(int);
+
+ QScriptValue readVarProperty(int);
+ QVariant readVarPropertyAsVariant(int);
+ void writeVarProperty(int, const QScriptValue &);
+ void writeVarProperty(int, const QVariant &);
+
+ QAbstractDynamicMetaObject *parent;
+
+ void listChanged(int);
+ class List : public QList<QObject*>
+ {
+ public:
+ List(int lpi) : notifyIndex(lpi) {}
+ int notifyIndex;
+ };
+ QList<List> listProperties;
+
+ static void list_append(QDeclarativeListProperty<QObject> *, QObject *);
+ static int list_count(QDeclarativeListProperty<QObject> *);
+ static QObject *list_at(QDeclarativeListProperty<QObject> *, int);
+ static void list_clear(QDeclarativeListProperty<QObject> *);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEVMEMETAOBJECT_P_H
diff --git a/src/declarative/qml/qdeclarativewatcher.cpp b/src/declarative/qml/qdeclarativewatcher.cpp
new file mode 100644
index 0000000000..a870a81027
--- /dev/null
+++ b/src/declarative/qml/qdeclarativewatcher.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativewatcher_p.h"
+
+#include "qdeclarativeexpression.h"
+#include "qdeclarativecontext.h"
+#include "qdeclarative.h"
+
+#include <qdeclarativedebugservice_p.h>
+#include "private/qdeclarativeproperty_p.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QDeclarativeWatchProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeWatchProxy(int id,
+ QObject *object,
+ int debugId,
+ const QMetaProperty &prop,
+ QDeclarativeWatcher *parent = 0);
+
+ QDeclarativeWatchProxy(int id,
+ QDeclarativeExpression *exp,
+ int debugId,
+ QDeclarativeWatcher *parent = 0);
+
+public slots:
+ void notifyValueChanged();
+
+private:
+ friend class QDeclarativeWatcher;
+ int m_id;
+ QDeclarativeWatcher *m_watch;
+ QObject *m_object;
+ int m_debugId;
+ QMetaProperty m_property;
+
+ QDeclarativeExpression *m_expr;
+};
+
+QDeclarativeWatchProxy::QDeclarativeWatchProxy(int id,
+ QDeclarativeExpression *exp,
+ int debugId,
+ QDeclarativeWatcher *parent)
+: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp)
+{
+ QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged()));
+}
+
+QDeclarativeWatchProxy::QDeclarativeWatchProxy(int id,
+ QObject *object,
+ int debugId,
+ const QMetaProperty &prop,
+ QDeclarativeWatcher *parent)
+: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0)
+{
+ static int refreshIdx = -1;
+ if(refreshIdx == -1)
+ refreshIdx = QDeclarativeWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()");
+
+ if (prop.hasNotifySignal())
+ QDeclarativePropertyPrivate::connect(m_object, prop.notifySignalIndex(), this, refreshIdx);
+}
+
+void QDeclarativeWatchProxy::notifyValueChanged()
+{
+ QVariant v;
+ if (m_expr)
+ v = m_expr->evaluate();
+ else
+ v = m_property.read(m_object);
+
+ emit m_watch->propertyChanged(m_id, m_debugId, m_property, v);
+}
+
+
+QDeclarativeWatcher::QDeclarativeWatcher(QObject *parent)
+ : QObject(parent)
+{
+}
+
+bool QDeclarativeWatcher::addWatch(int id, quint32 debugId)
+{
+ QObject *object = QDeclarativeDebugService::objectForId(debugId);
+ if (object) {
+ int propCount = object->metaObject()->propertyCount();
+ for (int ii=0; ii<propCount; ii++)
+ addPropertyWatch(id, object, debugId, object->metaObject()->property(ii));
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeWatcher::addWatch(int id, quint32 debugId, const QByteArray &property)
+{
+ QObject *object = QDeclarativeDebugService::objectForId(debugId);
+ if (object) {
+ int index = object->metaObject()->indexOfProperty(property.constData());
+ if (index >= 0) {
+ addPropertyWatch(id, object, debugId, object->metaObject()->property(index));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QDeclarativeWatcher::addWatch(int id, quint32 objectId, const QString &expr)
+{
+ QObject *object = QDeclarativeDebugService::objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ if (context) {
+ QDeclarativeExpression *exprObj = new QDeclarativeExpression(context, object, expr);
+ exprObj->setNotifyOnValueChanged(true);
+ QDeclarativeWatchProxy *proxy = new QDeclarativeWatchProxy(id, exprObj, objectId, this);
+ exprObj->setParent(proxy);
+ m_proxies[id].append(proxy);
+ proxy->notifyValueChanged();
+ return true;
+ }
+ return false;
+}
+
+void QDeclarativeWatcher::removeWatch(int id)
+{
+ if (!m_proxies.contains(id))
+ return;
+
+ QList<QPointer<QDeclarativeWatchProxy> > proxies = m_proxies.take(id);
+ qDeleteAll(proxies);
+}
+
+void QDeclarativeWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property)
+{
+ QDeclarativeWatchProxy *proxy = new QDeclarativeWatchProxy(id, object, debugId, property, this);
+ m_proxies[id].append(proxy);
+
+ proxy->notifyValueChanged();
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativewatcher.moc>
diff --git a/src/declarative/qml/qdeclarativewatcher_p.h b/src/declarative/qml/qdeclarativewatcher_p.h
new file mode 100644
index 0000000000..b5e234fd17
--- /dev/null
+++ b/src/declarative/qml/qdeclarativewatcher_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEWATCHER_P_H
+#define QDECLARATIVEWATCHER_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/qobject.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qset.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeWatchProxy;
+class QDeclarativeExpression;
+class QDeclarativeContext;
+class QMetaProperty;
+
+class QDeclarativeWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeWatcher(QObject * = 0);
+
+ bool addWatch(int id, quint32 objectId);
+ bool addWatch(int id, quint32 objectId, const QByteArray &property);
+ bool addWatch(int id, quint32 objectId, const QString &expr);
+
+ void removeWatch(int id);
+
+Q_SIGNALS:
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ friend class QDeclarativeWatchProxy;
+ void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property);
+
+ QHash<int, QList<QPointer<QDeclarativeWatchProxy> > > m_proxies;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEWATCHER_P_H
diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp
new file mode 100644
index 0000000000..db8a2ae81b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeworkerscript.cpp
@@ -0,0 +1,753 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeworkerscript_p.h"
+#include "private/qdeclarativelistmodel_p.h"
+#include "private/qdeclarativelistmodelworkeragent_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeexpression_p.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptengine.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtScript/qscriptvalueiterator.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdatetime.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include "qdeclarativenetworkaccessmanagerfactory.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class WorkerDataEvent : public QEvent
+{
+public:
+ enum Type { WorkerData = QEvent::User };
+
+ WorkerDataEvent(int workerId, const QVariant &data);
+ virtual ~WorkerDataEvent();
+
+ int workerId() const;
+ QVariant data() const;
+
+private:
+ int m_id;
+ QVariant m_data;
+};
+
+class WorkerLoadEvent : public QEvent
+{
+public:
+ enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
+
+ WorkerLoadEvent(int workerId, const QUrl &url);
+
+ int workerId() const;
+ QUrl url() const;
+
+private:
+ int m_id;
+ QUrl m_url;
+};
+
+class WorkerRemoveEvent : public QEvent
+{
+public:
+ enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
+
+ WorkerRemoveEvent(int workerId);
+
+ int workerId() const;
+
+private:
+ int m_id;
+};
+
+class WorkerErrorEvent : public QEvent
+{
+public:
+ enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
+
+ WorkerErrorEvent(const QDeclarativeError &error);
+
+ QDeclarativeError error() const;
+
+private:
+ QDeclarativeError m_error;
+};
+
+class QDeclarativeWorkerScriptEnginePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ enum WorkerEventTypes {
+ WorkerDestroyEvent = QEvent::User + 100
+ };
+
+ QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
+
+ struct ScriptEngine : public QDeclarativeScriptEngine
+ {
+ ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {}
+ ~ScriptEngine() { delete accessManager; }
+ QDeclarativeWorkerScriptEnginePrivate *p;
+ QNetworkAccessManager *accessManager;
+
+ virtual QNetworkAccessManager *networkAccessManager() {
+ if (!accessManager) {
+ if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
+ accessManager = p->qmlengine->networkAccessManagerFactory()->create(this);
+ } else {
+ accessManager = new QNetworkAccessManager(this);
+ }
+ }
+ return accessManager;
+ }
+ };
+ ScriptEngine *workerEngine;
+ static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) {
+ return static_cast<ScriptEngine *>(e)->p;
+ }
+
+ QDeclarativeEngine *qmlengine;
+
+ QMutex m_lock;
+ QWaitCondition m_wait;
+
+ struct WorkerScript {
+ WorkerScript();
+
+ int id;
+ QUrl source;
+ bool initialized;
+ QDeclarativeWorkerScript *owner;
+ QScriptValue object;
+
+ QScriptValue callback;
+ };
+
+ QHash<int, WorkerScript *> workers;
+ QScriptValue getWorker(int);
+
+ int m_nextId;
+
+ static QVariant scriptValueToVariant(const QScriptValue &);
+ static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
+
+ static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
+ static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
+
+signals:
+ void stopThread();
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ void processMessage(int, const QVariant &);
+ void processLoad(int, const QUrl &);
+ void reportScriptException(WorkerScript *);
+};
+
+QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
+: workerEngine(0), qmlengine(engine), m_nextId(0)
+{
+}
+
+QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+
+ int id = ctxt->thisObject().data().toVariant().toInt();
+
+ WorkerScript *script = p->workers.value(id);
+ if (!script)
+ return engine->undefinedValue();
+
+ if (ctxt->argumentCount() >= 1)
+ script->callback = ctxt->argument(0);
+
+ return script->callback;
+}
+
+QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
+{
+ if (!ctxt->argumentCount())
+ return engine->undefinedValue();
+
+ QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+
+ int id = ctxt->thisObject().data().toVariant().toInt();
+
+ WorkerScript *script = p->workers.value(id);
+ if (!script)
+ return engine->undefinedValue();
+
+ QMutexLocker(&p->m_lock);
+
+ if (script->owner)
+ QCoreApplication::postEvent(script->owner,
+ new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
+
+ return engine->undefinedValue();
+}
+
+QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
+{
+ QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
+
+ if (iter == workers.end())
+ return workerEngine->nullValue();
+
+ WorkerScript *script = *iter;
+ if (!script->initialized) {
+
+ script->initialized = true;
+ script->object = workerEngine->newObject();
+
+ QScriptValue api = workerEngine->newObject();
+ api.setData(script->id);
+
+ api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
+ QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
+
+ script->object.setProperty(QLatin1String("WorkerScript"), api);
+ }
+
+ return script->object;
+}
+
+bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
+{
+ if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
+ WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
+ processMessage(workerEvent->workerId(), workerEvent->data());
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
+ WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
+ processLoad(workerEvent->workerId(), workerEvent->url());
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
+ emit stopThread();
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
+{
+ WorkerScript *script = workers.value(id);
+ if (!script)
+ return;
+
+ if (script->callback.isFunction()) {
+ QScriptValue args = workerEngine->newArray(1);
+ args.setProperty(0, variantToScriptValue(data, workerEngine));
+
+ script->callback.call(script->object, args);
+
+ if (workerEngine->hasUncaughtException()) {
+ reportScriptException(script);
+ workerEngine->clearExceptions();
+ }
+ }
+}
+
+void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
+{
+ if (url.isRelative())
+ return;
+
+ QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+
+ QFile f(fileName);
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString sourceCode = QString::fromUtf8(data);
+
+ QScriptValue activation = getWorker(id);
+
+ QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine);
+ QScriptValue urlContext = workerEngine->newObject();
+ urlContext.setData(QScriptValue(workerEngine, url.toString()));
+ ctxt->pushScope(urlContext);
+ ctxt->pushScope(activation);
+ ctxt->setActivationObject(activation);
+ QDeclarativeScriptParser::extractPragmas(sourceCode);
+
+ workerEngine->baseUrl = url;
+ workerEngine->evaluate(sourceCode);
+
+ WorkerScript *script = workers.value(id);
+ if (script) {
+ script->source = url;
+ if (workerEngine->hasUncaughtException()) {
+ reportScriptException(script);
+ workerEngine->clearExceptions();
+ }
+ }
+
+ workerEngine->popContext();
+ } else {
+ qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
+ }
+}
+
+void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script)
+{
+ if (!script || !workerEngine->hasUncaughtException())
+ return;
+
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error);
+ error.setUrl(script->source);
+
+ QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
+
+ QMutexLocker(&p->m_lock);
+ if (script->owner)
+ QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
+}
+
+QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
+{
+ if (value.isBool()) {
+ return QVariant(value.toBool());
+ } else if (value.isString()) {
+ return QVariant(value.toString());
+ } else if (value.isNumber()) {
+ return QVariant((qreal)value.toNumber());
+ } else if (value.isDate()) {
+ return QVariant(value.toDateTime());
+#ifndef QT_NO_REGEXP
+ } else if (value.isRegExp()) {
+ return QVariant(value.toRegExp());
+#endif
+ } else if (value.isArray()) {
+ QVariantList list;
+
+ quint32 length = (quint32)value.property(QLatin1String("length")).toNumber();
+
+ for (quint32 ii = 0; ii < length; ++ii) {
+ QVariant v = scriptValueToVariant(value.property(ii));
+ list << v;
+ }
+
+ return QVariant(list);
+ } else if (value.isQObject()) {
+ QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
+ if (lm) {
+ QDeclarativeListModelWorkerAgent *agent = lm->agent();
+ if (agent) {
+ QDeclarativeListModelWorkerAgent::VariantRef v(agent);
+ return QVariant::fromValue(v);
+ } else {
+ return QVariant();
+ }
+ } else {
+ // No other QObject's are allowed to be sent
+ return QVariant();
+ }
+ } else if (value.isObject()) {
+ QVariantHash hash;
+
+ QScriptValueIterator iter(value);
+
+ while (iter.hasNext()) {
+ iter.next();
+ hash.insert(iter.name(), scriptValueToVariant(iter.value()));
+ }
+
+ return QVariant(hash);
+ }
+
+ return QVariant();
+
+}
+
+QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
+{
+ if (value.userType() == QVariant::Bool) {
+ return QScriptValue(value.toBool());
+ } else if (value.userType() == QVariant::String) {
+ return QScriptValue(value.toString());
+ } else if (value.userType() == QMetaType::QReal) {
+ return QScriptValue(value.toReal());
+ } else if (value.userType() == QVariant::DateTime) {
+ return engine->newDate(value.toDateTime());
+#ifndef QT_NO_REGEXP
+ } else if (value.userType() == QVariant::RegExp) {
+ return engine->newRegExp(value.toRegExp());
+#endif
+ } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) {
+ QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value);
+ if (vr.a->scriptEngine() == 0)
+ vr.a->setScriptEngine(engine);
+ else if (vr.a->scriptEngine() != engine)
+ return engine->nullValue();
+ QScriptValue o = engine->newQObject(vr.a);
+ o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
+ return o;
+ } else if (value.userType() == QMetaType::QVariantList) {
+ QVariantList list = qvariant_cast<QVariantList>(value);
+ QScriptValue rv = engine->newArray(list.count());
+
+ for (quint32 ii = 0; ii < quint32(list.count()); ++ii)
+ rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
+
+ return rv;
+ } else if (value.userType() == QMetaType::QVariantHash) {
+
+ QVariantHash hash = qvariant_cast<QVariantHash>(value);
+
+ QScriptValue rv = engine->newObject();
+
+ for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
+ rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
+
+ return rv;
+ } else {
+ return engine->nullValue();
+ }
+}
+
+WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
+: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
+{
+}
+
+WorkerDataEvent::~WorkerDataEvent()
+{
+}
+
+int WorkerDataEvent::workerId() const
+{
+ return m_id;
+}
+
+QVariant WorkerDataEvent::data() const
+{
+ return m_data;
+}
+
+WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
+: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
+{
+}
+
+int WorkerLoadEvent::workerId() const
+{
+ return m_id;
+}
+
+QUrl WorkerLoadEvent::url() const
+{
+ return m_url;
+}
+
+WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
+: QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
+{
+}
+
+int WorkerRemoveEvent::workerId() const
+{
+ return m_id;
+}
+
+WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error)
+: QEvent((QEvent::Type)WorkerError), m_error(error)
+{
+}
+
+QDeclarativeError WorkerErrorEvent::error() const
+{
+ return m_error;
+}
+
+QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent)
+: QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent))
+{
+ d->m_lock.lock();
+ connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
+ start(QThread::IdlePriority);
+ d->m_wait.wait(&d->m_lock);
+ d->moveToThread(this);
+ d->m_lock.unlock();
+}
+
+QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
+{
+ d->m_lock.lock();
+ qDeleteAll(d->workers);
+ d->workers.clear();
+ QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
+ d->m_lock.unlock();
+
+ wait();
+ d->deleteLater();
+}
+
+QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
+: id(-1), initialized(false), owner(0)
+{
+}
+
+int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
+{
+ QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript;
+ script->id = d->m_nextId++;
+ script->owner = owner;
+
+ d->m_lock.lock();
+ d->workers.insert(script->id, script);
+ d->m_lock.unlock();
+
+ return script->id;
+}
+
+void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id)
+{
+ QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
+}
+
+void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
+{
+ QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
+}
+
+void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data)
+{
+ QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
+}
+
+void QDeclarativeWorkerScriptEngine::run()
+{
+ d->m_lock.lock();
+
+ d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d);
+
+ d->m_wait.wakeAll();
+
+ d->m_lock.unlock();
+
+ exec();
+
+ delete d->workerEngine; d->workerEngine = 0;
+}
+
+
+/*!
+ \qmlclass WorkerScript QDeclarativeWorkerScript
+ \ingroup qml-utility-elements
+ \brief The WorkerScript element enables the use of threads in QML.
+
+ Use WorkerScript to run operations in a new thread.
+ This is useful for running operations in the background so
+ that the main GUI thread is not blocked.
+
+ Messages can be passed between the new thread and the parent thread
+ using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler.
+
+ An example:
+
+ \snippet doc/src/snippets/declarative/workerscript.qml 0
+
+ The above worker script specifies a JavaScript file, "script.js", that handles
+ the operations to be performed in the new thread. Here is \c script.js:
+
+ \quotefile doc/src/snippets/declarative/script.js
+
+ When the user clicks anywhere within the rectangle, \c sendMessage() is
+ called, triggering the \tt WorkerScript.onMessage() handler in
+ \tt script.js. This in turn sends a reply message that is then received
+ by the \tt onMessage() handler of \tt myWorker.
+
+
+ \section3 Restrictions
+
+ Since the \c WorkerScript.onMessage() function is run in a separate thread, the
+ JavaScript file is evaluated in a context separate from the main QML engine. This means
+ that unlike an ordinary JavaScript file that is imported into QML, the \c script.js
+ in the above example cannot access the properties, methods or other attributes
+ of the QML item, nor can it access any context properties set on the QML object
+ through QDeclarativeContext.
+
+ Additionally, there are restrictions on the types of values that can be passed to and
+ from the worker script. See the sendMessage() documentation for details.
+
+ \sa {declarative/threading/workerscript}{WorkerScript example},
+ {declarative/threading/threadedlistmodel}{Threaded ListModel example}
+*/
+QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent)
+: QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true)
+{
+}
+
+QDeclarativeWorkerScript::~QDeclarativeWorkerScript()
+{
+ if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
+}
+
+/*!
+ \qmlproperty url WorkerScript::source
+
+ This holds the url of the JavaScript file that implements the
+ \tt WorkerScript.onMessage() handler for threaded operations.
+*/
+QUrl QDeclarativeWorkerScript::source() const
+{
+ return m_source;
+}
+
+void QDeclarativeWorkerScript::setSource(const QUrl &source)
+{
+ if (m_source == source)
+ return;
+
+ m_source = source;
+
+ if (engine())
+ m_engine->executeUrl(m_scriptId, m_source);
+
+ emit sourceChanged();
+}
+
+/*!
+ \qmlmethod WorkerScript::sendMessage(jsobject message)
+
+ Sends the given \a message to a worker script handler in another
+ thread. The other worker script handler can receive this message
+ through the onMessage() handler.
+
+ The \c message object may only contain values of the following
+ types:
+
+ \list
+ \o boolean, number, string
+ \o JavaScript objects and arrays
+ \o ListModel objects (any other type of QObject* is not allowed)
+ \endlist
+
+ All objects and arrays are copied to the \c message. With the exception
+ of ListModel objects, any modifications by the other thread to an object
+ passed in \c message will not be reflected in the original object.
+*/
+void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message)
+{
+ if (!engine()) {
+ qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
+ return;
+ }
+
+ m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message));
+}
+
+void QDeclarativeWorkerScript::classBegin()
+{
+ m_componentComplete = false;
+}
+
+QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine()
+{
+ if (m_engine) return m_engine;
+ if (m_componentComplete) {
+ QDeclarativeEngine *engine = qmlEngine(this);
+ if (!engine) {
+ qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set");
+ return 0;
+ }
+
+ m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine();
+ m_scriptId = m_engine->registerWorkerScript(this);
+
+ if (m_source.isValid())
+ m_engine->executeUrl(m_scriptId, m_source);
+
+ return m_engine;
+ }
+ return 0;
+}
+
+void QDeclarativeWorkerScript::componentComplete()
+{
+ m_componentComplete = true;
+ engine(); // Get it started now.
+}
+
+/*!
+ \qmlsignal WorkerScript::onMessage(jsobject msg)
+
+ This handler is called when a message \a msg is received from a worker
+ script in another thread through a call to sendMessage().
+*/
+
+bool QDeclarativeWorkerScript::event(QEvent *event)
+{
+ if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
+ QDeclarativeEngine *engine = qmlEngine(this);
+ if (engine) {
+ QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
+ QScriptValue value =
+ QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
+ emit message(value);
+ }
+ return true;
+ } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
+ WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
+ QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error());
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativeworkerscript.moc>
+
diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h
new file mode 100644
index 0000000000..70fdeb4d0d
--- /dev/null
+++ b/src/declarative/qml/qdeclarativeworkerscript_p.h
@@ -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 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 QDECLARATIVEWORKERSCRIPT_P_H
+#define QDECLARATIVEWORKERSCRIPT_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 "qdeclarativeparserstatus.h"
+
+#include <QtCore/qthread.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeWorkerScript;
+class QDeclarativeWorkerScriptEnginePrivate;
+class QDeclarativeWorkerScriptEngine : public QThread
+{
+Q_OBJECT
+public:
+ QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent = 0);
+ virtual ~QDeclarativeWorkerScriptEngine();
+
+ int registerWorkerScript(QDeclarativeWorkerScript *);
+ void removeWorkerScript(int);
+ void executeUrl(int, const QUrl &);
+ void sendMessage(int, const QVariant &);
+
+protected:
+ virtual void run();
+
+private:
+ QDeclarativeWorkerScriptEnginePrivate *d;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+public:
+ QDeclarativeWorkerScript(QObject *parent = 0);
+ virtual ~QDeclarativeWorkerScript();
+
+ QUrl source() const;
+ void setSource(const QUrl &);
+
+public slots:
+ void sendMessage(const QScriptValue &);
+
+signals:
+ void sourceChanged();
+ void message(const QScriptValue &messageObject);
+
+protected:
+ virtual void classBegin();
+ virtual void componentComplete();
+ virtual bool event(QEvent *);
+
+private:
+ QDeclarativeWorkerScriptEngine *engine();
+ QDeclarativeWorkerScriptEngine *m_engine;
+ int m_scriptId;
+ QUrl m_source;
+ bool m_componentComplete;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeWorkerScript)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEWORKERSCRIPT_P_H
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
new file mode 100644
index 0000000000..aefc896f5b
--- /dev/null
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -0,0 +1,1740 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativexmlhttprequest_p.h"
+
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativerefcount_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "qdeclarativeglobal_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qtextcodec.h>
+#include <QtCore/qxmlstream.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qdebug.h>
+
+#include <QtCore/QStringBuilder>
+
+#ifndef QT_NO_XMLSTREAMREADER
+
+// From DOM-Level-3-Core spec
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html
+#define INDEX_SIZE_ERR 1
+#define DOMSTRING_SIZE_ERR 2
+#define HIERARCHY_REQUEST_ERR 3
+#define WRONG_DOCUMENT_ERR 4
+#define INVALID_CHARACTER_ERR 5
+#define NO_DATA_ALLOWED_ERR 6
+#define NO_MODIFICATION_ALLOWED_ERR 7
+#define NOT_FOUND_ERR 8
+#define NOT_SUPPORTED_ERR 9
+#define INUSE_ATTRIBUTE_ERR 10
+#define INVALID_STATE_ERR 11
+#define SYNTAX_ERR 12
+#define INVALID_MODIFICATION_ERR 13
+#define NAMESPACE_ERR 14
+#define INVALID_ACCESS_ERR 15
+#define VALIDATION_ERR 16
+#define TYPE_MISMATCH_ERR 17
+
+#define THROW_DOM(error, desc) \
+{ \
+ QScriptValue errorValue = context->throwError(QLatin1String(desc)); \
+ errorValue.setProperty(QLatin1String("code"), error); \
+ return errorValue; \
+}
+
+#define THROW_SYNTAX(desc) \
+ return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc));
+#define THROW_REFERENCE(desc) \
+ return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc));
+
+#define D(arg) (arg)->release()
+#define A(arg) (arg)->addref()
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+
+class DocumentImpl;
+class NodeImpl
+{
+public:
+ NodeImpl() : type(Element), document(0), parent(0) {}
+ virtual ~NodeImpl() {
+ for (int ii = 0; ii < children.count(); ++ii)
+ delete children.at(ii);
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ delete attributes.at(ii);
+ }
+
+ // These numbers are copied from the Node IDL definition
+ enum Type {
+ Attr = 2,
+ CDATA = 4,
+ Comment = 8,
+ Document = 9,
+ DocumentFragment = 11,
+ DocumentType = 10,
+ Element = 1,
+ Entity = 6,
+ EntityReference = 5,
+ Notation = 12,
+ ProcessingInstruction = 7,
+ Text = 3
+ };
+ Type type;
+
+ QString namespaceUri;
+ QString name;
+
+ QString data;
+
+ void addref();
+ void release();
+
+ DocumentImpl *document;
+ NodeImpl *parent;
+
+ QList<NodeImpl *> children;
+ QList<NodeImpl *> attributes;
+};
+
+class DocumentImpl : public QDeclarativeRefCount, public NodeImpl
+{
+public:
+ DocumentImpl() : root(0) { type = Document; }
+ virtual ~DocumentImpl() {
+ if (root) delete root;
+ }
+
+ QString version;
+ QString encoding;
+ bool isStandalone;
+
+ NodeImpl *root;
+
+ void addref() { QDeclarativeRefCount::addref(); }
+ void release() { QDeclarativeRefCount::release(); }
+};
+
+class NamedNodeMap
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
+
+ NamedNodeMap();
+ NamedNodeMap(const NamedNodeMap &);
+ ~NamedNodeMap();
+ bool isNull();
+
+ NodeImpl *d;
+ QList<NodeImpl *> *list;
+private:
+ NamedNodeMap &operator=(const NamedNodeMap &);
+};
+
+class NamedNodeMapClass : public QScriptClass
+{
+public:
+ NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
+
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class NodeList
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ NodeList();
+ NodeList(const NodeList &);
+ ~NodeList();
+ bool isNull();
+
+ NodeImpl *d;
+private:
+ NodeList &operator=(const NodeList &);
+};
+
+class NodeListClass : public QScriptClass
+{
+public:
+ NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class Node
+{
+public:
+ // JS API
+ static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
+
+ static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
+
+ //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ Node();
+ Node(const Node &o);
+ ~Node();
+ bool isNull() const;
+
+ NodeImpl *d;
+
+private:
+ Node &operator=(const Node &);
+};
+
+class Element : public Node
+{
+public:
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Attr : public Node
+{
+public:
+ // JS API
+ static QScriptValue name(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue specified(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue value(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue isId(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CharacterData : public Node
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Text : public CharacterData
+{
+public:
+ // JS API
+ static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CDATA : public Text
+{
+public:
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Document : public Node
+{
+public:
+ // JS API
+ static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Node)
+Q_DECLARE_METATYPE(NodeList)
+Q_DECLARE_METATYPE(NamedNodeMap)
+
+QT_BEGIN_NAMESPACE
+
+void NodeImpl::addref()
+{
+ A(document);
+}
+
+void NodeImpl::release()
+{
+ D(document);
+}
+
+QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ switch (node.d->type) {
+ case NodeImpl::Document:
+ return QScriptValue(QLatin1String("#document"));
+ case NodeImpl::CDATA:
+ return QScriptValue(QLatin1String("#cdata-section"));
+ case NodeImpl::Text:
+ return QScriptValue(QLatin1String("#text"));
+ default:
+ return QScriptValue(node.d->name);
+ }
+}
+
+QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->type == NodeImpl::Document ||
+ node.d->type == NodeImpl::DocumentFragment ||
+ node.d->type == NodeImpl::DocumentType ||
+ node.d->type == NodeImpl::Element ||
+ node.d->type == NodeImpl::Entity ||
+ node.d->type == NodeImpl::EntityReference ||
+ node.d->type == NodeImpl::Notation)
+ return engine->nullValue();
+
+ return QScriptValue(node.d->data);
+}
+
+QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+ return QScriptValue(node.d->type);
+}
+
+QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->parent) return Node::create(engine, node.d->parent);
+ else return engine->nullValue();
+}
+
+QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return NodeList::create(engine, node.d);
+}
+
+QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.first());
+}
+
+QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.last());
+}
+
+QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if (ii == 0) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii - 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii + 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->type != NodeImpl::Element)
+ return engine->nullValue();
+ else
+ return NamedNodeMap::create(engine, node.d, &node.d->attributes);
+}
+
+QScriptValue Node::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+
+ switch (data->type) {
+ case NodeImpl::Attr:
+ instance.setPrototype(Attr::prototype(engine));
+ break;
+ case NodeImpl::Comment:
+ case NodeImpl::Document:
+ case NodeImpl::DocumentFragment:
+ case NodeImpl::DocumentType:
+ case NodeImpl::Entity:
+ case NodeImpl::EntityReference:
+ case NodeImpl::Notation:
+ case NodeImpl::ProcessingInstruction:
+ return QScriptValue();
+ case NodeImpl::CDATA:
+ instance.setPrototype(CDATA::prototype(engine));
+ break;
+ case NodeImpl::Text:
+ instance.setPrototype(Text::prototype(engine));
+ break;
+ case NodeImpl::Element:
+ instance.setPrototype(Element::prototype(engine));
+ break;
+ }
+
+ Node node;
+ node.d = data;
+ if (data) A(data);
+
+ return engine->newVariant(instance, QVariant::fromValue(node));
+}
+
+QScriptValue Element::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Attr::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->name);
+}
+
+QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data);
+}
+
+QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return Node::create(engine, node.d->parent);
+}
+
+QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data.length());
+}
+
+QScriptValue CharacterData::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return node.d->data.trimmed().isEmpty();
+}
+
+QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return node.d->data;
+}
+
+QScriptValue Text::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(CharacterData::prototype(engine));
+
+ proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue CDATA::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Text::prototype(engine));
+ return proto;
+}
+
+QScriptValue Document::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
+{
+ Q_ASSERT(engine);
+
+ DocumentImpl *document = 0;
+ QStack<NodeImpl *> nodeStack;
+
+ QXmlStreamReader reader(data);
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ break;
+ case QXmlStreamReader::Invalid:
+ break;
+ case QXmlStreamReader::StartDocument:
+ Q_ASSERT(!document);
+ document = new DocumentImpl;
+ document->document = document;
+ document->version = reader.documentVersion().toString();
+ document->encoding = reader.documentEncoding().toString();
+ document->isStandalone = reader.isStandaloneDocument();
+ break;
+ case QXmlStreamReader::EndDocument:
+ break;
+ case QXmlStreamReader::StartElement:
+ {
+ Q_ASSERT(document);
+ NodeImpl *node = new NodeImpl;
+ node->document = document;
+ node->namespaceUri = reader.namespaceUri().toString();
+ node->name = reader.name().toString();
+ if (nodeStack.isEmpty()) {
+ document->root = node;
+ } else {
+ node->parent = nodeStack.top();
+ node->parent->children.append(node);
+ }
+ nodeStack.append(node);
+
+ foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+ NodeImpl *attr = new NodeImpl;
+ attr->document = document;
+ attr->type = NodeImpl::Attr;
+ attr->namespaceUri = a.namespaceUri().toString();
+ attr->name = a.name().toString();
+ attr->data = a.value().toString();
+ attr->parent = node;
+ node->attributes.append(attr);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ nodeStack.pop();
+ break;
+ case QXmlStreamReader::Characters:
+ {
+ NodeImpl *node = new NodeImpl;
+ node->document = document;
+ node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
+ node->parent = nodeStack.top();
+ node->parent->children.append(node);
+ node->data = reader.text().toString();
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ break;
+ case QXmlStreamReader::DTD:
+ break;
+ case QXmlStreamReader::EntityReference:
+ break;
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+
+ if (!document || reader.hasError()) {
+ if (document) D(document);
+ return engine->nullValue();
+ }
+
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(Document::prototype(engine));
+ Node documentNode;
+ documentNode.d = document;
+ return engine->newVariant(instance, QVariant::fromValue(documentNode));
+}
+
+Node::Node()
+: d(0)
+{
+}
+
+Node::Node(const Node &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+Node::~Node()
+{
+ if (d) D(d);
+}
+
+bool Node::isNull() const
+{
+ return d == 0;
+}
+
+QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
+ if (map.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(map.list->count());
+}
+
+QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NamedNodeMap::prototype(engine));
+
+ NamedNodeMap map;
+ map.d = data;
+ map.list = list;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(QVariant::fromValue(map)));
+
+ if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass)
+ QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
+
+ instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass);
+
+ return instance;
+}
+
+NamedNodeMap::NamedNodeMap()
+: d(0), list(0)
+{
+}
+
+NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
+: d(o.d), list(o.list)
+{
+ if (d) A(d);
+}
+
+NamedNodeMap::~NamedNodeMap()
+{
+ if (d) D(d);
+}
+
+bool NamedNodeMap::isNull()
+{
+ return d == 0;
+}
+
+QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+ if (list.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(list.d->children.count());
+}
+
+QScriptValue NodeList::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NodeList::prototype(engine));
+
+ NodeList list;
+ list.d = data;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(QVariant::fromValue(list)));
+
+ if (!QDeclarativeScriptEngine::get(engine)->nodeListClass)
+ QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine);
+
+ instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass);
+
+ return instance;
+}
+
+NodeList::NodeList()
+: d(0)
+{
+}
+
+NodeList::NodeList(const NodeList &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+NodeList::~NodeList()
+{
+ if (d) D(d);
+}
+
+bool NodeList::isNull()
+{
+ return d == 0;
+}
+
+NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ Q_ASSERT(!map.isNull());
+
+ bool ok = false;
+ QString nameString = name.toString();
+ uint index = nameString.toUInt(&ok);
+ if (ok) {
+ if ((uint)map.list->count() <= index)
+ return 0;
+
+ *id = index;
+ return HandlesReadAccess;
+ } else {
+ for (int ii = 0; ii < map.list->count(); ++ii) {
+ if (map.list->at(ii) && map.list->at(ii)->name == nameString) {
+ *id = ii;
+ return HandlesReadAccess;
+ }
+ }
+ }
+
+ return 0;
+}
+
+QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ return Node::create(engine(), map.list->at(id));
+}
+
+NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ bool ok = false;
+ uint index = name.toString().toUInt(&ok);
+ if (!ok)
+ return 0;
+
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ if (list.isNull() || (uint)list.d->children.count() <= index)
+ return 0; // ### I think we're meant to raise an exception
+
+ *id = index;
+ return HandlesReadAccess;
+}
+
+QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ return Node::create(engine(), list.d->children.at(id));
+}
+
+QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+{
+ Node document = qscriptvalue_cast<Node>(context->thisObject());
+ if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+ return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root);
+}
+
+QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+{
+ Node document = qscriptvalue_cast<Node>(context->thisObject());
+ if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+ return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone);
+}
+
+QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+{
+ Node document = qscriptvalue_cast<Node>(context->thisObject());
+ if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+ return QScriptValue(static_cast<DocumentImpl *>(document.d)->version);
+}
+
+QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+{
+ Node document = qscriptvalue_cast<Node>(context->thisObject());
+ if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+
+ return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding);
+}
+
+class QDeclarativeXMLHttpRequest : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Unsent = 0,
+ Opened = 1, HeadersReceived = 2,
+ Loading = 3, Done = 4 };
+
+ QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager);
+ virtual ~QDeclarativeXMLHttpRequest();
+
+ bool sendFlag() const;
+ bool errorFlag() const;
+ quint32 readyState() const;
+ int replyStatus() const;
+ QString replyStatusText() const;
+
+ QScriptValue open(QScriptValue *me, const QString &, const QUrl &);
+
+ void addHeader(const QString &, const QString &);
+ QString header(const QString &name);
+ QString headers();
+ QScriptValue send(QScriptValue *me, const QByteArray &);
+ QScriptValue abort(QScriptValue *me);
+
+ QString responseBody();
+ const QByteArray & rawResponseBody() const;
+ bool receivedXml() const;
+private slots:
+ void downloadProgress(qint64);
+ void error(QNetworkReply::NetworkError);
+ void finished();
+
+private:
+ void requestFromUrl(const QUrl &url);
+
+ State m_state;
+ bool m_errorFlag;
+ bool m_sendFlag;
+ QString m_method;
+ QUrl m_url;
+ QByteArray m_responseEntityBody;
+ QByteArray m_data;
+ int m_redirectCount;
+
+ typedef QPair<QByteArray, QByteArray> HeaderPair;
+ typedef QList<HeaderPair> HeadersList;
+ HeadersList m_headersList;
+ void fillHeadersList();
+
+ bool m_gotXml;
+ QByteArray m_mime;
+ QByteArray m_charset;
+ QTextCodec *m_textCodec;
+#ifndef QT_NO_TEXTCODEC
+ QTextCodec* findTextCodec() const;
+#endif
+ void readEncoding();
+
+ QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback)
+
+ QScriptValue dispatchCallback(QScriptValue *me);
+ void printError(const QScriptValue&);
+
+ int m_status;
+ QString m_statusText;
+ QNetworkRequest m_request;
+ QDeclarativeGuard<QNetworkReply> m_network;
+ void destroyNetwork();
+
+ QNetworkAccessManager *m_nam;
+ QNetworkAccessManager *networkAccessManager() { return m_nam; }
+};
+
+QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager)
+: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
+ m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
+{
+}
+
+QDeclarativeXMLHttpRequest::~QDeclarativeXMLHttpRequest()
+{
+ destroyNetwork();
+}
+
+bool QDeclarativeXMLHttpRequest::sendFlag() const
+{
+ return m_sendFlag;
+}
+
+bool QDeclarativeXMLHttpRequest::errorFlag() const
+{
+ return m_errorFlag;
+}
+
+quint32 QDeclarativeXMLHttpRequest::readyState() const
+{
+ return m_state;
+}
+
+int QDeclarativeXMLHttpRequest::replyStatus() const
+{
+ return m_status;
+}
+
+QString QDeclarativeXMLHttpRequest::replyStatusText() const
+{
+ return m_statusText;
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url)
+{
+ destroyNetwork();
+ m_sendFlag = false;
+ m_errorFlag = false;
+ m_responseEntityBody = QByteArray();
+ m_method = method;
+ m_url = url;
+ m_state = Opened;
+ return dispatchCallback(me);
+}
+
+void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value)
+{
+ QByteArray utfname = name.toUtf8();
+
+ if (m_request.hasRawHeader(utfname)) {
+ m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8());
+ } else {
+ m_request.setRawHeader(utfname, value.toUtf8());
+ }
+}
+
+QString QDeclarativeXMLHttpRequest::header(const QString &name)
+{
+ QByteArray utfname = name.toLower().toUtf8();
+
+ foreach (const HeaderPair &header, m_headersList) {
+ if (header.first == utfname)
+ return QString::fromUtf8(header.second);
+ }
+ return QString();
+}
+
+QString QDeclarativeXMLHttpRequest::headers()
+{
+ QString ret;
+
+ foreach (const HeaderPair &header, m_headersList) {
+ if (ret.length())
+ ret.append(QLatin1String("\r\n"));
+ ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ")
+ % QString::fromUtf8(header.second);
+ }
+ return ret;
+}
+
+void QDeclarativeXMLHttpRequest::fillHeadersList()
+{
+ QList<QByteArray> headerList = m_network->rawHeaderList();
+
+ m_headersList.clear();
+ foreach (const QByteArray &header, headerList) {
+ HeaderPair pair (header.toLower(), m_network->rawHeader(header));
+ if (pair.first == "set-cookie" ||
+ pair.first == "set-cookie2")
+ continue;
+
+ m_headersList << pair;
+ }
+}
+
+void QDeclarativeXMLHttpRequest::requestFromUrl(const QUrl &url)
+{
+ QNetworkRequest request = m_request;
+ request.setUrl(url);
+ if(m_method == QLatin1String("POST") ||
+ m_method == QLatin1String("PUT")) {
+ QVariant var = request.header(QNetworkRequest::ContentTypeHeader);
+ if (var.isValid()) {
+ QString str = var.toString();
+ int charsetIdx = str.indexOf(QLatin1String("charset="));
+ if (charsetIdx == -1) {
+ // No charset - append
+ if (!str.isEmpty()) str.append(QLatin1Char(';'));
+ str.append(QLatin1String("charset=UTF-8"));
+ } else {
+ charsetIdx += 8;
+ int n = 0;
+ int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
+ if (semiColon == -1) {
+ n = str.length() - charsetIdx;
+ } else {
+ n = semiColon - charsetIdx;
+ }
+
+ str.replace(charsetIdx, n, QLatin1String("UTF-8"));
+ }
+ request.setHeader(QNetworkRequest::ContentTypeHeader, str);
+ } else {
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QLatin1String("text/plain;charset=UTF-8"));
+ }
+ }
+
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << " " << qPrintable(url.toString());
+ if (!m_data.isEmpty()) {
+ qWarning().nospace() << " "
+ << qPrintable(QString::fromUtf8(m_data));
+ }
+ }
+
+ if (m_method == QLatin1String("GET"))
+ m_network = networkAccessManager()->get(request);
+ else if (m_method == QLatin1String("HEAD"))
+ m_network = networkAccessManager()->head(request);
+ else if(m_method == QLatin1String("POST"))
+ m_network = networkAccessManager()->post(request, m_data);
+ else if(m_method == QLatin1String("PUT"))
+ m_network = networkAccessManager()->put(request, m_data);
+
+ QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(downloadProgress(qint64)));
+ QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(error(QNetworkReply::NetworkError)));
+ QObject::connect(m_network, SIGNAL(finished()),
+ this, SLOT(finished()));
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data)
+{
+ m_errorFlag = false;
+ m_sendFlag = true;
+ m_redirectCount = 0;
+ m_data = data;
+ m_me = *me;
+
+ requestFromUrl(m_url);
+
+ return QScriptValue();
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
+{
+ destroyNetwork();
+ m_responseEntityBody = QByteArray();
+ m_errorFlag = true;
+ m_request = QNetworkRequest();
+
+ if (!(m_state == Unsent ||
+ (m_state == Opened && !m_sendFlag) ||
+ m_state == Done)) {
+
+ m_state = Done;
+ m_sendFlag = false;
+ QScriptValue cbv = dispatchCallback(me);
+ if (cbv.isError()) return cbv;
+ }
+
+ m_state = Unsent;
+ return QScriptValue();
+}
+
+void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
+{
+ Q_UNUSED(bytes)
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ // ### We assume if this is called the headers are now available
+ if (m_state < HeadersReceived) {
+ m_state = HeadersReceived;
+ fillHeadersList ();
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+ }
+
+ bool wasEmpty = m_responseEntityBody.isEmpty();
+ m_responseEntityBody.append(m_network->readAll());
+ if (wasEmpty && !m_responseEntityBody.isEmpty()) {
+ m_state = Loading;
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+ }
+}
+
+void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
+{
+ Q_UNUSED(error)
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ m_responseEntityBody = QByteArray();
+
+ m_request = QNetworkRequest();
+ m_data.clear();
+ destroyNetwork();
+
+ if (error == QNetworkReply::ContentAccessDenied ||
+ error == QNetworkReply::ContentOperationNotPermittedError ||
+ error == QNetworkReply::ContentNotFoundError ||
+ error == QNetworkReply::AuthenticationRequiredError ||
+ error == QNetworkReply::ContentReSendError) {
+ m_state = Loading;
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+ } else {
+ m_errorFlag = true;
+ }
+
+ m_state = Done;
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+}
+
+#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
+void QDeclarativeXMLHttpRequest::finished()
+{
+ m_redirectCount++;
+ if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = m_network->url().resolved(redirect.toUrl());
+ destroyNetwork();
+ requestFromUrl(url);
+ return;
+ }
+ }
+
+ m_status =
+ m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ m_statusText =
+ QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray());
+
+ if (m_state < HeadersReceived) {
+ m_state = HeadersReceived;
+ fillHeadersList ();
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+ }
+ m_responseEntityBody.append(m_network->readAll());
+ readEncoding();
+
+ if (xhrDump()) {
+ qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString());
+ if (!m_responseEntityBody.isEmpty()) {
+ qWarning().nospace() << " "
+ << qPrintable(QString::fromUtf8(m_responseEntityBody));
+ }
+ }
+
+
+ m_data.clear();
+ destroyNetwork();
+ if (m_state < Loading) {
+ m_state = Loading;
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+ }
+ m_state = Done;
+ QScriptValue cbv = dispatchCallback(&m_me);
+ if (cbv.isError()) printError(cbv);
+
+ m_me = QScriptValue();
+}
+
+
+void QDeclarativeXMLHttpRequest::readEncoding()
+{
+ foreach (const HeaderPair &header, m_headersList) {
+ if (header.first == "content-type") {
+ int separatorIdx = header.second.indexOf(';');
+ if (separatorIdx == -1) {
+ m_mime == header.second;
+ } else {
+ m_mime = header.second.mid(0, separatorIdx);
+ int charsetIdx = header.second.indexOf("charset=");
+ if (charsetIdx != -1) {
+ charsetIdx += 8;
+ separatorIdx = header.second.indexOf(';', charsetIdx);
+ m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length());
+ }
+ }
+ break;
+ }
+ }
+
+ if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml"))
+ m_gotXml = true;
+}
+
+bool QDeclarativeXMLHttpRequest::receivedXml() const
+{
+ return m_gotXml;
+}
+
+
+#ifndef QT_NO_TEXTCODEC
+QTextCodec* QDeclarativeXMLHttpRequest::findTextCodec() const
+{
+ QTextCodec *codec = 0;
+
+ if (!m_charset.isEmpty())
+ codec = QTextCodec::codecForName(m_charset);
+
+ if (!codec && m_gotXml) {
+ QXmlStreamReader reader(m_responseEntityBody);
+ reader.readNext();
+ codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
+ }
+
+ if (!codec && m_mime == "text/html")
+ codec = QTextCodec::codecForHtml(m_responseEntityBody, 0);
+
+ if (!codec)
+ codec = QTextCodec::codecForUtfText(m_responseEntityBody, 0);
+
+ if (!codec)
+ codec = QTextCodec::codecForName("UTF-8");
+ return codec;
+}
+#endif
+
+
+QString QDeclarativeXMLHttpRequest::responseBody()
+{
+#ifndef QT_NO_TEXTCODEC
+ if (!m_textCodec)
+ m_textCodec = findTextCodec();
+ if (m_textCodec)
+ return m_textCodec->toUnicode(m_responseEntityBody);
+#endif
+
+ return QString::fromUtf8(m_responseEntityBody);
+}
+
+const QByteArray &QDeclarativeXMLHttpRequest::rawResponseBody() const
+{
+ return m_responseEntityBody;
+}
+
+QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me)
+{
+ QScriptValue v = me->property(QLatin1String("callback"));
+ return v.call();
+}
+
+void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv)
+{
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error);
+ QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error);
+}
+
+void QDeclarativeXMLHttpRequest::destroyNetwork()
+{
+ if (m_network) {
+ m_network->disconnect();
+ m_network->deleteLater();
+ m_network = 0;
+ }
+}
+
+// XMLHttpRequest methods
+static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine)
+{
+ QScriptValue dataObject = context->thisObject().data();
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (context->argumentCount() < 2 || context->argumentCount() > 5)
+ THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+ // Argument 0 - Method
+ QString method = context->argument(0).toString().toUpper();
+ if (method != QLatin1String("GET") &&
+ method != QLatin1String("PUT") &&
+ method != QLatin1String("HEAD") &&
+ method != QLatin1String("POST"))
+ THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
+
+
+ // Argument 1 - URL
+ QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8());
+
+ if (url.isRelative()) {
+ url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url);
+ }
+
+ // Argument 2 - async (optional)
+ if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
+ THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
+
+
+ // Argument 3/4 - user/pass (optional)
+ QString username, password;
+ if (context->argumentCount() > 3)
+ username = context->argument(3).toString();
+ if (context->argumentCount() > 4)
+ password = context->argument(4).toString();
+
+
+ // Clear the fragment (if any)
+ url.setFragment(QString());
+ // Set username/password
+ if (!username.isNull()) url.setUserName(username);
+ if (!password.isNull()) url.setPassword(password);
+
+ return request->open(&dataObject, method, url);
+}
+
+static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (context->argumentCount() != 2)
+ THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+
+ if (request->readyState() != QDeclarativeXMLHttpRequest::Opened ||
+ request->sendFlag())
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+
+ QString name = context->argument(0).toString();
+ QString value = context->argument(1).toString();
+
+ // ### Check that name and value are well formed
+
+ QString nameUpper = name.toUpper();
+ if (nameUpper == QLatin1String("ACCEPT-CHARSET") ||
+ nameUpper == QLatin1String("ACCEPT-ENCODING") ||
+ nameUpper == QLatin1String("CONNECTION") ||
+ nameUpper == QLatin1String("CONTENT-LENGTH") ||
+ nameUpper == QLatin1String("COOKIE") ||
+ nameUpper == QLatin1String("COOKIE2") ||
+ nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") ||
+ nameUpper == QLatin1String("DATE") ||
+ nameUpper == QLatin1String("EXPECT") ||
+ nameUpper == QLatin1String("HOST") ||
+ nameUpper == QLatin1String("KEEP-ALIVE") ||
+ nameUpper == QLatin1String("REFERER") ||
+ nameUpper == QLatin1String("TE") ||
+ nameUpper == QLatin1String("TRAILER") ||
+ nameUpper == QLatin1String("TRANSFER-ENCODING") ||
+ nameUpper == QLatin1String("UPGRADE") ||
+ nameUpper == QLatin1String("USER-AGENT") ||
+ nameUpper == QLatin1String("VIA") ||
+ nameUpper.startsWith(QLatin1String("PROXY-")) ||
+ nameUpper.startsWith(QLatin1String("SEC-")))
+ return engine->undefinedValue();
+
+ request->addHeader(nameUpper, value);
+
+ return engine->undefinedValue();
+}
+
+static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *)
+{
+ QScriptValue dataObject = context->thisObject().data();
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (request->readyState() != QDeclarativeXMLHttpRequest::Opened)
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ if (request->sendFlag())
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ QByteArray data;
+ if (context->argumentCount() > 0)
+ data = context->argument(0).toString().toUtf8();
+
+ return request->send(&dataObject, data);
+}
+
+static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *)
+{
+ QScriptValue dataObject = context->thisObject().data();
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ return request->abort(&dataObject);
+}
+
+static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (context->argumentCount() != 1)
+ THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+ if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ request->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ QString headerName = context->argument(0).toString();
+
+ return QScriptValue(request->header(headerName));
+}
+
+static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (context->argumentCount() != 0)
+ THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+ if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ request->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ return QScriptValue(request->headers());
+}
+
+// XMLHttpRequest properties
+static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ return QScriptValue(request->readyState());
+}
+
+static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ request->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ if (request->errorFlag())
+ return QScriptValue(0);
+ else
+ return QScriptValue(request->replyStatus());
+}
+
+static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ request->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ if (request->errorFlag())
+ return QScriptValue(0);
+ else
+ return QScriptValue(request->replyStatusText());
+}
+
+static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine)
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ request->readyState() != QDeclarativeXMLHttpRequest::Done)
+ return QScriptValue(QString());
+ else
+ return QScriptValue(request->responseBody());
+}
+
+static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+{
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (!request->receivedXml() ||
+ (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ request->readyState() != QDeclarativeXMLHttpRequest::Done))
+ return engine->nullValue();
+ else
+ return Document::load(engine, request->rawResponseBody());
+}
+
+static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
+{
+ Q_UNUSED(engine);
+ QScriptValue dataObject = context->thisObject().data();
+ QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
+ if (!request)
+ THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ if (context->argumentCount()) {
+ QScriptValue v = context->argument(0);
+ dataObject.setProperty(QLatin1String("callback"), v);
+ return v;
+ } else {
+ return dataObject.property(QLatin1String("callback"));
+ }
+}
+
+// Constructor
+static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
+{
+ if (context->isCalledAsConstructor()) {
+ context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership));
+ }
+ return engine->undefinedValue();
+}
+
+void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
+{
+ QScriptValue prototype = engine->newObject();
+
+ // Methods
+ prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
+ prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
+ prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send));
+ prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort));
+ prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1));
+ prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders));
+
+ // Read-only properties
+ prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+
+ // State values
+ prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+
+ // Constructor
+ QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
+ constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
+
+ // DOM Exception
+ QScriptValue domExceptionPrototype = engine->newObject();
+ domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+
+ engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_XMLSTREAMREADER
+
+#include <qdeclarativexmlhttprequest.moc>
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest_p.h b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
new file mode 100644
index 0000000000..7863035842
--- /dev/null
+++ b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEXMLHTTPREQUEST_P_H
+#define QDECLARATIVEXMLHTTPREQUEST_P_H
+
+#include <QtScript/qscriptengine.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>
+
+#ifndef QT_NO_XMLSTREAMREADER
+
+QT_BEGIN_NAMESPACE
+
+class QScriptEngine;
+void qt_add_qmlxmlhttprequest(QScriptEngine *engine);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_XMLSTREAMREADER
+
+#endif // QDECLARATIVEXMLHTTPREQUEST_P_H
+
diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp
new file mode 100644
index 0000000000..dc941e2601
--- /dev/null
+++ b/src/declarative/qml/qmetaobjectbuilder.cpp
@@ -0,0 +1,2544 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qmetaobjectbuilder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMetaObjectBuilder
+ \internal
+ \brief The QMetaObjectBuilder class supports building QMetaObject objects at runtime.
+
+*/
+
+/*!
+ \enum QMetaObjectBuilder::AddMember
+ This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject()
+
+ \value ClassName Add the class name.
+ \value SuperClass Add the super class.
+ \value Methods Add methods that aren't signals or slots.
+ \value Signals Add signals.
+ \value Slots Add slots.
+ \value Constructors Add constructors.
+ \value Properties Add properties.
+ \value Enumerators Add enumerators.
+ \value ClassInfos Add items of class information.
+ \value RelatedMetaObjects Add related meta objects.
+ \value StaticMetacall Add the static metacall function.
+ \value PublicMethods Add public methods (ignored for signals).
+ \value ProtectedMethods Add protected methods (ignored for signals).
+ \value PrivateMethods All private methods (ignored for signals).
+ \value AllMembers Add all members.
+ \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function.
+*/
+
+// copied from moc's generator.cpp
+uint qvariant_nameToType(const char* name)
+{
+ if (!name)
+ return 0;
+
+ if (strcmp(name, "QVariant") == 0)
+ return 0xffffffff;
+ if (strcmp(name, "QCString") == 0)
+ return QMetaType::QByteArray;
+ if (strcmp(name, "Q_LLONG") == 0)
+ return QMetaType::LongLong;
+ if (strcmp(name, "Q_ULLONG") == 0)
+ return QMetaType::ULongLong;
+ if (strcmp(name, "QIconSet") == 0)
+ return QMetaType::QIcon;
+
+ uint tp = QMetaType::type(name);
+ return tp < QMetaType::User ? tp : 0;
+}
+
+/*
+ Returns true if the type is a QVariant types.
+*/
+bool isVariantType(const char* type)
+{
+ return qvariant_nameToType(type) != 0;
+}
+
+// copied from qmetaobject.cpp
+// do not touch without touching the moc as well
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ Notify = 0x00400000,
+ Revisioned = 0x00800000
+};
+
+enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodConstructor = 0x0c,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40,
+ MethodRevisioned = 0x80
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+};
+
+static inline const QMetaObjectPrivate *priv(const uint* data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+// end of copied lines from qmetaobject.cpp
+
+class QMetaMethodBuilderPrivate
+{
+public:
+ QMetaMethodBuilderPrivate
+ (QMetaMethod::MethodType _methodType,
+ const QByteArray& _signature,
+ const QByteArray& _returnType = QByteArray(),
+ QMetaMethod::Access _access = QMetaMethod::Public)
+ : signature(QMetaObject::normalizedSignature(_signature.constData())),
+ returnType(QMetaObject::normalizedType(_returnType)),
+ attributes(((int)_access) | (((int)_methodType) << 2))
+ {
+ }
+
+ QByteArray signature;
+ QByteArray returnType;
+ QList<QByteArray> parameterNames;
+ QByteArray tag;
+ int attributes;
+
+ QMetaMethod::MethodType methodType() const
+ {
+ return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2);
+ }
+
+ QMetaMethod::Access access() const
+ {
+ return (QMetaMethod::Access)(attributes & AccessMask);
+ }
+
+ void setAccess(QMetaMethod::Access value)
+ {
+ attributes = ((attributes & ~AccessMask) | (int)value);
+ }
+};
+
+class QMetaPropertyBuilderPrivate
+{
+public:
+ QMetaPropertyBuilderPrivate
+ (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1)
+ : name(_name),
+ type(QMetaObject::normalizedType(_type.constData())),
+ flags(Readable | Writable | Scriptable), notifySignal(-1)
+ {
+ if (notifierIdx >= 0) {
+ flags |= Notify;
+ notifySignal = notifierIdx;
+ }
+ }
+
+ QByteArray name;
+ QByteArray type;
+ int flags;
+ int notifySignal;
+
+ bool flag(int f) const
+ {
+ return ((flags & f) != 0);
+ }
+
+ void setFlag(int f, bool value)
+ {
+ if (value)
+ flags |= f;
+ else
+ flags &= ~f;
+ }
+};
+
+class QMetaEnumBuilderPrivate
+{
+public:
+ QMetaEnumBuilderPrivate(const QByteArray& _name)
+ : name(_name), isFlag(false)
+ {
+ }
+
+ QByteArray name;
+ bool isFlag;
+ QList<QByteArray> keys;
+ QList<int> values;
+};
+
+class QMetaObjectBuilderPrivate
+{
+public:
+ QMetaObjectBuilderPrivate()
+ : flags(0)
+ {
+ superClass = &QObject::staticMetaObject;
+ staticMetacallFunction = 0;
+ }
+
+ QByteArray className;
+ const QMetaObject *superClass;
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction;
+ QList<QMetaMethodBuilderPrivate> methods;
+ QList<QMetaMethodBuilderPrivate> constructors;
+ QList<QMetaPropertyBuilderPrivate> properties;
+ QList<QByteArray> classInfoNames;
+ QList<QByteArray> classInfoValues;
+ QList<QMetaEnumBuilderPrivate> enumerators;
+#ifdef Q_NO_DATA_RELOCATION
+ QList<QMetaObjectAccessor> relatedMetaObjects;
+#else
+ QList<const QMetaObject *> relatedMetaObjects;
+#endif
+ int flags;
+};
+
+/*!
+ Constructs a new QMetaObjectBuilder.
+*/
+QMetaObjectBuilder::QMetaObjectBuilder()
+{
+ d = new QMetaObjectBuilderPrivate();
+}
+
+/*!
+ Constructs a new QMetaObjectBuilder which is a copy of the
+ meta object information in \a prototype. Note: the super class
+ contents for \a prototype are not copied, only the immediate
+ class that is defined by \a prototype.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+
+ \sa addMetaObject()
+*/
+QMetaObjectBuilder::QMetaObjectBuilder
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ d = new QMetaObjectBuilderPrivate();
+ addMetaObject(prototype, members);
+}
+
+/*!
+ Destroys this meta object builder.
+*/
+QMetaObjectBuilder::~QMetaObjectBuilder()
+{
+ delete d;
+}
+
+/*!
+ Returns the name of the class being constructed by this
+ meta object builder. The default value is an empty QByteArray.
+
+ \sa setClassName(), superClass()
+*/
+QByteArray QMetaObjectBuilder::className() const
+{
+ return d->className;
+}
+
+/*!
+ Sets the \a name of the class being constructed by this
+ meta object builder.
+
+ \sa className(), setSuperClass()
+*/
+void QMetaObjectBuilder::setClassName(const QByteArray& name)
+{
+ d->className = name;
+}
+
+/*!
+ Returns the superclass meta object of the class being constructed
+ by this meta object builder. The default value is the meta object
+ for QObject.
+
+ \sa setSuperClass(), className()
+*/
+const QMetaObject *QMetaObjectBuilder::superClass() const
+{
+ return d->superClass;
+}
+
+/*!
+ Sets the superclass meta object of the class being constructed
+ by this meta object builder to \a meta. The \a meta parameter
+ must not be null.
+
+ \sa superClass(), setClassName()
+*/
+void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta)
+{
+ Q_ASSERT(meta);
+ d->superClass = meta;
+}
+
+/*!
+ Returns the flags of the class being constructed by this meta object
+ builder.
+
+ \sa setFlags()
+*/
+QMetaObjectBuilder::MetaObjectFlags QMetaObjectBuilder::flags() const
+{
+ return (QMetaObjectBuilder::MetaObjectFlags)d->flags;
+}
+
+/*!
+ Sets the \a flags of the class being constructed by this meta object
+ builder.
+
+ \sa flags()
+*/
+void QMetaObjectBuilder::setFlags(MetaObjectFlags flags)
+{
+ d->flags = flags;
+}
+
+/*!
+ Returns the number of methods in this class, excluding the number
+ of methods in the base class. These include signals and slots
+ as well as normal member functions.
+
+ \sa addMethod(), method(), removeMethod(), indexOfMethod()
+*/
+int QMetaObjectBuilder::methodCount() const
+{
+ return d->methods.size();
+}
+
+/*!
+ Returns the number of constructors in this class.
+
+ \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor()
+*/
+int QMetaObjectBuilder::constructorCount() const
+{
+ return d->constructors.size();
+}
+
+/*!
+ Returns the number of properties in this class, excluding the number
+ of properties in the base class.
+
+ \sa addProperty(), property(), removeProperty(), indexOfProperty()
+*/
+int QMetaObjectBuilder::propertyCount() const
+{
+ return d->properties.size();
+}
+
+/*!
+ Returns the number of enumerators in this class, excluding the
+ number of enumerators in the base class.
+
+ \sa addEnumerator(), enumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+int QMetaObjectBuilder::enumeratorCount() const
+{
+ return d->enumerators.size();
+}
+
+/*!
+ Returns the number of items of class information in this class,
+ exclusing the number of items of class information in the base class.
+
+ \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::classInfoCount() const
+{
+ return d->classInfoNames.size();
+}
+
+/*!
+ Returns the number of related meta objects that are associated
+ with this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa addRelatedMetaObject(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+int QMetaObjectBuilder::relatedMetaObjectCount() const
+{
+ return d->relatedMetaObjects.size();
+}
+
+/*!
+ Adds a new public method to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the method. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class with the specified
+ \a signature and \a returnType. Returns an object that can be
+ used to adjust the other attributes of the method. The \a signature
+ and \a returnType will be normalized before they are added to
+ the class. If \a returnType is empty, then it indicates that
+ the method has \c{void} as its return type.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod
+ (const QByteArray& signature, const QByteArray& returnType)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Method, signature, returnType));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class that has the same information as
+ \a prototype. This is used to clone the methods of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the method.
+
+ This function will detect if \a prototype is an ordinary method,
+ signal, slot, or constructor and act accordingly.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype)
+{
+ QMetaMethodBuilder method;
+ if (prototype.methodType() == QMetaMethod::Method)
+ method = addMethod(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Signal)
+ method = addSignal(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Slot)
+ method = addSlot(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Constructor)
+ method = addConstructor(prototype.signature());
+ method.setReturnType(prototype.typeName());
+ method.setParameterNames(prototype.parameterNames());
+ method.setTag(prototype.tag());
+ method.setAccess(prototype.access());
+ method.setAttributes(prototype.attributes());
+ return method;
+}
+
+/*!
+ Adds a new public slot to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the slot. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSignal(), indexOfSlot()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new signal to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the signal. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSlot(), indexOfSignal()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new constructor to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the constructor. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature)
+{
+ int index = d->constructors.size();
+ d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature));
+ return QMetaMethodBuilder(this, -(index + 1));
+}
+
+/*!
+ Adds a new constructor to this class that has the same information as
+ \a prototype. This is used to clone the constructors of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the constructor.
+
+ This function requires that \a prototype be a constructor.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype)
+{
+ Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor);
+ QMetaMethodBuilder ctor = addConstructor(prototype.signature());
+ ctor.setReturnType(prototype.typeName());
+ ctor.setParameterNames(prototype.parameterNames());
+ ctor.setTag(prototype.tag());
+ ctor.setAccess(prototype.access());
+ ctor.setAttributes(prototype.attributes());
+ return ctor;
+}
+
+/*!
+ Adds a new readable/writable property to this class with the
+ specified \a name and \a type. Returns an object that can be used
+ to adjust the other attributes of the property. The \a type will
+ be normalized before it is added to the class. \a notifierId will
+ be registered as the property's \e notify signal.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty
+ (const QByteArray& name, const QByteArray& type, int notifierId)
+{
+ int index = d->properties.size();
+ d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId));
+ return QMetaPropertyBuilder(this, index);
+}
+
+/*!
+ Adds a new property to this class that has the same information as
+ \a prototype. This is used to clone the properties of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the property.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype)
+{
+ QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName());
+ property.setReadable(prototype.isReadable());
+ property.setWritable(prototype.isWritable());
+ property.setResettable(prototype.isResettable());
+ property.setDesignable(prototype.isDesignable());
+ property.setScriptable(prototype.isScriptable());
+ property.setStored(prototype.isStored());
+ property.setEditable(prototype.isEditable());
+ property.setUser(prototype.isUser());
+ property.setStdCppSet(prototype.hasStdCppSet());
+ property.setEnumOrFlag(prototype.isEnumType());
+ if (prototype.hasNotifySignal()) {
+ // Find an existing method for the notify signal, or add a new one.
+ QMetaMethod method = prototype.notifySignal();
+ int index = indexOfMethod(method.signature());
+ if (index == -1)
+ index = addMethod(method).index();
+ d->properties[property._index].notifySignal = index;
+ d->properties[property._index].setFlag(Notify, true);
+ }
+ return property;
+}
+
+/*!
+ Adds a new enumerator to this class with the specified
+ \a name. Returns an object that can be used to adjust
+ the other attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name)
+{
+ int index = d->enumerators.size();
+ d->enumerators.append(QMetaEnumBuilderPrivate(name));
+ return QMetaEnumBuilder(this, index);
+}
+
+/*!
+ Adds a new enumerator to this class that has the same information as
+ \a prototype. This is used to clone the enumerators of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
+{
+ QMetaEnumBuilder en = addEnumerator(prototype.name());
+ en.setIsFlag(prototype.isFlag());
+ int count = prototype.keyCount();
+ for (int index = 0; index < count; ++index)
+ en.addKey(prototype.key(index), prototype.value(index));
+ return en;
+}
+
+/*!
+ Adds \a name and \a value as an item of class information to this class.
+ Returns the index of the new item of class information.
+
+ \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value)
+{
+ int index = d->classInfoNames.size();
+ d->classInfoNames += name;
+ d->classInfoValues += value;
+ return index;
+}
+
+/*!
+ Adds \a meta to this class as a related meta object. Returns
+ the index of the new related meta object entry.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+#ifdef Q_NO_DATA_RELOCATION
+int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObjectAccessor &meta)
+#else
+int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta)
+#endif
+{
+ Q_ASSERT(meta);
+ int index = d->relatedMetaObjects.size();
+ d->relatedMetaObjects.append(meta);
+ return index;
+}
+
+/*!
+ Adds the contents of \a prototype to this meta object builder.
+ This function is useful for cloning the contents of an existing QMetaObject.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+*/
+void QMetaObjectBuilder::addMetaObject
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ Q_ASSERT(prototype);
+ int index;
+
+ if ((members & ClassName) != 0)
+ d->className = prototype->className();
+
+ if ((members & SuperClass) != 0)
+ d->superClass = prototype->superClass();
+
+ if ((members & (Methods | Signals | Slots)) != 0) {
+ for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) {
+ QMetaMethod method = prototype->method(index);
+ if (method.methodType() != QMetaMethod::Signal) {
+ if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0)
+ continue;
+ }
+ if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Signal &&
+ (members & Signals) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Slot &&
+ (members & Slots) != 0) {
+ addMethod(method);
+ }
+ }
+ }
+
+ if ((members & Constructors) != 0) {
+ for (index = 0; index < prototype->constructorCount(); ++index)
+ addConstructor(prototype->constructor(index));
+ }
+
+ if ((members & Properties) != 0) {
+ for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index)
+ addProperty(prototype->property(index));
+ }
+
+ if ((members & Enumerators) != 0) {
+ for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index)
+ addEnumerator(prototype->enumerator(index));
+ }
+
+ if ((members & ClassInfos) != 0) {
+ for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) {
+ QMetaClassInfo ci = prototype->classInfo(index);
+ addClassInfo(ci.name(), ci.value());
+ }
+ }
+
+ if ((members & RelatedMetaObjects) != 0) {
+#ifdef Q_NO_DATA_RELOCATION
+ const QMetaObjectAccessor *objects = 0;
+#else
+ const QMetaObject **objects;
+ if (priv(prototype->d.data)->revision < 2) {
+ objects = (const QMetaObject **)(prototype->d.extradata);
+ } else
+#endif
+ {
+ const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra)
+ objects = extra->objects;
+ else
+ objects = 0;
+ }
+ if (objects) {
+ while (*objects != 0) {
+ addRelatedMetaObject(*objects);
+ ++objects;
+ }
+ }
+ }
+
+ if ((members & StaticMetacall) != 0) {
+ if (priv(prototype->d.data)->revision >= 6) {
+ const QMetaObjectExtraData *extra =
+ (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra && extra->static_metacall)
+ setStaticMetacallFunction(extra->static_metacall);
+ }
+ }
+}
+
+/*!
+ Returns the method at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::method(int index) const
+{
+ if (index >= 0 && index < d->methods.size())
+ return QMetaMethodBuilder(this, index);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the constructor at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const
+{
+ if (index >= 0 && index < d->constructors.size())
+ return QMetaMethodBuilder(this, -(index + 1));
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the property at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const
+{
+ if (index >= 0 && index < d->properties.size())
+ return QMetaPropertyBuilder(this, index);
+ else
+ return QMetaPropertyBuilder();
+}
+
+/*!
+ Returns the enumerator at \a index in this class.
+
+ \sa enumeratorCount(), addEnumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const
+{
+ if (index >= 0 && index < d->enumerators.size())
+ return QMetaEnumBuilder(this, index);
+ else
+ return QMetaEnumBuilder();
+}
+
+/*!
+ Returns the related meta object at \a index in this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+#ifdef Q_NO_DATA_RELOCATION
+ return &((*(d->relatedMetaObjects[index]))());
+#else
+ return d->relatedMetaObjects[index];
+#endif
+ else
+ return 0;
+}
+
+/*!
+ Returns the name of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoName(int index) const
+{
+ if (index >= 0 && index < d->classInfoNames.size())
+ return d->classInfoNames[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoValue(int index) const
+{
+ if (index >= 0 && index < d->classInfoValues.size())
+ return d->classInfoValues[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Removes the method at \a index from this class. The indices of
+ all following methods will be adjusted downwards by 1. If the
+ method is registered as a notify signal on a property, then the
+ notify signal will be removed from the property.
+
+ \sa methodCount(), addMethod(), method(), indexOfMethod()
+*/
+void QMetaObjectBuilder::removeMethod(int index)
+{
+ if (index >= 0 && index < d->methods.size()) {
+ d->methods.removeAt(index);
+ for (int prop = 0; prop < d->properties.size(); ++prop) {
+ // Adjust the indices of property notify signal references.
+ if (d->properties[prop].notifySignal == index) {
+ d->properties[prop].notifySignal = -1;
+ d->properties[prop].setFlag(Notify, false);
+ } else if (d->properties[prop].notifySignal > index)
+ (d->properties[prop].notifySignal)--;
+ }
+ }
+}
+
+/*!
+ Removes the constructor at \a index from this class. The indices of
+ all following constructors will be adjusted downwards by 1.
+
+ \sa constructorCount(), addConstructor(), constructor()
+ \sa indexOfConstructor()
+*/
+void QMetaObjectBuilder::removeConstructor(int index)
+{
+ if (index >= 0 && index < d->constructors.size())
+ d->constructors.removeAt(index);
+}
+
+/*!
+ Removes the property at \a index from this class. The indices of
+ all following properties will be adjusted downwards by 1.
+
+ \sa propertyCount(), addProperty(), property(), indexOfProperty()
+*/
+void QMetaObjectBuilder::removeProperty(int index)
+{
+ if (index >= 0 && index < d->properties.size())
+ d->properties.removeAt(index);
+}
+
+/*!
+ Removes the enumerator at \a index from this class. The indices of
+ all following enumerators will be adjusted downwards by 1.
+
+ \sa enumertorCount(), addEnumerator(), enumerator()
+ \sa indexOfEnumerator()
+*/
+void QMetaObjectBuilder::removeEnumerator(int index)
+{
+ if (index >= 0 && index < d->enumerators.size())
+ d->enumerators.removeAt(index);
+}
+
+/*!
+ Removes the item of class information at \a index from this class.
+ The indices of all following items will be adjusted downwards by 1.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue()
+ \sa indexOfClassInfo()
+*/
+void QMetaObjectBuilder::removeClassInfo(int index)
+{
+ if (index >= 0 && index < d->classInfoNames.size()) {
+ d->classInfoNames.removeAt(index);
+ d->classInfoValues.removeAt(index);
+ }
+}
+
+/*!
+ Removes the related meta object at \a index from this class.
+ The indices of all following related meta objects will be adjusted
+ downwards by 1.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa relatedMetaObject()
+*/
+void QMetaObjectBuilder::removeRelatedMetaObject(int index)
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+ d->relatedMetaObjects.removeAt(index);
+}
+
+/*!
+ Finds a method with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa method(), methodCount(), addMethod(), removeMethod()
+*/
+int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a signal with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSlot()
+*/
+int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Signal)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a slot with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSignal()
+*/
+int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Slot)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a constructor with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa constructor(), constructorCount(), addConstructor(), removeConstructor()
+*/
+int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->constructors.size(); ++index) {
+ if (sig == d->constructors[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a property with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa property(), propertyCount(), addProperty(), removeProperty()
+*/
+int QMetaObjectBuilder::indexOfProperty(const QByteArray& name)
+{
+ for (int index = 0; index < d->properties.size(); ++index) {
+ if (name == d->properties[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an enumerator with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator()
+*/
+int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name)
+{
+ for (int index = 0; index < d->enumerators.size(); ++index) {
+ if (name == d->enumerators[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an item of class information with the specified \a name and
+ returns its index; otherwise returns -1.
+
+ \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo()
+ \sa removeClassInfo()
+*/
+int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name)
+{
+ for (int index = 0; index < d->classInfoNames.size(); ++index) {
+ if (name == d->classInfoNames[index])
+ return index;
+ }
+ return -1;
+}
+
+// Align on a specific type boundary.
+#define ALIGN(size,type) \
+ (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1)
+
+// Build a string into a QMetaObject representation. Returns the
+// position in the string table where the string was placed.
+static int buildString
+ (char *buf, char *str, int *offset, const QByteArray& value, int empty)
+{
+ if (value.size() == 0 && empty >= 0)
+ return empty;
+ if (buf) {
+ memcpy(str + *offset, value.constData(), value.size());
+ str[*offset + value.size()] = '\0';
+ }
+ int posn = *offset;
+ *offset += value.size() + 1;
+ return posn;
+}
+
+// Build the parameter array string for a method.
+static QByteArray buildParameterNames
+ (const QByteArray& signature, const QList<QByteArray>& parameterNames)
+{
+ // If the parameter name list is specified, then concatenate them.
+ if (!parameterNames.isEmpty()) {
+ QByteArray names;
+ bool first = true;
+ foreach (const QByteArray &name, parameterNames) {
+ if (first)
+ first = false;
+ else
+ names += (char)',';
+ names += name;
+ }
+ return names;
+ }
+
+ // Count commas in the signature, excluding those inside template arguments.
+ int index = signature.indexOf('(');
+ if (index < 0)
+ return QByteArray();
+ ++index;
+ if (index >= signature.size())
+ return QByteArray();
+ if (signature[index] == ')')
+ return QByteArray();
+ int count = 1;
+ int brackets = 0;
+ while (index < signature.size() && signature[index] != ',') {
+ char ch = signature[index++];
+ if (ch == '<')
+ ++brackets;
+ else if (ch == '>')
+ --brackets;
+ else if (ch == ',' && brackets <= 0)
+ ++count;
+ }
+ return QByteArray(count - 1, ',');
+}
+
+// Build a QMetaObject in "buf" based on the information in "d".
+// If "buf" is null, then return the number of bytes needed to
+// build the QMetaObject. Returns -1 if the metaobject if
+// relocatable is set, but the metaobject contains extradata.
+static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
+ bool relocatable)
+{
+ int size = 0;
+ int dataIndex;
+ int enumIndex;
+ int index;
+ bool hasNotifySignals = false;
+
+ if (relocatable &&
+ (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction))
+ return -1;
+
+ // Create the main QMetaObject structure at the start of the buffer.
+ QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf);
+ size += sizeof(QMetaObject);
+ ALIGN(size, int);
+ if (buf) {
+ if (!relocatable) meta->d.superdata = d->superClass;
+ meta->d.extradata = 0;
+ }
+
+ // Populate the QMetaObjectPrivate structure.
+ QMetaObjectPrivate *pmeta
+ = reinterpret_cast<QMetaObjectPrivate *>(buf + size);
+ int pmetaSize = size;
+ dataIndex = 13; // Number of fields in the QMetaObjectPrivate.
+ for (index = 0; index < d->properties.size(); ++index) {
+ if (d->properties[index].notifySignal != -1) {
+ hasNotifySignals = true;
+ break;
+ }
+ }
+ if (buf) {
+ pmeta->revision = 3;
+ pmeta->flags = d->flags;
+ pmeta->className = 0; // Class name is always the first string.
+
+ pmeta->classInfoCount = d->classInfoNames.size();
+ pmeta->classInfoData = dataIndex;
+ dataIndex += 2 * d->classInfoNames.size();
+
+ pmeta->methodCount = d->methods.size();
+ pmeta->methodData = dataIndex;
+ dataIndex += 5 * d->methods.size();
+
+ pmeta->propertyCount = d->properties.size();
+ pmeta->propertyData = dataIndex;
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+
+ pmeta->enumeratorCount = d->enumerators.size();
+ pmeta->enumeratorData = dataIndex;
+ dataIndex += 4 * d->enumerators.size();
+
+ pmeta->constructorCount = d->constructors.size();
+ pmeta->constructorData = dataIndex;
+ dataIndex += 5 * d->constructors.size();
+ } else {
+ dataIndex += 2 * d->classInfoNames.size();
+ dataIndex += 5 * d->methods.size();
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+ dataIndex += 4 * d->enumerators.size();
+ dataIndex += 5 * d->constructors.size();
+ }
+
+ // Allocate space for the enumerator key names and values.
+ enumIndex = dataIndex;
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ dataIndex += 2 * enumerator->keys.size();
+ }
+
+ // Zero terminator at the end of the data offset table.
+ ++dataIndex;
+
+ // Find the start of the data and string tables.
+ int *data = reinterpret_cast<int *>(pmeta);
+ size += dataIndex * sizeof(int);
+ char *str = reinterpret_cast<char *>(buf + size);
+ if (buf) {
+ if (relocatable) {
+ meta->d.stringdata = reinterpret_cast<const char *>((quintptr)size);
+ meta->d.data = reinterpret_cast<uint *>((quintptr)pmetaSize);
+ } else {
+ meta->d.stringdata = str;
+ meta->d.data = reinterpret_cast<uint *>(data);
+ }
+ }
+
+ // Reset the current data position to just past the QMetaObjectPrivate.
+ dataIndex = 13;
+
+ // Add the class name to the string table.
+ int offset = 0;
+ buildString(buf, str, &offset, d->className, -1);
+
+ // Add a common empty string, which is used to indicate "void"
+ // method returns, empty tag strings, etc.
+ int empty = buildString(buf, str, &offset, QByteArray(), -1);
+
+ // Output the class infos,
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ int name = buildString(buf, str, &offset, d->classInfoNames[index], empty);
+ int value = buildString(buf, str, &offset, d->classInfoValues[index], empty);
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = value;
+ }
+ dataIndex += 2;
+ }
+
+ // Output the methods in the class.
+ for (index = 0; index < d->methods.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // Output the properties in the class.
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ int name = buildString(buf, str, &offset, prop->name, empty);
+ int type = buildString(buf, str, &offset, prop->type, empty);
+ int flags = prop->flags;
+
+ if (!isVariantType(prop->type)) {
+ flags |= EnumOrFlag;
+ } else {
+ flags |= qvariant_nameToType(prop->type) << 24;
+ }
+
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = type;
+ data[dataIndex + 2] = flags;
+ }
+ dataIndex += 3;
+ }
+ if (hasNotifySignals) {
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ if (buf) {
+ if (prop->notifySignal != -1)
+ data[dataIndex] = prop->notifySignal;
+ else
+ data[dataIndex] = 0;
+ }
+ ++dataIndex;
+ }
+ }
+
+ // Output the enumerators in the class.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ int name = buildString(buf, str, &offset, enumerator->name, empty);
+ int isFlag = (int)(enumerator->isFlag);
+ int count = enumerator->keys.size();
+ int enumOffset = enumIndex;
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = isFlag;
+ data[dataIndex + 2] = count;
+ data[dataIndex + 3] = enumOffset;
+ }
+ for (int key = 0; key < count; ++key) {
+ int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty);
+ if (buf) {
+ data[enumOffset++] = keyIndex;
+ data[enumOffset++] = enumerator->values[key];
+ }
+ }
+ dataIndex += 4;
+ enumIndex += 2 * count;
+ }
+
+ // Output the constructors in the class.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // One more empty string to act as a terminator.
+ buildString(buf, str, &offset, QByteArray(), -1);
+ size += offset;
+
+ // Output the zero terminator in the data array.
+ if (buf)
+ data[enumIndex] = 0;
+
+ // Create the extradata block if we need one.
+ if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) {
+ ALIGN(size, QMetaObject **);
+ ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction);
+ QMetaObjectExtraData *extra =
+ reinterpret_cast<QMetaObjectExtraData *>(buf + size);
+ size += sizeof(QMetaObjectExtraData);
+ ALIGN(size, QMetaObject *);
+#ifdef Q_NO_DATA_RELOCATION
+ QMetaObjectAccessor *objects =
+ reinterpret_cast<QMetaObjectAccessor *>(buf + size);
+#else
+ const QMetaObject **objects =
+ reinterpret_cast<const QMetaObject **>(buf + size);
+#endif
+ if (buf) {
+ if (d->relatedMetaObjects.size() > 0) {
+ extra->objects = objects;
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index)
+ objects[index] = d->relatedMetaObjects[index];
+ objects[index] = 0;
+ } else {
+ extra->objects = 0;
+ }
+ extra->static_metacall = d->staticMetacallFunction;
+ meta->d.extradata = reinterpret_cast<void *>(extra);
+ }
+ if (d->relatedMetaObjects.size() > 0)
+ size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1);
+ }
+
+ // Align the final size and return it.
+ ALIGN(size, void *);
+ return size;
+}
+
+/*!
+ Converts this meta object builder into a concrete QMetaObject.
+ The return value should be deallocated using qFree() once it
+ is no longer needed.
+
+ The returned meta object is a snapshot of the state of the
+ QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder
+ will not be reflected in previous meta objects returned by
+ this method.
+*/
+QMetaObject *QMetaObjectBuilder::toMetaObject() const
+{
+ int size = buildMetaObject(d, 0, false);
+ char *buf = reinterpret_cast<char *>(qMalloc(size));
+ buildMetaObject(d, buf, false);
+ return reinterpret_cast<QMetaObject *>(buf);
+}
+
+/*
+ \internal
+
+ Converts this meta object builder into relocatable data. This data can
+ be stored, copied and later passed to fromRelocatableData() to create a
+ concrete QMetaObject.
+
+ The data is specific to the architecture on which it was created, but is not
+ specific to the process that created it. Not all meta object builder's can
+ be converted to data in this way. If \a ok is provided, it will be set to
+ true if the conversion succeeds, and false otherwise. If a
+ staticMetacallFunction() or any relatedMetaObject()'s are specified the
+ conversion to relocatable data will fail.
+*/
+QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const
+{
+ int size = buildMetaObject(d, 0, true);
+ if (size == -1) {
+ if (ok) *ok = false;
+ return QByteArray();
+ }
+
+ QByteArray data;
+ data.resize(size);
+ char *buf = data.data();
+ buildMetaObject(d, buf, true);
+ if (ok) *ok = true;
+ return data;
+}
+
+/*
+ \internal
+
+ Sets the \a data returned from toRelocatableData() onto a concrete
+ QMetaObject instance, \a output. As the meta object's super class is not
+ saved in the relocatable data, it must be passed as \a superClass.
+*/
+void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output,
+ const QMetaObject *superclass,
+ const QByteArray &data)
+{
+ if (!output)
+ return;
+
+ const char *buf = data.constData();
+ const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf);
+
+ quintptr stringdataOffset = (quintptr)dataMo->d.stringdata;
+ quintptr dataOffset = (quintptr)dataMo->d.data;
+
+ output->d.superdata = superclass;
+ output->d.stringdata = buf + stringdataOffset;
+ output->d.data = reinterpret_cast<const uint *>(buf + dataOffset);
+}
+
+/*!
+ \typedef QMetaObjectBuilder::StaticMetacallFunction
+
+ Typedef for static metacall functions. The three parameters are
+ the call type value, the constructor index, and the
+ array of parameters.
+*/
+
+/*!
+ Returns the static metacall function to use to construct objects
+ of this class. The default value is null.
+
+ \sa setStaticMetacallFunction()
+*/
+QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const
+{
+ return d->staticMetacallFunction;
+}
+
+/*!
+ Sets the static metacall function to use to construct objects
+ of this class to \a value. The default value is null.
+
+ \sa staticMetacallFunction()
+*/
+void QMetaObjectBuilder::setStaticMetacallFunction
+ (QMetaObjectBuilder::StaticMetacallFunction value)
+{
+ d->staticMetacallFunction = value;
+}
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ Serializes the contents of the meta object builder onto \a stream.
+
+ \sa deserialize()
+*/
+void QMetaObjectBuilder::serialize(QDataStream& stream) const
+{
+ int index;
+
+ // Write the class and super class names.
+ stream << d->className;
+ if (d->superClass)
+ stream << QByteArray(d->superClass->className());
+ else
+ stream << QByteArray();
+
+ // Write the counts for each type of class member.
+ stream << d->classInfoNames.size();
+ stream << d->methods.size();
+ stream << d->properties.size();
+ stream << d->enumerators.size();
+ stream << d->constructors.size();
+ stream << d->relatedMetaObjects.size();
+
+ // Write the items of class information.
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ stream << d->classInfoNames[index];
+ stream << d->classInfoValues[index];
+ }
+
+ // Write the methods.
+ for (index = 0; index < d->methods.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the properties.
+ for (index = 0; index < d->properties.size(); ++index) {
+ const QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream << property->name;
+ stream << property->type;
+ stream << property->flags;
+ stream << property->notifySignal;
+ }
+
+ // Write the enumerators.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream << enumerator->name;
+ stream << enumerator->isFlag;
+ stream << enumerator->keys;
+ stream << enumerator->values;
+ }
+
+ // Write the constructors.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the related meta objects.
+#ifdef Q_NO_DATA_RELOCATION
+ //### What do we do here?
+#else
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index) {
+ const QMetaObject *meta = d->relatedMetaObjects[index];
+ stream << QByteArray(meta->className());
+ }
+#endif
+
+ // Add an extra empty QByteArray for additional data in future versions.
+ // This should help maintain backwards compatibility, allowing older
+ // versions to read newer data.
+ stream << QByteArray();
+}
+
+// Resolve a class name using the name reference map.
+static const QMetaObject *resolveClassName
+ (const QMap<QByteArray, const QMetaObject *>& references,
+ const QByteArray& name)
+{
+ if (name == QByteArray("QObject"))
+ return &QObject::staticMetaObject;
+ else
+ return references.value(name, 0);
+}
+
+/*!
+ Deserializes a meta object builder from \a stream into
+ this meta object builder.
+
+ The \a references parameter specifies a mapping from class names
+ to QMetaObject instances for resolving the super class name and
+ related meta objects in the object that is deserialized.
+ The meta object for QObject is implicitly added to \a references
+ and does not need to be supplied.
+
+ The QDataStream::status() value on \a stream will be set to
+ QDataStream::ReadCorruptData if the input data is corrupt.
+ The status will be set to QDataStream::ReadPastEnd if the
+ input was exhausted before the full meta object was read.
+
+ \sa serialize()
+*/
+void QMetaObjectBuilder::deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references)
+{
+ QByteArray name;
+ const QMetaObject *cl;
+ int index;
+
+ // Clear all members in the builder to their default states.
+ d->className.clear();
+ d->superClass = &QObject::staticMetaObject;
+ d->classInfoNames.clear();
+ d->classInfoValues.clear();
+ d->methods.clear();
+ d->properties.clear();
+ d->enumerators.clear();
+ d->constructors.clear();
+ d->relatedMetaObjects.clear();
+ d->staticMetacallFunction = 0;
+
+ // Read the class and super class names.
+ stream >> d->className;
+ stream >> name;
+ if (name.isEmpty()) {
+ d->superClass = 0;
+ } else if ((cl = resolveClassName(references, name)) != 0) {
+ d->superClass = cl;
+ } else {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the counts for each type of class member.
+ int classInfoCount, methodCount, propertyCount;
+ int enumeratorCount, constructorCount, relatedMetaObjectCount;
+ stream >> classInfoCount;
+ stream >> methodCount;
+ stream >> propertyCount;
+ stream >> enumeratorCount;
+ stream >> constructorCount;
+ stream >> relatedMetaObjectCount;
+ if (classInfoCount < 0 || methodCount < 0 ||
+ propertyCount < 0 || enumeratorCount < 0 ||
+ constructorCount < 0 || relatedMetaObjectCount < 0) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the items of class information.
+ for (index = 0; index < classInfoCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray value;
+ stream >> name;
+ stream >> value;
+ addClassInfo(name, value);
+ }
+
+ // Read the member methods.
+ for (index = 0; index < methodCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addMethod(name);
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() == QMetaMethod::Constructor) {
+ // Cannot add a constructor in this set of methods.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the properties.
+ for (index = 0; index < propertyCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray type;
+ stream >> name;
+ stream >> type;
+ addProperty(name, type);
+ QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream >> property->flags;
+ stream >> property->notifySignal;
+ if (property->notifySignal < -1 ||
+ property->notifySignal >= d->methods.size()) {
+ // Notify signal method index is out of range.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ if (property->notifySignal >= 0 &&
+ d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) {
+ // Notify signal method index does not refer to a signal.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the enumerators.
+ for (index = 0; index < enumeratorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addEnumerator(name);
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream >> enumerator->isFlag;
+ stream >> enumerator->keys;
+ stream >> enumerator->values;
+ if (enumerator->keys.size() != enumerator->values.size()) {
+ // Mismatch between number of keys and number of values.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the constructor methods.
+ for (index = 0; index < constructorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addConstructor(name);
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() != QMetaMethod::Constructor) {
+ // The type must be Constructor.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the related meta objects.
+#ifdef Q_NO_DATA_RELOCATION
+ //### What do we do here
+#else
+ for (index = 0; index < relatedMetaObjectCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ cl = resolveClassName(references, name);
+ if (!cl) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ addRelatedMetaObject(cl);
+ }
+#endif
+
+ // Read the extra data block, which is reserved for future use.
+ stream >> name;
+}
+
+#endif // !QT_NO_DATASTREAM
+
+/*!
+ \class QMetaMethodBuilder
+ \internal
+ \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder.
+*/
+
+QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const
+{
+ // Positive indices indicate methods, negative indices indicate constructors.
+ if (_mobj && _index >= 0 && _index < _mobj->d->methods.size())
+ return &(_mobj->d->methods[_index]);
+ else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size())
+ return &(_mobj->d->constructors[(-_index) - 1]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaMethodBuilder::QMetaMethodBuilder()
+ \internal
+*/
+
+/*!
+ Returns the index of this method within its QMetaObjectBuilder.
+*/
+int QMetaMethodBuilder::index() const
+{
+ if (_index >= 0)
+ return _index; // Method, signal, or slot
+ else
+ return (-_index) - 1; // Constructor
+}
+
+/*!
+ Returns the type of this method (signal, slot, method, or constructor).
+*/
+QMetaMethod::MethodType QMetaMethodBuilder::methodType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->methodType();
+ else
+ return QMetaMethod::Method;
+}
+
+/*!
+ Returns the signature of this method.
+
+ \sa parameterNames(), returnType()
+*/
+QByteArray QMetaMethodBuilder::signature() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->signature;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the return type for this method; empty if the method's
+ return type is \c{void}.
+
+ \sa setReturnType(), signature()
+*/
+QByteArray QMetaMethodBuilder::returnType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->returnType;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the return type for this method to \a value. If \a value
+ is empty, then the method's return type is \c{void}. The \a value
+ will be normalized before it is added to the method.
+
+ \sa returnType(), signature()
+*/
+void QMetaMethodBuilder::setReturnType(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->returnType = QMetaObject::normalizedType(value);
+}
+
+/*!
+ Returns the list of parameter names for this method.
+
+ \sa setParameterNames()
+*/
+QList<QByteArray> QMetaMethodBuilder::parameterNames() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->parameterNames;
+ else
+ return QList<QByteArray>();
+}
+
+/*!
+ Sets the list of parameter names for this method to \a value.
+
+ \sa parameterNames()
+*/
+void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->parameterNames = value;
+}
+
+/*!
+ Returns the tag associated with this method.
+
+ \sa setTag()
+*/
+QByteArray QMetaMethodBuilder::tag() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->tag;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the tag associated with this method to \a value.
+
+ \sa setTag()
+*/
+void QMetaMethodBuilder::setTag(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->tag = value;
+}
+
+/*!
+ Returns the access specification of this method (private, protected,
+ or public). The default value is QMetaMethod::Public for methods,
+ slots, and constructors. The default value is QMetaMethod::Protected
+ for signals.
+
+ \sa setAccess()
+*/
+QMetaMethod::Access QMetaMethodBuilder::access() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->access();
+ else
+ return QMetaMethod::Public;
+}
+
+/*!
+ Sets the access specification of this method (private, protected,
+ or public) to \a value. If the method is a signal, this function
+ will be ignored.
+
+ \sa access()
+*/
+void QMetaMethodBuilder::setAccess(QMetaMethod::Access value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d && d->methodType() != QMetaMethod::Signal)
+ d->setAccess(value);
+}
+
+/*!
+ Returns the additional attributes for this method.
+
+ \sa setAttributes()
+*/
+int QMetaMethodBuilder::attributes() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return (d->attributes >> 4);
+ else
+ return 0;
+}
+
+/*!
+ Sets the additional attributes for this method to \a value.
+
+ \sa attributes()
+*/
+void QMetaMethodBuilder::setAttributes(int value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->attributes = ((d->attributes & 0x0f) | (value << 4));
+}
+
+/*!
+ \class QMetaPropertyBuilder
+ \internal
+ \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder.
+*/
+
+QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->properties.size())
+ return &(_mobj->d->properties[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaPropertyBuilder::QMetaPropertyBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaPropertyBuilder::index() const
+
+ Returns the index of this property within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name associated with this property.
+
+ \sa type()
+*/
+QByteArray QMetaPropertyBuilder::name() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the type associated with this property.
+
+ \sa name()
+*/
+QByteArray QMetaPropertyBuilder::type() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->type;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this property has a notify signal; false otherwise.
+
+ \sa notifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+bool QMetaPropertyBuilder::hasNotifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Notify);
+ else
+ return false;
+}
+
+/*!
+ Returns the notify signal associated with this property.
+
+ \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d && d->notifySignal >= 0)
+ return QMetaMethodBuilder(_mobj, d->notifySignal);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Sets the notify signal associated with this property to \a value.
+
+ \sa hasNotifySignal(), notifySignal(), removeNotifySignal()
+*/
+void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ if (value._mobj) {
+ d->notifySignal = value._index;
+ d->setFlag(Notify, true);
+ } else {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+ }
+}
+
+/*!
+ Removes the notify signal from this property.
+
+ \sa hasNotifySignal(), notifySignal(), setNotifySignal()
+*/
+void QMetaPropertyBuilder::removeNotifySignal()
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+}
+
+/*!
+ Returns true if this property is readable; otherwise returns false.
+ The default value is true.
+
+ \sa setReadable(), isWritable()
+*/
+bool QMetaPropertyBuilder::isReadable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Readable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is writable; otherwise returns false.
+ The default value is true.
+
+ \sa setWritable(), isReadable()
+*/
+bool QMetaPropertyBuilder::isWritable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Writable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property can be reset to a default value; otherwise
+ returns false. The default value is false.
+
+ \sa setResettable()
+*/
+bool QMetaPropertyBuilder::isResettable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Resettable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designable; otherwise returns false.
+ This default value is false.
+
+ \sa setDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isDesignable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Designable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is scriptable; otherwise returns false.
+ This default value is true.
+
+ \sa setScriptable(), isDesignable(), isStored()
+*/
+bool QMetaPropertyBuilder::isScriptable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Scriptable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is stored; otherwise returns false.
+ This default value is false.
+
+ \sa setStored(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isStored() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Stored);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is editable; otherwise returns false.
+ This default value is false.
+
+ \sa setEditable(), isDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isEditable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Editable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designated as the \c USER
+ property, i.e., the one that the user can edit or that is
+ significant in some other way. Otherwise it returns
+ false. This default value is false.
+
+ \sa setUser(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isUser() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(User);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a C++ setter function that
+ follows Qt's standard "name" / "setName" pattern. Designer and uic
+ query hasStdCppSet() in order to avoid expensive
+ QObject::setProperty() calls. All properties in Qt [should] follow
+ this pattern. The default value is false.
+
+ \sa setStdCppSet()
+*/
+bool QMetaPropertyBuilder::hasStdCppSet() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(StdCppSet);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is an enumerator or flag type;
+ otherwise returns false. This default value is false.
+
+ \sa setEnumOrFlag()
+*/
+bool QMetaPropertyBuilder::isEnumOrFlag() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(EnumOrFlag);
+ else
+ return false;
+}
+
+/*!
+ Sets this property to readable if \a value is true.
+
+ \sa isReadable(), setWritable()
+*/
+void QMetaPropertyBuilder::setReadable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Readable, value);
+}
+
+/*!
+ Sets this property to writable if \a value is true.
+
+ \sa isWritable(), setReadable()
+*/
+void QMetaPropertyBuilder::setWritable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Writable, value);
+}
+
+/*!
+ Sets this property to resettable if \a value is true.
+
+ \sa isResettable()
+*/
+void QMetaPropertyBuilder::setResettable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Resettable, value);
+}
+
+/*!
+ Sets this property to designable if \a value is true.
+
+ \sa isDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setDesignable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Designable, value);
+}
+
+/*!
+ Sets this property to scriptable if \a value is true.
+
+ \sa isScriptable(), setDesignable(), setStored()
+*/
+void QMetaPropertyBuilder::setScriptable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Scriptable, value);
+}
+
+/*!
+ Sets this property to storable if \a value is true.
+
+ \sa isStored(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setStored(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Stored, value);
+}
+
+/*!
+ Sets this property to editable if \a value is true.
+
+ \sa isEditable(), setDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setEditable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Editable, value);
+}
+
+/*!
+ Sets the \c USER flag on this property to \a value.
+
+ \sa isUser(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setUser(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(User, value);
+}
+
+/*!
+ Sets the C++ setter flag on this property to \a value, which is
+ true if the property has a C++ setter function that follows Qt's
+ standard "name" / "setName" pattern.
+
+ \sa hasStdCppSet()
+*/
+void QMetaPropertyBuilder::setStdCppSet(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(StdCppSet, value);
+}
+
+/*!
+ Sets this property to be of an enumerator or flag type if
+ \a value is true.
+
+ \sa isEnumOrFlag()
+*/
+void QMetaPropertyBuilder::setEnumOrFlag(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(EnumOrFlag, value);
+}
+
+/*!
+ \class QMetaEnumBuilder
+ \internal
+ \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
+*/
+
+QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size())
+ return &(_mobj->d->enumerators[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaEnumBuilder::QMetaEnumBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaEnumBuilder::index() const
+
+ Returns the index of this enumerator within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name of the enumerator (without the scope).
+*/
+QByteArray QMetaEnumBuilder::name() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this enumerator is used as a flag; otherwise returns
+ false.
+
+ \sa setIsFlag()
+*/
+bool QMetaEnumBuilder::isFlag() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->isFlag;
+ else
+ return false;
+}
+
+/*!
+ Sets this enumerator to be used as a flag if \a value is true.
+
+ \sa isFlag()
+*/
+void QMetaEnumBuilder::setIsFlag(bool value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->isFlag = value;
+}
+
+/*!
+ Returns the number of keys.
+
+ \sa key(), addKey()
+*/
+int QMetaEnumBuilder::keyCount() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->keys.size();
+ else
+ return 0;
+}
+
+/*!
+ Returns the key with the given \a index, or an empty QByteArray
+ if no such key exists.
+
+ \sa keyCount(), addKey(), value()
+*/
+QByteArray QMetaEnumBuilder::key(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->keys[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value with the given \a index; or returns -1 if there
+ is no such value.
+
+ \sa keyCount(), addKey(), key()
+*/
+int QMetaEnumBuilder::value(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->values[index];
+ else
+ return -1;
+}
+
+/*!
+ Adds a new key called \a name to this enumerator, associated
+ with \a value. Returns the index of the new key.
+
+ \sa keyCount(), key(), value(), removeKey()
+*/
+int QMetaEnumBuilder::addKey(const QByteArray& name, int value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d) {
+ int index = d->keys.size();
+ d->keys += name;
+ d->values += value;
+ return index;
+ } else {
+ return -1;
+ }
+}
+
+/*!
+ Removes the key at \a index from this enumerator.
+
+ \sa addKey()
+*/
+void QMetaEnumBuilder::removeKey(int index)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size()) {
+ d->keys.removeAt(index);
+ d->values.removeAt(index);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h
new file mode 100644
index 0000000000..d7085f8784
--- /dev/null
+++ b/src/declarative/qml/qmetaobjectbuilder_p.h
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QMETAOBJECTBUILDER_H
+#define QMETAOBJECTBUILDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of moc. This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmap.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMetaObjectBuilderPrivate;
+class QMetaMethodBuilder;
+class QMetaMethodBuilderPrivate;
+class QMetaPropertyBuilder;
+class QMetaPropertyBuilderPrivate;
+class QMetaEnumBuilder;
+class QMetaEnumBuilderPrivate;
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QMetaObjectBuilder
+{
+public:
+ enum AddMember
+ {
+ ClassName = 0x00000001,
+ SuperClass = 0x00000002,
+ Methods = 0x00000004,
+ Signals = 0x00000008,
+ Slots = 0x00000010,
+ Constructors = 0x00000020,
+ Properties = 0x00000040,
+ Enumerators = 0x00000080,
+ ClassInfos = 0x00000100,
+ RelatedMetaObjects = 0x00000200,
+ StaticMetacall = 0x00000400,
+ PublicMethods = 0x00000800,
+ ProtectedMethods = 0x00001000,
+ PrivateMethods = 0x00002000,
+ AllMembers = 0x7FFFFFFF,
+ AllPrimaryMembers = 0x7FFFFBFC
+ };
+ Q_DECLARE_FLAGS(AddMembers, AddMember)
+
+ enum MetaObjectFlag {
+ DynamicMetaObject = 0x01
+ };
+ Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag)
+
+ QMetaObjectBuilder();
+ explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+ virtual ~QMetaObjectBuilder();
+
+ QByteArray className() const;
+ void setClassName(const QByteArray& name);
+
+ const QMetaObject *superClass() const;
+ void setSuperClass(const QMetaObject *meta);
+
+ MetaObjectFlags flags() const;
+ void setFlags(MetaObjectFlags);
+
+ int methodCount() const;
+ int constructorCount() const;
+ int propertyCount() const;
+ int enumeratorCount() const;
+ int classInfoCount() const;
+ int relatedMetaObjectCount() const;
+
+ QMetaMethodBuilder addMethod(const QByteArray& signature);
+ QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType);
+ QMetaMethodBuilder addMethod(const QMetaMethod& prototype);
+
+ QMetaMethodBuilder addSlot(const QByteArray& signature);
+ QMetaMethodBuilder addSignal(const QByteArray& signature);
+
+ QMetaMethodBuilder addConstructor(const QByteArray& signature);
+ QMetaMethodBuilder addConstructor(const QMetaMethod& prototype);
+
+ QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1);
+ QMetaPropertyBuilder addProperty(const QMetaProperty& prototype);
+
+ QMetaEnumBuilder addEnumerator(const QByteArray& name);
+ QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype);
+
+ int addClassInfo(const QByteArray& name, const QByteArray& value);
+
+#ifdef Q_NO_DATA_RELOCATION
+ int addRelatedMetaObject(const QMetaObjectAccessor &meta);
+#else
+ int addRelatedMetaObject(const QMetaObject *meta);
+#endif
+
+ void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+
+ QMetaMethodBuilder method(int index) const;
+ QMetaMethodBuilder constructor(int index) const;
+ QMetaPropertyBuilder property(int index) const;
+ QMetaEnumBuilder enumerator(int index) const;
+ const QMetaObject *relatedMetaObject(int index) const;
+
+ QByteArray classInfoName(int index) const;
+ QByteArray classInfoValue(int index) const;
+
+ void removeMethod(int index);
+ void removeConstructor(int index);
+ void removeProperty(int index);
+ void removeEnumerator(int index);
+ void removeClassInfo(int index);
+ void removeRelatedMetaObject(int index);
+
+ int indexOfMethod(const QByteArray& signature);
+ int indexOfSignal(const QByteArray& signature);
+ int indexOfSlot(const QByteArray& signature);
+ int indexOfConstructor(const QByteArray& signature);
+ int indexOfProperty(const QByteArray& name);
+ int indexOfEnumerator(const QByteArray& name);
+ int indexOfClassInfo(const QByteArray& name);
+
+ typedef QMetaObjectExtraData::StaticMetacallFunction StaticMetacallFunction;
+
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const;
+ void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value);
+
+ QMetaObject *toMetaObject() const;
+ QByteArray toRelocatableData(bool * = 0) const;
+ static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &);
+
+#ifndef QT_NO_DATASTREAM
+ void serialize(QDataStream& stream) const;
+ void deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references);
+#endif
+
+private:
+ Q_DISABLE_COPY(QMetaObjectBuilder)
+
+ QMetaObjectBuilderPrivate *d;
+
+ friend class QMetaMethodBuilder;
+ friend class QMetaPropertyBuilder;
+ friend class QMetaEnumBuilder;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QMetaMethodBuilder
+{
+public:
+ QMetaMethodBuilder() : _mobj(0), _index(0) {}
+
+ int index() const;
+
+ QMetaMethod::MethodType methodType() const;
+ QByteArray signature() const;
+
+ QByteArray returnType() const;
+ void setReturnType(const QByteArray& value);
+
+ QList<QByteArray> parameterNames() const;
+ void setParameterNames(const QList<QByteArray>& value);
+
+ QByteArray tag() const;
+ void setTag(const QByteArray& value);
+
+ QMetaMethod::Access access() const;
+ void setAccess(QMetaMethod::Access value);
+
+ int attributes() const;
+ void setAttributes(int value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+ friend class QMetaPropertyBuilder;
+
+ QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaMethodBuilderPrivate *d_func() const;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QMetaPropertyBuilder
+{
+public:
+ QMetaPropertyBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+ QByteArray type() const;
+
+ bool hasNotifySignal() const;
+ QMetaMethodBuilder notifySignal() const;
+ void setNotifySignal(const QMetaMethodBuilder& value);
+ void removeNotifySignal();
+
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isResettable() const;
+ bool isDesignable() const;
+ bool isScriptable() const;
+ bool isStored() const;
+ bool isEditable() const;
+ bool isUser() const;
+ bool hasStdCppSet() const;
+ bool isEnumOrFlag() const;
+
+ void setReadable(bool value);
+ void setWritable(bool value);
+ void setResettable(bool value);
+ void setDesignable(bool value);
+ void setScriptable(bool value);
+ void setStored(bool value);
+ void setEditable(bool value);
+ void setUser(bool value);
+ void setStdCppSet(bool value);
+ void setEnumOrFlag(bool value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaPropertyBuilderPrivate *d_func() const;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QMetaEnumBuilder
+{
+public:
+ QMetaEnumBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+
+ bool isFlag() const;
+ void setIsFlag(bool value);
+
+ int keyCount() const;
+ QByteArray key(int index) const;
+ int value(int index) const;
+
+ int addKey(const QByteArray& name, int value);
+ void removeKey(int index);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaEnumBuilderPrivate *d_func() const;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
new file mode 100644
index 0000000000..bf9e54a986
--- /dev/null
+++ b/src/declarative/qml/qml.pri
@@ -0,0 +1,141 @@
+INCLUDEPATH += $$PWD
+SOURCES += \
+ $$PWD/qdeclarativeparser.cpp \
+ $$PWD/qdeclarativeinstruction.cpp \
+ $$PWD/qdeclarativevmemetaobject.cpp \
+ $$PWD/qdeclarativeengine.cpp \
+ $$PWD/qdeclarativeexpression.cpp \
+ $$PWD/qdeclarativebinding.cpp \
+ $$PWD/qdeclarativeproperty.cpp \
+ $$PWD/qdeclarativecomponent.cpp \
+ $$PWD/qdeclarativecontext.cpp \
+ $$PWD/qdeclarativeinclude.cpp \
+ $$PWD/qdeclarativecustomparser.cpp \
+ $$PWD/qdeclarativepropertyvaluesource.cpp \
+ $$PWD/qdeclarativepropertyvalueinterceptor.cpp \
+ $$PWD/qdeclarativeproxymetaobject.cpp \
+ $$PWD/qdeclarativevme.cpp \
+ $$PWD/qdeclarativecompiler.cpp \
+ $$PWD/qdeclarativecompileddata.cpp \
+ $$PWD/qdeclarativeboundsignal.cpp \
+ $$PWD/qdeclarativedom.cpp \
+ $$PWD/qdeclarativerefcount.cpp \
+ $$PWD/qdeclarativemetatype.cpp \
+ $$PWD/qdeclarativestringconverters.cpp \
+ $$PWD/qdeclarativeparserstatus.cpp \
+ $$PWD/qdeclarativetypeloader.cpp \
+ $$PWD/qdeclarativeinfo.cpp \
+ $$PWD/qdeclarativeerror.cpp \
+ $$PWD/qdeclarativescriptparser.cpp \
+ $$PWD/qdeclarativeenginedebug.cpp \
+ $$PWD/qdeclarativerewrite.cpp \
+ $$PWD/qdeclarativevaluetype.cpp \
+ $$PWD/qdeclarativecompiledbindings.cpp \
+ $$PWD/qdeclarativefastproperties.cpp \
+ $$PWD/qdeclarativexmlhttprequest.cpp \
+ $$PWD/qdeclarativesqldatabase.cpp \
+ $$PWD/qmetaobjectbuilder.cpp \
+ $$PWD/qdeclarativewatcher.cpp \
+ $$PWD/qdeclarativecleanup.cpp \
+ $$PWD/qdeclarativepropertycache.cpp \
+ $$PWD/qdeclarativenotifier.cpp \
+ $$PWD/qdeclarativeintegercache.cpp \
+ $$PWD/qdeclarativetypenotavailable.cpp \
+ $$PWD/qdeclarativetypenamecache.cpp \
+ $$PWD/qdeclarativescriptstring.cpp \
+ $$PWD/qdeclarativeobjectscriptclass.cpp \
+ $$PWD/qdeclarativecontextscriptclass.cpp \
+ $$PWD/qdeclarativeglobalscriptclass.cpp \
+ $$PWD/qdeclarativevaluetypescriptclass.cpp \
+ $$PWD/qdeclarativetypenamescriptclass.cpp \
+ $$PWD/qdeclarativelistscriptclass.cpp \
+ $$PWD/qdeclarativeworkerscript.cpp \
+ $$PWD/qdeclarativeimageprovider.cpp \
+ $$PWD/qdeclarativenetworkaccessmanagerfactory.cpp \
+ $$PWD/qdeclarativedirparser.cpp \
+ $$PWD/qdeclarativeextensionplugin.cpp \
+ $$PWD/qdeclarativeimport.cpp \
+ $$PWD/qdeclarativelist.cpp \
+ $$PWD/qperformancetimer.cpp
+
+HEADERS += \
+ $$PWD/qdeclarativeparser_p.h \
+ $$PWD/qdeclarativeglobal_p.h \
+ $$PWD/qdeclarativeinstruction_p.h \
+ $$PWD/qdeclarativevmemetaobject_p.h \
+ $$PWD/qdeclarative.h \
+ $$PWD/qdeclarativebinding_p.h \
+ $$PWD/qdeclarativebinding_p_p.h \
+ $$PWD/qdeclarativeproperty.h \
+ $$PWD/qdeclarativecomponent.h \
+ $$PWD/qdeclarativecomponent_p.h \
+ $$PWD/qdeclarativecustomparser_p.h \
+ $$PWD/qdeclarativecustomparser_p_p.h \
+ $$PWD/qdeclarativepropertyvaluesource.h \
+ $$PWD/qdeclarativepropertyvalueinterceptor.h \
+ $$PWD/qdeclarativeboundsignal_p.h \
+ $$PWD/qdeclarativeparserstatus.h \
+ $$PWD/qdeclarativeproxymetaobject_p.h \
+ $$PWD/qdeclarativevme_p.h \
+ $$PWD/qdeclarativecompiler_p.h \
+ $$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 \
+ $$PWD/qdeclarativecontext.h \
+ $$PWD/qdeclarativeexpression.h \
+ $$PWD/qdeclarativestringconverters_p.h \
+ $$PWD/qdeclarativeinfo.h \
+ $$PWD/qdeclarativeproperty_p.h \
+ $$PWD/qdeclarativecontext_p.h \
+ $$PWD/qdeclarativeinclude_p.h \
+ $$PWD/qdeclarativetypeloader_p.h \
+ $$PWD/qdeclarativelist.h \
+ $$PWD/qdeclarativelist_p.h \
+ $$PWD/qdeclarativedata_p.h \
+ $$PWD/qdeclarativeerror.h \
+ $$PWD/qdeclarativescriptparser_p.h \
+ $$PWD/qdeclarativeenginedebug_p.h \
+ $$PWD/qdeclarativerewrite_p.h \
+ $$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 \
+ $$PWD/qmetaobjectbuilder_p.h \
+ $$PWD/qdeclarativewatcher_p.h \
+ $$PWD/qdeclarativecleanup_p.h \
+ $$PWD/qdeclarativepropertycache_p.h \
+ $$PWD/qdeclarativenotifier_p.h \
+ $$PWD/qdeclarativeintegercache_p.h \
+ $$PWD/qdeclarativetypenotavailable_p.h \
+ $$PWD/qdeclarativetypenamecache_p.h \
+ $$PWD/qdeclarativescriptstring.h \
+ $$PWD/qdeclarativeobjectscriptclass_p.h \
+ $$PWD/qdeclarativecontextscriptclass_p.h \
+ $$PWD/qdeclarativeglobalscriptclass_p.h \
+ $$PWD/qdeclarativevaluetypescriptclass_p.h \
+ $$PWD/qdeclarativetypenamescriptclass_p.h \
+ $$PWD/qdeclarativelistscriptclass_p.h \
+ $$PWD/qdeclarativeworkerscript_p.h \
+ $$PWD/qdeclarativeguard_p.h \
+ $$PWD/qdeclarativeimageprovider.h \
+ $$PWD/qdeclarativenetworkaccessmanagerfactory.h \
+ $$PWD/qdeclarativedirparser_p.h \
+ $$PWD/qdeclarativeextensioninterface.h \
+ $$PWD/qdeclarativeimport_p.h \
+ $$PWD/qdeclarativeextensionplugin.h \
+ $$PWD/qperformancetimer_p.h
+
+QT += sql
+include(parser/parser.pri)
+include(rewriter/rewriter.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/qperformancetimer.cpp b/src/declarative/qml/qperformancetimer.cpp
new file mode 100644
index 0000000000..3b1e09bc33
--- /dev/null
+++ b/src/declarative/qml/qperformancetimer.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 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 "qperformancetimer_p.h"
+
+#if defined(Q_OS_MAC)
+#include <sys/time.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#elif defined(Q_OS_UNIX)
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#elif defined(Q_OS_SYMBIAN)
+#include <e32std.h>
+#include <sys/time.h>
+#include <hal.h>
+#elif defined(Q_OS_WIN)
+#include <windows.h>
+#endif
+
+// mac/unix code heavily copied from QElapsedTimer
+
+QT_BEGIN_NAMESPACE
+
+////////////////////////////// Mac //////////////////////////////
+#if defined(Q_OS_MAC)
+
+static mach_timebase_info_data_t info = {0,0};
+static qint64 absoluteToNSecs(qint64 cpuTime)
+{
+ if (info.denom == 0)
+ mach_timebase_info(&info);
+ qint64 nsecs = cpuTime * info.numer / info.denom;
+ return nsecs;
+}
+
+void QPerformanceTimer::start()
+{
+ t1 = mach_absolute_time();
+}
+
+qint64 QPerformanceTimer::elapsed() const
+{
+ uint64_t cpu_time = mach_absolute_time();
+ return absoluteToNSecs(cpu_time - t1);
+}
+
+////////////////////////////// Unix //////////////////////////////
+#elif defined(Q_OS_UNIX)
+
+#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED)
+// turn off the monotonic clock
+# ifdef _POSIX_MONOTONIC_CLOCK
+# undef _POSIX_MONOTONIC_CLOCK
+# endif
+# define _POSIX_MONOTONIC_CLOCK -1
+#endif
+
+#if (_POSIX_MONOTONIC_CLOCK-0 != 0)
+static const bool monotonicClockChecked = true;
+static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0;
+#else
+static int monotonicClockChecked = false;
+static int monotonicClockAvailable = false;
+#endif
+
+#ifdef Q_CC_GNU
+# define is_likely(x) __builtin_expect((x), 1)
+#else
+# define is_likely(x) (x)
+#endif
+#define load_acquire(x) ((volatile const int&)(x))
+#define store_release(x,v) ((volatile int&)(x) = (v))
+
+static void unixCheckClockType()
+{
+#if (_POSIX_MONOTONIC_CLOCK-0 == 0)
+ if (is_likely(load_acquire(monotonicClockChecked)))
+ return;
+
+# if defined(_SC_MONOTONIC_CLOCK)
+ // detect if the system support monotonic timers
+ long x = sysconf(_SC_MONOTONIC_CLOCK);
+ store_release(monotonicClockAvailable, x >= 200112L);
+# endif
+
+ store_release(monotonicClockChecked, true);
+#endif
+}
+
+static inline void do_gettime(qint64 *sec, qint64 *frac)
+{
+#if (_POSIX_MONOTONIC_CLOCK-0 >= 0)
+ unixCheckClockType();
+ if (is_likely(monotonicClockAvailable)) {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ *sec = ts.tv_sec;
+ *frac = ts.tv_nsec;
+ return;
+ }
+#endif
+ *sec = 0;
+ *frac = 0;
+}
+
+void QPerformanceTimer::start()
+{
+ do_gettime(&t1, &t2);
+}
+
+qint64 QPerformanceTimer::elapsed() const
+{
+ qint64 sec, frac;
+ do_gettime(&sec, &frac);
+ sec = sec - t1;
+ frac = frac - t2;
+
+ return sec * Q_INT64_C(1000000000) + frac;
+}
+
+////////////////////////////// Symbian //////////////////////////////
+#elif defined(Q_OS_SYMBIAN)
+
+static qint64 getTimeFromTick(quint64 elapsed)
+{
+ static TInt freq;
+ if (!freq)
+ HAL::Get(HALData::EFastCounterFrequency, freq);
+
+ // ### not sure on units
+ return elapsed / freq;
+}
+
+void QPerformanceTimer::start()
+{
+ t1 = User::FastCounter();
+}
+
+qint64 QPerformanceTimer::elapsed() const
+{
+ return getTimeFromTick(User::FastCounter() - t1);
+}
+
+////////////////////////////// Windows //////////////////////////////
+#elif defined(Q_OS_WIN)
+
+static qint64 getTimeFromTick(quint64 elapsed)
+{
+ static LARGE_INTEGER freq;
+ if (!freq.QuadPart)
+ QueryPerformanceFrequency(&freq);
+ return 1000000000 * elapsed / freq.QuadPart;
+}
+
+void QPerformanceTimer::start()
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ t1 = li.QuadPart;
+}
+
+qint64 QPerformanceTimer::elapsed() const
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return getTimeFromTick(li.QuadPart - t1);
+}
+
+////////////////////////////// Default //////////////////////////////
+#else
+
+// default implementation (no hi-perf timer) does nothing
+void QPerformanceTimer::start()
+{
+}
+
+qint64 QPerformanceTimer::elapsed() const
+{
+ return 0;
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+
diff --git a/src/declarative/qml/qperformancetimer_p.h b/src/declarative/qml/qperformancetimer_p.h
new file mode 100644
index 0000000000..27879213b4
--- /dev/null
+++ b/src/declarative/qml/qperformancetimer_p.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 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 QPERFORMANCETIMER_P_H
+#define QPERFORMANCETIMER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of moc. This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_EXPORT QPerformanceTimer
+{
+public:
+ void start();
+ qint64 elapsed() const;
+
+private:
+ qint64 t1;
+ qint64 t2;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPERFORMANCETIMER_P_H
diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h
new file mode 100644
index 0000000000..41e6b5b67b
--- /dev/null
+++ b/src/declarative/qml/qpodvector_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QPODVECTOR_P_H
+#define QPODVECTOR_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 <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+template<class T, int Increment=1024>
+class QPODVector
+{
+public:
+ QPODVector()
+ : m_count(0), m_capacity(0), m_data(0) {}
+ ~QPODVector() { if (m_data) ::free(m_data); }
+
+ const T &at(int idx) const {
+ return m_data[idx];
+ }
+
+ T &operator[](int idx) {
+ return m_data[idx];
+ }
+
+ void clear() {
+ m_count = 0;
+ }
+
+ void prepend(const T &v) {
+ insert(0, v);
+ }
+
+ void append(const T &v) {
+ insert(m_count, v);
+ }
+
+ void insert(int idx, const T &v) {
+ if (m_count == m_capacity) {
+ m_capacity += Increment;
+ m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ }
+ int moveCount = m_count - idx;
+ if (moveCount)
+ ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T));
+ m_count++;
+ m_data[idx] = v;
+ }
+
+ void reserve(int count) {
+ if (count >= m_capacity) {
+ m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1);
+ m_data = (T *)realloc(m_data, m_capacity * sizeof(T));
+ }
+ }
+
+ void insertBlank(int idx, int count) {
+ int newSize = m_count + count;
+ reserve(newSize);
+ int moveCount = m_count - idx;
+ if (moveCount)
+ ::memmove(m_data + idx + count, m_data + idx,
+ moveCount * sizeof(T));
+ m_count = newSize;
+ }
+
+ void remove(int idx, int count = 1) {
+ int moveCount = m_count - (idx + count);
+ if (moveCount)
+ ::memmove(m_data + idx, m_data + idx + count,
+ moveCount * sizeof(T));
+ m_count -= count;
+ }
+
+ void removeOne(const T &v) {
+ int idx = 0;
+ while (idx < m_count) {
+ if (m_data[idx] == v) {
+ remove(idx);
+ return;
+ }
+ ++idx;
+ }
+ }
+
+ int find(const T &v) {
+ for (int idx = 0; idx < m_count; ++idx)
+ if (m_data[idx] == v)
+ return idx;
+ return -1;
+ }
+
+ bool contains(const T &v) {
+ return find(v) != -1;
+ }
+
+ int count() const {
+ return m_count;
+ }
+
+ void copyAndClear(QPODVector<T,Increment> &other) {
+ if (other.m_data) ::free(other.m_data);
+ other.m_count = m_count;
+ other.m_capacity = m_capacity;
+ other.m_data = m_data;
+ m_count = 0;
+ m_capacity = 0;
+ m_data = 0;
+ }
+
+ QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; }
+private:
+ QPODVector(const QPODVector &);
+ QPODVector &operator=(const QPODVector &);
+ int m_count;
+ int m_capacity;
+ T *m_data;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/qml/rewriter/rewriter.pri b/src/declarative/qml/rewriter/rewriter.pri
new file mode 100644
index 0000000000..a9fa1b5772
--- /dev/null
+++ b/src/declarative/qml/rewriter/rewriter.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/textwriter_p.h
+SOURCES += $$PWD/textwriter.cpp
diff --git a/src/declarative/qml/rewriter/textwriter.cpp b/src/declarative/qml/rewriter/textwriter.cpp
new file mode 100644
index 0000000000..40a7d864e4
--- /dev/null
+++ b/src/declarative/qml/rewriter/textwriter.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 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/textwriter_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+using namespace QDeclarativeJS;
+
+TextWriter::TextWriter()
+ :string(0), cursor(0)
+{
+}
+
+static bool overlaps(int posA, int lengthA, int posB, int lengthB) {
+ return (posA < posB + lengthB && posA + lengthA > posB + lengthB)
+ || (posA < posB && posA + lengthA > posB);
+}
+
+bool TextWriter::hasOverlap(int pos, int length)
+{
+ {
+ QListIterator<Replace> i(replaceList);
+ while (i.hasNext()) {
+ const Replace &cmd = i.next();
+ if (overlaps(pos, length, cmd.pos, cmd.length))
+ return true;
+ }
+ }
+ {
+ QListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ const Move &cmd = i.next();
+ if (overlaps(pos, length, cmd.pos, cmd.length))
+ return true;
+ }
+ return false;
+ }
+}
+
+bool TextWriter::hasMoveInto(int pos, int length)
+{
+ QListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ const Move &cmd = i.next();
+ if (cmd.to >= pos && cmd.to < pos + length)
+ return true;
+ }
+ return false;
+}
+
+void TextWriter::replace(int pos, int length, const QString &replacement)
+{
+ Q_ASSERT(!hasOverlap(pos, length));
+ Q_ASSERT(!hasMoveInto(pos, length));
+
+ Replace cmd;
+ cmd.pos = pos;
+ cmd.length = length;
+ cmd.replacement = replacement;
+ replaceList += cmd;
+}
+
+void TextWriter::move(int pos, int length, int to)
+{
+ Q_ASSERT(!hasOverlap(pos, length));
+
+ Move cmd;
+ cmd.pos = pos;
+ cmd.length = length;
+ cmd.to = to;
+ moveList += cmd;
+}
+
+void TextWriter::doReplace(const Replace &replace)
+{
+ int diff = replace.replacement.size() - replace.length;
+ {
+ QMutableListIterator<Replace> i(replaceList);
+ while (i.hasNext()) {
+ Replace &c = i.next();
+ if (replace.pos < c.pos)
+ c.pos += diff;
+ else if (replace.pos + replace.length < c.pos + c.length)
+ c.length += diff;
+ }
+ }
+ {
+ QMutableListIterator<Move> i(moveList);
+ while (i.hasNext()) {
+ Move &c = i.next();
+ if (replace.pos < c.pos)
+ c.pos += diff;
+ else if (replace.pos + replace.length < c.pos + c.length)
+ c.length += diff;
+
+ if (replace.pos < c.to)
+ c.to += diff;
+ }
+ }
+
+ if (string) {
+ string->replace(replace.pos, replace.length, replace.replacement);
+ } else if (cursor) {
+ cursor->setPosition(replace.pos);
+ cursor->setPosition(replace.pos + replace.length, QTextCursor::KeepAnchor);
+ cursor->insertText(replace.replacement);
+ }
+}
+
+void TextWriter::doMove(const Move &move)
+{
+ QString text;
+ if (string) {
+ text = string->mid(move.pos, move.length);
+ } else if (cursor) {
+ cursor->setPosition(move.pos);
+ cursor->setPosition(move.pos + move.length, QTextCursor::KeepAnchor);
+ text = cursor->selectedText();
+ }
+
+ Replace cut;
+ cut.pos = move.pos;
+ cut.length = move.length;
+ Replace paste;
+ paste.pos = move.to;
+ paste.length = 0;
+ paste.replacement = text;
+
+ replaceList.append(cut);
+ replaceList.append(paste);
+
+ Replace cmd;
+ while (!replaceList.isEmpty()) {
+ cmd = replaceList.first();
+ replaceList.removeFirst();
+ doReplace(cmd);
+ }
+}
+
+void TextWriter::write(QString *s)
+{
+ string = s;
+ write_helper();
+ string = 0;
+}
+
+void TextWriter::write(QTextCursor *textCursor)
+{
+ cursor = textCursor;
+ write_helper();
+ cursor = 0;
+}
+
+void TextWriter::write_helper()
+{
+ if (cursor)
+ cursor->beginEditBlock();
+ {
+ Replace cmd;
+ while (!replaceList.isEmpty()) {
+ cmd = replaceList.first();
+ replaceList.removeFirst();
+ doReplace(cmd);
+ }
+ }
+ {
+ Move cmd;
+ while (!moveList.isEmpty()) {
+ cmd = moveList.first();
+ moveList.removeFirst();
+ doMove(cmd);
+ }
+ }
+ if (cursor)
+ cursor->endEditBlock();
+}
+
+QT_QML_END_NAMESPACE
diff --git a/src/declarative/qml/rewriter/textwriter_p.h b/src/declarative/qml/rewriter/textwriter_p.h
new file mode 100644
index 0000000000..90249be299
--- /dev/null
+++ b/src/declarative/qml/rewriter/textwriter_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 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 TEXTWRITER_H
+#define TEXTWRITER_H
+
+#include <qdeclarativejsglobal_p.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtGui/QTextCursor>
+
+QT_BEGIN_HEADER
+QT_QML_BEGIN_NAMESPACE
+
+namespace QDeclarativeJS {
+
+class TextWriter
+{
+ QString *string;
+ QTextCursor *cursor;
+
+ struct Replace {
+ int pos;
+ int length;
+ QString replacement;
+ };
+
+ QList<Replace> replaceList;
+
+ struct Move {
+ int pos;
+ int length;
+ int to;
+ };
+
+ QList<Move> moveList;
+
+ bool hasOverlap(int pos, int length);
+ bool hasMoveInto(int pos, int length);
+
+ void doReplace(const Replace &replace);
+ void doMove(const Move &move);
+
+ void write_helper();
+
+public:
+ TextWriter();
+
+ void replace(int pos, int length, const QString &replacement);
+ void move(int pos, int length, int to);
+
+ void write(QString *s);
+ void write(QTextCursor *textCursor);
+
+};
+
+} // end of namespace QDeclarativeJS
+
+QT_QML_END_NAMESPACE
+QT_END_HEADER
+
+#endif // TEXTWRITER_H
diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp
new file mode 100644
index 0000000000..b3bf84b9f5
--- /dev/null
+++ b/src/declarative/util/qdeclarativeanimation.cpp
@@ -0,0 +1,2948 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeanimation_p.h"
+#include "private/qdeclarativeanimation_p_p.h"
+
+#include "private/qdeclarativebehavior_p.h"
+#include "private/qdeclarativestateoperations_p.h"
+#include "private/qdeclarativecontext_p.h"
+
+#include <qdeclarativepropertyvaluesource.h>
+#include <qdeclarative.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativeexpression.h>
+#include <qdeclarativestringconverters_p.h>
+#include <qdeclarativeglobal_p.h>
+#include <qdeclarativemetatype_p.h>
+#include <qdeclarativevaluetype_p.h>
+#include <qdeclarativeproperty_p.h>
+#include <qdeclarativeengine_p.h>
+
+#include <qvariant.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <QParallelAnimationGroup>
+#include <QSequentialAnimationGroup>
+#include <QtCore/qset.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qmath.h>
+
+#include <private/qvariantanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Animation QDeclarativeAbstractAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \brief The Animation element is the base of all QML animations.
+
+ The Animation element cannot be used directly in a QML file. It exists
+ to provide a set of common properties and methods, available across all the
+ other animation types that inherit from it. Attempting to use the Animation
+ element directly will result in an error.
+*/
+
+QDeclarativeAbstractAnimation::QDeclarativeAbstractAnimation(QObject *parent)
+: QObject(*(new QDeclarativeAbstractAnimationPrivate), parent)
+{
+}
+
+QDeclarativeAbstractAnimation::~QDeclarativeAbstractAnimation()
+{
+}
+
+QDeclarativeAbstractAnimation::QDeclarativeAbstractAnimation(QDeclarativeAbstractAnimationPrivate &dd, QObject *parent)
+: QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty bool Animation::running
+ This property holds whether the animation is currently running.
+
+ The \c running property can be set to declaratively control whether or not
+ an animation is running. The following example will animate a rectangle
+ whenever the \l MouseArea is pressed.
+
+ \code
+ Rectangle {
+ width: 100; height: 100
+ NumberAnimation on x {
+ running: myMouse.pressed
+ from: 0; to: 100
+ }
+ MouseArea { id: myMouse }
+ }
+ \endcode
+
+ Likewise, the \c running property can be read to determine if the animation
+ is running. In the following example the text element will indicate whether
+ or not the animation is running.
+
+ \code
+ NumberAnimation { id: myAnimation }
+ Text { text: myAnimation.running ? "Animation is running" : "Animation is not running" }
+ \endcode
+
+ Animations can also be started and stopped imperatively from JavaScript
+ using the \c start() and \c stop() methods.
+
+ By default, animations are not running. Though, when the animations are assigned to properties,
+ as property value sources using the \e on syntax, they are set to running by default.
+*/
+bool QDeclarativeAbstractAnimation::isRunning() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->running;
+}
+
+// the behavior calls this function
+void QDeclarativeAbstractAnimation::notifyRunningChanged(bool running)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->disableUserControl && d->running != running) {
+ d->running = running;
+ emit runningChanged(running);
+ }
+}
+
+//commence is called to start an animation when it is used as a
+//simple animation, and not as part of a transition
+void QDeclarativeAbstractAnimationPrivate::commence()
+{
+ Q_Q(QDeclarativeAbstractAnimation);
+
+ QDeclarativeStateActions actions;
+ QDeclarativeProperties properties;
+ q->transition(actions, properties, QDeclarativeAbstractAnimation::Forward);
+
+ q->qtAnimation()->start();
+ if (q->qtAnimation()->state() != QAbstractAnimation::Running) {
+ running = false;
+ emit q->completed();
+ }
+}
+
+QDeclarativeProperty QDeclarativeAbstractAnimationPrivate::createProperty(QObject *obj, const QString &str, QObject *infoObj)
+{
+ QDeclarativeProperty prop(obj, str, qmlContext(infoObj));
+ if (!prop.isValid()) {
+ qmlInfo(infoObj) << QDeclarativeAbstractAnimation::tr("Cannot animate non-existent property \"%1\"").arg(str);
+ return QDeclarativeProperty();
+ } else if (!prop.isWritable()) {
+ qmlInfo(infoObj) << QDeclarativeAbstractAnimation::tr("Cannot animate read-only property \"%1\"").arg(str);
+ return QDeclarativeProperty();
+ }
+ return prop;
+}
+
+void QDeclarativeAbstractAnimation::setRunning(bool r)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (!d->componentComplete) {
+ d->running = r;
+ if (r == false)
+ d->avoidPropertyValueSourceStart = true;
+ else if (!d->registered) {
+ d->registered = true;
+ QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
+ engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ }
+ return;
+ }
+
+ if (d->running == r)
+ return;
+
+ if (d->group || d->disableUserControl) {
+ qmlInfo(this) << "setRunning() cannot be used on non-root animation nodes.";
+ return;
+ }
+
+ d->running = r;
+ if (d->running) {
+ bool supressStart = false;
+ if (d->alwaysRunToEnd && d->loopCount != 1
+ && qtAnimation()->state() == QAbstractAnimation::Running) {
+ //we've restarted before the final loop finished; restore proper loop count
+ if (d->loopCount == -1)
+ qtAnimation()->setLoopCount(d->loopCount);
+ else
+ qtAnimation()->setLoopCount(qtAnimation()->currentLoop() + d->loopCount);
+ supressStart = true; //we want the animation to continue, rather than restart
+ }
+
+ if (!d->connectedTimeLine) {
+ QObject::connect(qtAnimation(), SIGNAL(finished()),
+ this, SLOT(timelineComplete()));
+ d->connectedTimeLine = true;
+ }
+ if (!supressStart)
+ d->commence();
+ emit started();
+ } else {
+ if (d->alwaysRunToEnd) {
+ if (d->loopCount != 1)
+ qtAnimation()->setLoopCount(qtAnimation()->currentLoop()+1); //finish the current loop
+ } else
+ qtAnimation()->stop();
+
+ emit completed();
+ }
+
+ emit runningChanged(d->running);
+}
+
+/*!
+ \qmlproperty bool Animation::paused
+ This property holds whether the animation is currently paused.
+
+ The \c paused property can be set to declaratively control whether or not
+ an animation is paused.
+
+ Animations can also be paused and resumed imperatively from JavaScript
+ using the \c pause() and \c resume() methods.
+
+ By default, animations are not paused.
+*/
+bool QDeclarativeAbstractAnimation::isPaused() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->paused;
+}
+
+void QDeclarativeAbstractAnimation::setPaused(bool p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->paused == p)
+ return;
+
+ if (d->group || d->disableUserControl) {
+ qmlInfo(this) << "setPaused() cannot be used on non-root animation nodes.";
+ return;
+ }
+
+ d->paused = p;
+ if (d->paused)
+ qtAnimation()->pause();
+ else
+ qtAnimation()->resume();
+
+ emit pausedChanged(d->paused);
+}
+
+void QDeclarativeAbstractAnimation::classBegin()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->componentComplete = false;
+}
+
+void QDeclarativeAbstractAnimation::componentComplete()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->componentComplete = true;
+}
+
+void QDeclarativeAbstractAnimation::componentFinalized()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->running) {
+ d->running = false;
+ setRunning(true);
+ }
+}
+
+/*!
+ \qmlproperty bool Animation::alwaysRunToEnd
+ This property holds whether the animation should run to completion when it is stopped.
+
+ If this true the animation will complete its current iteration when it
+ is stopped - either by setting the \c running property to false, or by
+ calling the \c stop() method. The \c complete() method is not effected
+ by this value.
+
+ This behavior is most useful when the \c repeat property is set, as the
+ animation will finish playing normally but not restart.
+
+ By default, the alwaysRunToEnd property is not set.
+
+ \note alwaysRunToEnd has no effect on animations in a Transition.
+*/
+bool QDeclarativeAbstractAnimation::alwaysRunToEnd() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->alwaysRunToEnd;
+}
+
+void QDeclarativeAbstractAnimation::setAlwaysRunToEnd(bool f)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->alwaysRunToEnd == f)
+ return;
+
+ d->alwaysRunToEnd = f;
+ emit alwaysRunToEndChanged(f);
+}
+
+/*!
+ \qmlproperty int Animation::loops
+ This property holds the number of times the animation should play.
+
+ By default, \c loops is 1: the animation will play through once and then stop.
+
+ If set to Animation.Infinite, the animation will continuously repeat until it is explicitly
+ stopped - either by setting the \c running property to false, or by calling
+ the \c stop() method.
+
+ In the following example, the rectangle will spin indefinitely.
+
+ \code
+ Rectangle {
+ width: 100; height: 100; color: "green"
+ RotationAnimation on rotation {
+ loops: Animation.Infinite
+ from: 0
+ to: 360
+ }
+ }
+ \endcode
+*/
+int QDeclarativeAbstractAnimation::loops() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->loopCount;
+}
+
+void QDeclarativeAbstractAnimation::setLoops(int loops)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (loops < 0)
+ loops = -1;
+
+ if (loops == d->loopCount)
+ return;
+
+ d->loopCount = loops;
+ qtAnimation()->setLoopCount(loops);
+ emit loopCountChanged(loops);
+}
+
+
+int QDeclarativeAbstractAnimation::currentTime()
+{
+ return qtAnimation()->currentLoopTime();
+}
+
+void QDeclarativeAbstractAnimation::setCurrentTime(int time)
+{
+ qtAnimation()->setCurrentTime(time);
+}
+
+QDeclarativeAnimationGroup *QDeclarativeAbstractAnimation::group() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->group;
+}
+
+void QDeclarativeAbstractAnimation::setGroup(QDeclarativeAnimationGroup *g)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->group == g)
+ return;
+ if (d->group)
+ static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.removeAll(this);
+
+ d->group = g;
+
+ if (d->group && !static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.contains(this))
+ static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.append(this);
+
+ //if (g) //if removed from a group, then the group should no longer be the parent
+ setParent(g);
+}
+
+/*!
+ \qmlmethod Animation::start()
+ \brief Starts the animation.
+
+ If the animation is already running, calling this method has no effect. The
+ \c running property will be true following a call to \c start().
+*/
+void QDeclarativeAbstractAnimation::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod Animation::pause()
+ \brief Pauses the animation.
+
+ If the animation is already paused, calling this method has no effect. The
+ \c paused property will be true following a call to \c pause().
+*/
+void QDeclarativeAbstractAnimation::pause()
+{
+ setPaused(true);
+}
+
+/*!
+ \qmlmethod Animation::resume()
+ \brief Resumes a paused animation.
+
+ If the animation is not paused, calling this method has no effect. The
+ \c paused property will be false following a call to \c resume().
+*/
+void QDeclarativeAbstractAnimation::resume()
+{
+ setPaused(false);
+}
+
+/*!
+ \qmlmethod Animation::stop()
+ \brief Stops the animation.
+
+ If the animation is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c stop().
+
+ Normally \c stop() stops the animation immediately, and the animation has
+ no further influence on property values. In this example animation
+ \code
+ Rectangle {
+ NumberAnimation on x { from: 0; to: 100; duration: 500 }
+ }
+ \endcode
+ was stopped at time 250ms, the \c x property will have a value of 50.
+
+ However, if the \c alwaysRunToEnd property is set, the animation will
+ continue running until it completes and then stop. The \c running property
+ will still become false immediately.
+*/
+void QDeclarativeAbstractAnimation::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod Animation::restart()
+ \brief Restarts the animation.
+
+ This is a convenience method, and is equivalent to calling \c stop() and
+ then \c start().
+*/
+void QDeclarativeAbstractAnimation::restart()
+{
+ stop();
+ start();
+}
+
+/*!
+ \qmlmethod Animation::complete()
+ \brief Stops the animation, jumping to the final property values.
+
+ If the animation is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c complete().
+
+ Unlike \c stop(), \c complete() immediately fast-forwards the animation to
+ its end. In the following example,
+ \code
+ Rectangle {
+ NumberAnimation on x { from: 0; to: 100; duration: 500 }
+ }
+ \endcode
+ calling \c stop() at time 250ms will result in the \c x property having
+ a value of 50, while calling \c complete() will set the \c x property to
+ 100, exactly as though the animation had played the whole way through.
+*/
+void QDeclarativeAbstractAnimation::complete()
+{
+ if (isRunning()) {
+ qtAnimation()->setCurrentTime(qtAnimation()->duration());
+ }
+}
+
+void QDeclarativeAbstractAnimation::setTarget(const QDeclarativeProperty &p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->defaultProperty = p;
+
+ if (!d->avoidPropertyValueSourceStart)
+ setRunning(true);
+}
+
+/*
+ we rely on setTarget only being called when used as a value source
+ so this function allows us to do the same thing as setTarget without
+ that assumption
+*/
+void QDeclarativeAbstractAnimation::setDefaultTarget(const QDeclarativeProperty &p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->defaultProperty = p;
+}
+
+/*
+ don't allow start/stop/pause/resume to be manually invoked,
+ because something else (like a Behavior) already has control
+ over the animation.
+*/
+void QDeclarativeAbstractAnimation::setDisableUserControl()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->disableUserControl = true;
+}
+
+void QDeclarativeAbstractAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(actions);
+ Q_UNUSED(modified);
+ Q_UNUSED(direction);
+}
+
+void QDeclarativeAbstractAnimation::timelineComplete()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ setRunning(false);
+ if (d->alwaysRunToEnd && d->loopCount != 1) {
+ //restore the proper loopCount for the next run
+ qtAnimation()->setLoopCount(d->loopCount);
+ }
+}
+
+/*!
+ \qmlclass PauseAnimation QDeclarativePauseAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The PauseAnimation element provides a pause for an animation.
+
+ When used in a SequentialAnimation, PauseAnimation is a step when
+ nothing happens, for a specified duration.
+
+ A 500ms animation sequence, with a 100ms pause between two animations:
+ \code
+ SequentialAnimation {
+ NumberAnimation { ... duration: 200 }
+ PauseAnimation { duration: 100 }
+ NumberAnimation { ... duration: 200 }
+ }
+ \endcode
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativePauseAnimation::QDeclarativePauseAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePauseAnimationPrivate), parent)
+{
+ Q_D(QDeclarativePauseAnimation);
+ d->init();
+}
+
+QDeclarativePauseAnimation::~QDeclarativePauseAnimation()
+{
+}
+
+void QDeclarativePauseAnimationPrivate::init()
+{
+ Q_Q(QDeclarativePauseAnimation);
+ pa = new QPauseAnimation;
+ QDeclarative_setParent_noEvent(pa, q);
+}
+
+/*!
+ \qmlproperty int PauseAnimation::duration
+ This property holds the duration of the pause in milliseconds
+
+ The default value is 250.
+*/
+int QDeclarativePauseAnimation::duration() const
+{
+ Q_D(const QDeclarativePauseAnimation);
+ return d->pa->duration();
+}
+
+void QDeclarativePauseAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QDeclarativePauseAnimation);
+ if (d->pa->duration() == duration)
+ return;
+ d->pa->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+QAbstractAnimation *QDeclarativePauseAnimation::qtAnimation()
+{
+ Q_D(QDeclarativePauseAnimation);
+ return d->pa;
+}
+
+/*!
+ \qmlclass ColorAnimation QDeclarativeColorAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits PropertyAnimation
+ \brief The ColorAnimation element animates changes in color values.
+
+ ColorAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a color value changes.
+
+ Here is a ColorAnimation applied to the \c color property of a \l Rectangle
+ as a property value source. It animates the \c color property's value from
+ its current value to a value of "red", over 1000 milliseconds:
+
+ \snippet doc/src/snippets/declarative/coloranimation.qml 0
+
+ Like any other animation element, a ColorAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ For convenience, when a ColorAnimation is used in a \l Transition, it will
+ animate any \c color properties that have been modified during the state
+ change. If a \l{PropertyAnimation::}{property} or
+ \l{PropertyAnimation::}{properties} are explicitly set for the animation,
+ then those are used instead.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeColorAnimation::QDeclarativeColorAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QColor;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QDeclarativeColorAnimation::~QDeclarativeColorAnimation()
+{
+}
+
+/*!
+ \qmlproperty color ColorAnimation::from
+ This property holds the color value at which the animation should begin.
+
+ For example, the following animation is not applied until a color value
+ has reached "#c0c0c0":
+
+ \qml
+ Item {
+ states: [
+ // States are defined here...
+ ]
+
+ transition: Transition {
+ NumberAnimation { from: "#c0c0c0"; duration: 2000 }
+ }
+ }
+ \endqml
+
+ If the ColorAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QColor QDeclarativeColorAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.value<QColor>();
+}
+
+void QDeclarativeColorAnimation::setFrom(const QColor &f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty color ColorAnimation::to
+
+ This property holds the color value at which the animation should end.
+
+ If the ColorAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QColor QDeclarativeColorAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.value<QColor>();
+}
+
+void QDeclarativeColorAnimation::setTo(const QColor &t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass ScriptAction QDeclarativeScriptAction
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The ScriptAction element allows scripts to be run during an animation.
+
+ ScriptAction can be used to run a script at a specific point in an animation.
+
+ \qml
+ SequentialAnimation {
+ NumberAnimation {
+ // ...
+ }
+ ScriptAction { script: doSomething(); }
+ NumberAnimation {
+ // ...
+ }
+ }
+ \endqml
+
+ When used as part of a Transition, you can also target a specific
+ StateChangeScript to run using the \c scriptName property.
+
+ \snippet doc/src/snippets/declarative/states/statechangescript.qml state and transition
+
+ \sa StateChangeScript
+*/
+QDeclarativeScriptAction::QDeclarativeScriptAction(QObject *parent)
+ :QDeclarativeAbstractAnimation(*(new QDeclarativeScriptActionPrivate), parent)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->init();
+}
+
+QDeclarativeScriptAction::~QDeclarativeScriptAction()
+{
+}
+
+void QDeclarativeScriptActionPrivate::init()
+{
+ Q_Q(QDeclarativeScriptAction);
+ rsa = new QActionAnimation(&proxy);
+ QDeclarative_setParent_noEvent(rsa, q);
+}
+
+/*!
+ \qmlproperty script ScriptAction::script
+ This property holds the script to run.
+*/
+QDeclarativeScriptString QDeclarativeScriptAction::script() const
+{
+ Q_D(const QDeclarativeScriptAction);
+ return d->script;
+}
+
+void QDeclarativeScriptAction::setScript(const QDeclarativeScriptString &script)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->script = script;
+}
+
+/*!
+ \qmlproperty string ScriptAction::scriptName
+ This property holds the the name of the StateChangeScript to run.
+
+ This property is only valid when ScriptAction is used as part of a transition.
+ If both script and scriptName are set, scriptName will be used.
+
+ \note When using scriptName in a reversible transition, the script will only
+ be run when the transition is being run forwards.
+*/
+QString QDeclarativeScriptAction::stateChangeScriptName() const
+{
+ Q_D(const QDeclarativeScriptAction);
+ return d->name;
+}
+
+void QDeclarativeScriptAction::setStateChangeScriptName(const QString &name)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->name = name;
+}
+
+void QDeclarativeScriptActionPrivate::execute()
+{
+ Q_Q(QDeclarativeScriptAction);
+ if (hasRunScriptScript && reversing)
+ return;
+
+ QDeclarativeScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
+
+ const QString &str = scriptStr.script();
+ if (!str.isEmpty()) {
+ QDeclarativeExpression expr(scriptStr.context(), scriptStr.scopeObject(), str);
+ QDeclarativeData *ddata = QDeclarativeData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expr.setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ expr.evaluate();
+ if (expr.hasError())
+ qmlInfo(q) << expr.error();
+ }
+}
+
+void QDeclarativeScriptAction::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeScriptAction);
+ Q_UNUSED(modified);
+
+ d->hasRunScriptScript = false;
+ d->reversing = (direction == Backward);
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ if (action.event && action.event->typeName() == QLatin1String("StateChangeScript")
+ && static_cast<QDeclarativeStateChangeScript*>(action.event)->name() == d->name) {
+ d->runScriptScript = static_cast<QDeclarativeStateChangeScript*>(action.event)->script();
+ d->hasRunScriptScript = true;
+ action.actionDone = true;
+ break; //only match one (names should be unique)
+ }
+ }
+}
+
+QAbstractAnimation *QDeclarativeScriptAction::qtAnimation()
+{
+ Q_D(QDeclarativeScriptAction);
+ return d->rsa;
+}
+
+
+
+/*!
+ \qmlclass PropertyAction QDeclarativePropertyAction
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The PropertyAction element allows immediate property changes during animation.
+
+ PropertyAction is used to specify an immediate property change during an
+ animation. The property change is not animated.
+
+ It is useful for setting non-animated property values during an animation.
+
+ For example, here is a SequentialAnimation that sets the image's
+ \l {Image::}{smooth} property to \c true, animates the width of the image,
+ then sets \l {Image::}{smooth} back to \c false:
+
+ \snippet doc/src/snippets/declarative/propertyaction.qml standalone
+
+ PropertyAction is also useful for setting the exact point at which a property
+ change should occur during a \l Transition. For example, if PropertyChanges
+ was used in a \l State to rotate an item around a particular
+ \l {Item::}{transformOrigin}, it might be implemented like this:
+
+ \snippet doc/src/snippets/declarative/propertyaction.qml transition
+
+ However, with this code, the \c transformOrigin is not set until \e after
+ the animation, as a \l State is taken to define the values at the \e end of
+ a transition. The animation would rotate at the default \c transformOrigin,
+ then jump to \c Item.BottomRight. To fix this, insert a PropertyAction
+ before the RotationAnimation begins:
+
+ \snippet doc/src/snippets/declarative/propertyaction-sequential.qml sequential
+
+ This immediately sets the \c transformOrigin property to the value defined
+ in the end state of the \l Transition (i.e. the value defined in the
+ PropertyAction object) so that the rotation animation begins with the
+ correct transform origin.
+
+ \sa {QML Animation and Transitions}, QtDeclarative
+*/
+QDeclarativePropertyAction::QDeclarativePropertyAction(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePropertyActionPrivate), parent)
+{
+ Q_D(QDeclarativePropertyAction);
+ d->init();
+}
+
+QDeclarativePropertyAction::~QDeclarativePropertyAction()
+{
+}
+
+void QDeclarativePropertyActionPrivate::init()
+{
+ Q_Q(QDeclarativePropertyAction);
+ spa = new QActionAnimation;
+ QDeclarative_setParent_noEvent(spa, q);
+}
+
+QObject *QDeclarativePropertyAction::target() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->target;
+}
+
+void QDeclarativePropertyAction::setTarget(QObject *o)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->target == o)
+ return;
+ d->target = o;
+ emit targetChanged();
+}
+
+QString QDeclarativePropertyAction::property() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->propertyName;
+}
+
+void QDeclarativePropertyAction::setProperty(const QString &n)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->propertyName == n)
+ return;
+ d->propertyName = n;
+ emit propertyChanged();
+}
+
+/*!
+ \qmlproperty Object PropertyAction::target
+ \qmlproperty list<Object> PropertyAction::targets
+ \qmlproperty string PropertyAction::property
+ \qmlproperty string PropertyAction::properties
+
+ These properties determine the items and their properties that are
+ affected by this action.
+
+ The details of how these properties are interpreted in different situations
+ is covered in the \l{PropertyAnimation::properties}{corresponding} PropertyAnimation
+ documentation.
+
+ \sa exclude
+*/
+QString QDeclarativePropertyAction::properties() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->properties;
+}
+
+void QDeclarativePropertyAction::setProperties(const QString &p)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->properties == p)
+ return;
+ d->properties = p;
+ emit propertiesChanged(p);
+}
+
+QDeclarativeListProperty<QObject> QDeclarativePropertyAction::targets()
+{
+ Q_D(QDeclarativePropertyAction);
+ return QDeclarativeListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAction::exclude
+ This property holds the objects that should not be affected by this action.
+
+ \sa targets
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAction::exclude()
+{
+ Q_D(QDeclarativePropertyAction);
+ return QDeclarativeListProperty<QObject>(this, d->exclude);
+}
+
+/*!
+ \qmlproperty any PropertyAction::value
+ This property holds the value to be set on the property.
+
+ If the PropertyAction is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+*/
+QVariant QDeclarativePropertyAction::value() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->value;
+}
+
+void QDeclarativePropertyAction::setValue(const QVariant &v)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->value.isNull || d->value != v) {
+ d->value = v;
+ emit valueChanged(v);
+ }
+}
+
+QAbstractAnimation *QDeclarativePropertyAction::qtAnimation()
+{
+ Q_D(QDeclarativePropertyAction);
+ return d->spa;
+}
+
+void QDeclarativePropertyAction::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativePropertyAction);
+ Q_UNUSED(direction);
+
+ struct QDeclarativeSetPropertyAnimationAction : public QAbstractAnimationAction
+ {
+ QDeclarativeStateActions actions;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QDeclarativeAction &action = actions.at(ii);
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+ };
+
+ QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
+ for (int ii = 0; ii < props.count(); ++ii)
+ props[ii] = props.at(ii).trimmed();
+ if (!d->propertyName.isEmpty())
+ props << d->propertyName;
+
+ QList<QObject*> targets = d->targets;
+ if (d->target)
+ targets.append(d->target);
+
+ bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
+
+ if (d->defaultProperty.isValid() && !hasSelectors) {
+ props << d->defaultProperty.name();
+ targets << d->defaultProperty.object();
+ }
+
+ QDeclarativeSetPropertyAnimationAction *data = new QDeclarativeSetPropertyAnimationAction;
+
+ bool hasExplicit = false;
+ //an explicit animation has been specified
+ if (d->value.isValid()) {
+ for (int i = 0; i < props.count(); ++i) {
+ for (int j = 0; j < targets.count(); ++j) {
+ QDeclarativeAction myAction;
+ myAction.property = d->createProperty(targets.at(j), props.at(i), this);
+ if (myAction.property.isValid()) {
+ myAction.toValue = d->value;
+ QDeclarativePropertyAnimationPrivate::convertVariant(myAction.toValue, myAction.property.propertyType());
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+ if (action.property.object() == myAction.property.object() &&
+ myAction.property.name() == action.property.name()) {
+ modified << action.property;
+ break; //### any chance there could be multiples?
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!hasExplicit)
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ QObject *obj = action.property.object();
+ QString propertyName = action.property.name();
+ QObject *sObj = action.specifiedObject;
+ QString sPropertyName = action.specifiedProperty;
+ bool same = (obj == sObj);
+
+ if ((targets.isEmpty() || targets.contains(obj) || (!same && targets.contains(sObj))) &&
+ (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) &&
+ (props.contains(propertyName) || (!same && props.contains(sPropertyName)))) {
+ QDeclarativeAction myAction = action;
+
+ if (d->value.isValid())
+ myAction.toValue = d->value;
+ QDeclarativePropertyAnimationPrivate::convertVariant(myAction.toValue, myAction.property.propertyType());
+
+ modified << action.property;
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ }
+ }
+
+ if (data->actions.count()) {
+ d->spa->setAnimAction(data, QAbstractAnimation::DeleteWhenStopped);
+ } else {
+ delete data;
+ }
+}
+
+/*!
+ \qmlclass NumberAnimation QDeclarativeNumberAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits PropertyAnimation
+ \brief The NumberAnimation element animates changes in qreal-type values.
+
+ NumberAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a numerical value changes.
+
+ Here is a NumberAnimation applied to the \c x property of a \l Rectangle
+ as a property value source. It animates the \c x value from its current
+ value to a value of 50, over 1000 milliseconds:
+
+ \snippet doc/src/snippets/declarative/numberanimation.qml 0
+
+ Like any other animation element, a NumberAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ Note that NumberAnimation may not animate smoothly if there are irregular
+ changes in the number value that it is tracking. If this is the case, use
+ SmoothedAnimation instead.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ init();
+}
+
+QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent)
+: QDeclarativePropertyAnimation(dd, parent)
+{
+ init();
+}
+
+QDeclarativeNumberAnimation::~QDeclarativeNumberAnimation()
+{
+}
+
+void QDeclarativeNumberAnimation::init()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QReal;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+}
+
+/*!
+ \qmlproperty real NumberAnimation::from
+ This property holds the starting value for the animation.
+
+ For example, the following animation is not applied until the \c x value
+ has reached 100:
+
+ \qml
+ Item {
+ states: [
+ // ...
+ ]
+
+ transition: Transition {
+ NumberAnimation { properties: "x"; from: 100; duration: 200 }
+ }
+ }
+ \endqml
+
+ If the NumberAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+
+qreal QDeclarativeNumberAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.toReal();
+}
+
+void QDeclarativeNumberAnimation::setFrom(qreal f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real NumberAnimation::to
+ This property holds the end value for the animation.
+
+ If the NumberAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeNumberAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.toReal();
+}
+
+void QDeclarativeNumberAnimation::setTo(qreal t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass Vector3dAnimation QDeclarativeVector3dAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits PropertyAnimation
+ \brief The Vector3dAnimation element animates changes in QVector3d values.
+
+ Vector3dAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a Vector3d value changes.
+
+ Like any other animation element, a Vector3dAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeVector3dAnimation::QDeclarativeVector3dAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QVector3D;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QDeclarativeVector3dAnimation::~QDeclarativeVector3dAnimation()
+{
+}
+
+/*!
+ \qmlproperty real Vector3dAnimation::from
+ This property holds the starting value for the animation.
+
+ If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QVector3D QDeclarativeVector3dAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.value<QVector3D>();
+}
+
+void QDeclarativeVector3dAnimation::setFrom(QVector3D f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real Vector3dAnimation::to
+ This property holds the end value for the animation.
+
+ If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QVector3D QDeclarativeVector3dAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.value<QVector3D>();
+}
+
+void QDeclarativeVector3dAnimation::setTo(QVector3D t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass RotationAnimation QDeclarativeRotationAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits PropertyAnimation
+ \brief The RotationAnimation element animates changes in rotation values.
+
+ RotationAnimation is a specialized PropertyAnimation that gives control
+ over the direction of rotation during an animation.
+
+ By default, it rotates in the direction
+ of the numerical change; a rotation from 0 to 240 will rotate 240 degrees
+ clockwise, while a rotation from 240 to 0 will rotate 240 degrees
+ counterclockwise. The \l direction property can be set to specify the
+ direction in which the rotation should occur.
+
+ In the following example we use RotationAnimation to animate the rotation
+ between states via the shortest path:
+
+ \snippet doc/src/snippets/declarative/rotationanimation.qml 0
+
+ Notice the RotationAnimation did not need to set a \l target
+ value. As a convenience, when used in a transition, RotationAnimation will rotate all
+ properties named "rotation" or "angle". You can override this by providing
+ your own properties via \l {PropertyAnimation::properties}{properties} or
+ \l {PropertyAnimation::property}{property}.
+
+ Also, note the \l Rectangle will be rotated around its default
+ \l {Item::}{transformOrigin} (which is \c Item.Center). To use a different
+ transform origin, set the origin in the PropertyChanges object and apply
+ the change at the start of the animation using PropertyAction. See the
+ PropertyAction documentation for more details.
+
+ Like any other animation element, a RotationAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff > 180.0){
+ newt -= 360.0;
+ diff -= 360.0;
+ }
+ while(diff < -180.0){
+ newt += 360.0;
+ diff += 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff < 0.0){
+ newt += 360.0;
+ diff += 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff > 0.0){
+ newt -= 360.0;
+ diff -= 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QDeclarativeRotationAnimation::QDeclarativeRotationAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(*(new QDeclarativeRotationAnimationPrivate), parent)
+{
+ Q_D(QDeclarativeRotationAnimation);
+ d->interpolatorType = QMetaType::QReal;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultProperties = QLatin1String("rotation,angle");
+}
+
+QDeclarativeRotationAnimation::~QDeclarativeRotationAnimation()
+{
+}
+
+/*!
+ \qmlproperty real RotationAnimation::from
+ This property holds the starting value for the animation.
+
+ For example, the following animation is not applied until the \c angle value
+ has reached 100:
+
+ \qml
+ Item {
+ states: [
+ // ...
+ ]
+
+ transition: Transition {
+ RotationAnimation { properties: "angle"; from: 100; duration: 2000 }
+ }
+ }
+ \endqml
+
+ If the RotationAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeRotationAnimation::from() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->from.toReal();
+}
+
+void QDeclarativeRotationAnimation::setFrom(qreal f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real RotationAnimation::to
+ This property holds the end value for the animation..
+
+ If the RotationAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeRotationAnimation::to() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->to.toReal();
+}
+
+void QDeclarativeRotationAnimation::setTo(qreal t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+/*!
+ \qmlproperty enumeration RotationAnimation::direction
+ This property holds the direction of the rotation.
+
+ Possible values are:
+
+ \list
+ \o RotationAnimation.Numerical (default) - Rotate by linearly interpolating between the two numbers.
+ A rotation from 10 to 350 will rotate 340 degrees clockwise.
+ \o RotationAnimation.Clockwise - Rotate clockwise between the two values
+ \o RotationAnimation.Counterclockwise - Rotate counterclockwise between the two values
+ \o RotationAnimation.Shortest - Rotate in the direction that produces the shortest animation path.
+ A rotation from 10 to 350 will rotate 20 degrees counterclockwise.
+ \endlist
+*/
+QDeclarativeRotationAnimation::RotationDirection QDeclarativeRotationAnimation::direction() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->direction;
+}
+
+void QDeclarativeRotationAnimation::setDirection(QDeclarativeRotationAnimation::RotationDirection direction)
+{
+ Q_D(QDeclarativeRotationAnimation);
+ if (d->direction == direction)
+ return;
+
+ d->direction = direction;
+ switch(d->direction) {
+ case Clockwise:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateClockwiseRotation);
+ break;
+ case Counterclockwise:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateCounterclockwiseRotation);
+ break;
+ case Shortest:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateShortestRotation);
+ break;
+ default:
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ break;
+ }
+
+ emit directionChanged();
+}
+
+
+
+QDeclarativeAnimationGroup::QDeclarativeAnimationGroup(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativeAnimationGroupPrivate), parent)
+{
+}
+
+QDeclarativeAnimationGroup::QDeclarativeAnimationGroup(QDeclarativeAnimationGroupPrivate &dd, QObject *parent)
+ : QDeclarativeAbstractAnimation(dd, parent)
+{
+}
+
+void QDeclarativeAnimationGroupPrivate::append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a)
+{
+ QDeclarativeAnimationGroup *q = qobject_cast<QDeclarativeAnimationGroup *>(list->object);
+ if (q) {
+ a->setGroup(q);
+ QDeclarative_setParent_noEvent(a->qtAnimation(), q->d_func()->ag);
+ q->d_func()->ag->addAnimation(a->qtAnimation());
+ }
+}
+
+void QDeclarativeAnimationGroupPrivate::clear_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list)
+{
+ QDeclarativeAnimationGroup *q = qobject_cast<QDeclarativeAnimationGroup *>(list->object);
+ if (q) {
+ for (int i = 0; i < q->d_func()->animations.count(); ++i)
+ q->d_func()->animations.at(i)->setGroup(0);
+ q->d_func()->animations.clear();
+ }
+}
+
+QDeclarativeAnimationGroup::~QDeclarativeAnimationGroup()
+{
+}
+
+QDeclarativeListProperty<QDeclarativeAbstractAnimation> QDeclarativeAnimationGroup::animations()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> list(this, d->animations);
+ list.append = &QDeclarativeAnimationGroupPrivate::append_animation;
+ list.clear = &QDeclarativeAnimationGroupPrivate::clear_animation;
+ return list;
+}
+
+/*!
+ \qmlclass SequentialAnimation QDeclarativeSequentialAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The SequentialAnimation element allows animations to be run sequentially.
+
+ The SequentialAnimation and ParallelAnimation elements allow multiple
+ animations to be run together. Animations defined in a SequentialAnimation
+ are run one after the other, while animations defined in a ParallelAnimation
+ are run at the same time.
+
+ The following example runs two number animations in a sequence. The \l Rectangle
+ animates to a \c x position of 50, then to a \c y position of 50.
+
+ \snippet doc/src/snippets/declarative/sequentialanimation.qml 0
+
+ Animations defined within a \l Transition are automatically run in parallel,
+ so SequentialAnimation can be used to enclose the animations in a \l Transition
+ if this is the preferred behavior.
+
+ Like any other animation element, a SequentialAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \note Once an animation has been grouped into a SequentialAnimation or
+ ParallelAnimation, it cannot be individually started and stopped; the
+ SequentialAnimation or ParallelAnimation must be started and stopped as a group.
+
+ \sa ParallelAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativeSequentialAnimation::QDeclarativeSequentialAnimation(QObject *parent) :
+ QDeclarativeAnimationGroup(parent)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ d->ag = new QSequentialAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, this);
+}
+
+QDeclarativeSequentialAnimation::~QDeclarativeSequentialAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeSequentialAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ return d->ag;
+}
+
+void QDeclarativeSequentialAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeAnimationGroup);
+
+ int inc = 1;
+ int from = 0;
+ if (direction == Backward) {
+ inc = -1;
+ from = d->animations.count() - 1;
+ }
+
+ bool valid = d->defaultProperty.isValid();
+ for (int ii = from; ii < d->animations.count() && ii >= 0; ii += inc) {
+ if (valid)
+ d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+}
+
+
+
+/*!
+ \qmlclass ParallelAnimation QDeclarativeParallelAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The ParallelAnimation element allows animations to be run in parallel.
+
+ The SequentialAnimation and ParallelAnimation elements allow multiple
+ animations to be run together. Animations defined in a SequentialAnimation
+ are run one after the other, while animations defined in a ParallelAnimation
+ are run at the same time.
+
+ The following animation runs two number animations in parallel. The \l Rectangle
+ moves to (50,50) by animating its \c x and \c y properties at the same time.
+
+ \snippet doc/src/snippets/declarative/parallelanimation.qml 0
+
+ Like any other animation element, a ParallelAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \note Once an animation has been grouped into a SequentialAnimation or
+ ParallelAnimation, it cannot be individually started and stopped; the
+ SequentialAnimation or ParallelAnimation must be started and stopped as a group.
+
+ \sa SequentialAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeParallelAnimation::QDeclarativeParallelAnimation(QObject *parent) :
+ QDeclarativeAnimationGroup(parent)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ d->ag = new QParallelAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, this);
+}
+
+QDeclarativeParallelAnimation::~QDeclarativeParallelAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeParallelAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ return d->ag;
+}
+
+void QDeclarativeParallelAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ 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);
+ }
+}
+
+
+
+//convert a variant from string type to another animatable type
+void QDeclarativePropertyAnimationPrivate::convertVariant(QVariant &variant, int type)
+{
+ if (variant.userType() != QVariant::String) {
+ variant.convert((QVariant::Type)type);
+ return;
+ }
+
+ switch (type) {
+ case QVariant::Rect: {
+ variant.setValue(QDeclarativeStringConverters::rectFFromString(variant.toString()).toRect());
+ break;
+ }
+ case QVariant::RectF: {
+ variant.setValue(QDeclarativeStringConverters::rectFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Point: {
+ variant.setValue(QDeclarativeStringConverters::pointFFromString(variant.toString()).toPoint());
+ break;
+ }
+ case QVariant::PointF: {
+ variant.setValue(QDeclarativeStringConverters::pointFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Size: {
+ variant.setValue(QDeclarativeStringConverters::sizeFFromString(variant.toString()).toSize());
+ break;
+ }
+ case QVariant::SizeF: {
+ variant.setValue(QDeclarativeStringConverters::sizeFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Color: {
+ variant.setValue(QDeclarativeStringConverters::colorFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Vector3D: {
+ variant.setValue(QDeclarativeStringConverters::vector3DFromString(variant.toString()));
+ break;
+ }
+ default:
+ if (QDeclarativeValueTypeFactory::isValueType((uint)type)) {
+ variant.convert((QVariant::Type)type);
+ } else {
+ QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
+ if (converter)
+ variant = converter(variant.toString());
+ }
+ break;
+ }
+}
+
+/*!
+ \qmlclass PropertyAnimation QDeclarativePropertyAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The PropertyAnimation element animates changes in property values.
+
+ PropertyAnimation provides a way to animate changes to a property's value.
+
+ It can be used to define animations in a number of ways:
+
+ \list
+ \o In a \l Transition
+
+ For example, to animate any objects that have changed their \c x or \c y properties
+ as a result of a state change, using an \c InOutQuad easing curve:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml transition
+
+
+ \o In a \l Behavior
+
+ For example, to animate all changes to a rectangle's \c x property:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml behavior
+
+
+ \o As a property value source
+
+ For example, to repeatedly animate the rectangle's \c x property:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml propertyvaluesource
+
+
+ \o In a signal handler
+
+ For example, to fade out \c theObject when clicked:
+ \qml
+ MouseArea {
+ anchors.fill: theObject
+ onClicked: PropertyAnimation { target: theObject; property: "opacity"; to: 0 }
+ }
+ \endqml
+
+ \o Standalone
+
+ For example, to animate \c rect's \c width property over 500ms, from its current width to 30:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml standalone
+
+ \endlist
+
+ Depending on how the animation is used, the set of properties normally used will be
+ different. For more information see the individual property documentation, as well
+ as the \l{QML Animation and Transitions} introduction.
+
+ Note that PropertyAnimation inherits the abstract \l Animation element.
+ This includes additional properties and methods for controlling the animation.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativePropertyAnimation::QDeclarativePropertyAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePropertyAnimationPrivate), parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->init();
+}
+
+QDeclarativePropertyAnimation::QDeclarativePropertyAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent)
+: QDeclarativeAbstractAnimation(dd, parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->init();
+}
+
+QDeclarativePropertyAnimation::~QDeclarativePropertyAnimation()
+{
+}
+
+void QDeclarativePropertyAnimationPrivate::init()
+{
+ Q_Q(QDeclarativePropertyAnimation);
+ va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(va, q);
+}
+
+/*!
+ \qmlproperty int PropertyAnimation::duration
+ This property holds the duration of the animation, in milliseconds.
+
+ The default value is 250.
+*/
+int QDeclarativePropertyAnimation::duration() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->va->duration();
+}
+
+void QDeclarativePropertyAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+/*!
+ \qmlproperty real PropertyAnimation::from
+ This property holds the starting value for the animation.
+
+ If the PropertyAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QVariant QDeclarativePropertyAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from;
+}
+
+void QDeclarativePropertyAnimation::setFrom(const QVariant &f)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->fromIsDefined && f == d->from)
+ return;
+ d->from = f;
+ d->fromIsDefined = f.isValid();
+ emit fromChanged(f);
+}
+
+/*!
+ \qmlproperty real PropertyAnimation::to
+ This property holds the end value for the animation.
+
+ If the PropertyAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QVariant QDeclarativePropertyAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to;
+}
+
+void QDeclarativePropertyAnimation::setTo(const QVariant &t)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->toIsDefined && t == d->to)
+ return;
+ d->to = t;
+ d->toIsDefined = t.isValid();
+ emit toChanged(t);
+}
+
+/*!
+ \qmlproperty enumeration PropertyAnimation::easing.type
+ \qmlproperty real PropertyAnimation::easing.amplitude
+ \qmlproperty real PropertyAnimation::easing.overshoot
+ \qmlproperty real PropertyAnimation::easing.period
+ \brief the easing curve used for the animation.
+
+ To specify an easing curve you need to specify at least the type. For some curves you can also specify
+ amplitude, period and/or overshoot (more details provided after the table). The default easing curve is
+ \c Easing.Linear.
+
+ \qml
+ PropertyAnimation { properties: "y"; easing.type: Easing.InOutElastic; easing.amplitude: 2.0; easing.period: 1.5 }
+ \endqml
+
+ Available types are:
+
+ \table
+ \row
+ \o \c Easing.Linear
+ \o Easing curve for a linear (t) function: velocity is constant.
+ \o \inlineimage qeasingcurve-linear.png
+ \row
+ \o \c Easing.InQuad
+ \o Easing curve for a quadratic (t^2) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquad.png
+ \row
+ \o \c Easing.OutQuad
+ \o Easing curve for a quadratic (t^2) function: decelerating to zero velocity.
+ \o \inlineimage qeasingcurve-outquad.png
+ \row
+ \o \c Easing.InOutQuad
+ \o Easing curve for a quadratic (t^2) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquad.png
+ \row
+ \o \c Easing.OutInQuad
+ \o Easing curve for a quadratic (t^2) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquad.png
+ \row
+ \o \c Easing.InCubic
+ \o Easing curve for a cubic (t^3) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incubic.png
+ \row
+ \o \c Easing.OutCubic
+ \o Easing curve for a cubic (t^3) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcubic.png
+ \row
+ \o \c Easing.InOutCubic
+ \o Easing curve for a cubic (t^3) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcubic.png
+ \row
+ \o \c Easing.OutInCubic
+ \o Easing curve for a cubic (t^3) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincubic.png
+ \row
+ \o \c Easing.InQuart
+ \o Easing curve for a quartic (t^4) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquart.png
+ \row
+ \o \c Easing.OutQuart
+ \o Easing curve for a quartic (t^4) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquart.png
+ \row
+ \o \c Easing.InOutQuart
+ \o Easing curve for a quartic (t^4) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquart.png
+ \row
+ \o \c Easing.OutInQuart
+ \o Easing curve for a quartic (t^4) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquart.png
+ \row
+ \o \c Easing.InQuint
+ \o Easing curve for a quintic (t^5) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquint.png
+ \row
+ \o \c Easing.OutQuint
+ \o Easing curve for a quintic (t^5) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquint.png
+ \row
+ \o \c Easing.InOutQuint
+ \o Easing curve for a quintic (t^5) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquint.png
+ \row
+ \o \c Easing.OutInQuint
+ \o Easing curve for a quintic (t^5) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquint.png
+ \row
+ \o \c Easing.InSine
+ \o Easing curve for a sinusoidal (sin(t)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-insine.png
+ \row
+ \o \c Easing.OutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outsine.png
+ \row
+ \o \c Easing.InOutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutsine.png
+ \row
+ \o \c Easing.OutInSine
+ \o Easing curve for a sinusoidal (sin(t)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinsine.png
+ \row
+ \o \c Easing.InExpo
+ \o Easing curve for an exponential (2^t) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inexpo.png
+ \row
+ \o \c Easing.OutExpo
+ \o Easing curve for an exponential (2^t) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outexpo.png
+ \row
+ \o \c Easing.InOutExpo
+ \o Easing curve for an exponential (2^t) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutexpo.png
+ \row
+ \o \c Easing.OutInExpo
+ \o Easing curve for an exponential (2^t) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinexpo.png
+ \row
+ \o \c Easing.InCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incirc.png
+ \row
+ \o \c Easing.OutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcirc.png
+ \row
+ \o \c Easing.InOutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcirc.png
+ \row
+ \o \c Easing.OutInCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincirc.png
+ \row
+ \o \c Easing.InElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: accelerating from zero velocity.
+ \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
+ \o \inlineimage qeasingcurve-inelastic.png
+ \row
+ \o \c Easing.OutElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: decelerating from zero velocity.
+ \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
+ \o \inlineimage qeasingcurve-outelastic.png
+ \row
+ \o \c Easing.InOutElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutelastic.png
+ \row
+ \o \c Easing.OutInElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinelastic.png
+ \row
+ \o \c Easing.InBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inback.png
+ \row
+ \o \c Easing.OutBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing out: decelerating to zero velocity.
+ \o \inlineimage qeasingcurve-outback.png
+ \row
+ \o \c Easing.InOutBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutback.png
+ \row
+ \o \c Easing.OutInBack
+ \o Easing curve for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinback.png
+ \row
+ \o \c Easing.InBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inbounce.png
+ \row
+ \o \c Easing.OutBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outbounce.png
+ \row
+ \o \c Easing.InOutBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function easing in/out: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutbounce.png
+ \row
+ \o \c Easing.OutInBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function easing out/in: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinbounce.png
+ \endtable
+
+ \c easing.amplitude is only applicable for bounce and elastic curves (curves of type
+ \c Easing.InBounce, \c Easing.OutBounce, \c Easing.InOutBounce, \c Easing.OutInBounce, \c Easing.InElastic,
+ \c Easing.OutElastic, \c Easing.InOutElastic or \c Easing.OutInElastic).
+
+ \c easing.overshoot is only applicable if \c easing.type is: \c Easing.InBack, \c Easing.OutBack,
+ \c Easing.InOutBack or \c Easing.OutInBack.
+
+ \c easing.period is only applicable if easing.type is: \c Easing.InElastic, \c Easing.OutElastic,
+ \c Easing.InOutElastic or \c Easing.OutInElastic.
+
+ See the \l {declarative/animation/easing}{easing} example for a demonstration of
+ the different easing settings.
+*/
+QEasingCurve QDeclarativePropertyAnimation::easing() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->va->easingCurve();
+}
+
+void QDeclarativePropertyAnimation::setEasing(const QEasingCurve &e)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->va->easingCurve() == e)
+ return;
+
+ d->va->setEasingCurve(e);
+ emit easingChanged(e);
+}
+
+QObject *QDeclarativePropertyAnimation::target() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->target;
+}
+
+void QDeclarativePropertyAnimation::setTarget(QObject *o)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->target == o)
+ return;
+ d->target = o;
+ emit targetChanged();
+}
+
+QString QDeclarativePropertyAnimation::property() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->propertyName;
+}
+
+void QDeclarativePropertyAnimation::setProperty(const QString &n)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->propertyName == n)
+ return;
+ d->propertyName = n;
+ emit propertyChanged();
+}
+
+QString QDeclarativePropertyAnimation::properties() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->properties;
+}
+
+void QDeclarativePropertyAnimation::setProperties(const QString &prop)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->properties == prop)
+ return;
+
+ d->properties = prop;
+ emit propertiesChanged(prop);
+}
+
+/*!
+ \qmlproperty string PropertyAnimation::properties
+ \qmlproperty list<Object> PropertyAnimation::targets
+ \qmlproperty string PropertyAnimation::property
+ \qmlproperty Object PropertyAnimation::target
+
+ These properties are used as a set to determine which properties should be animated.
+ The singular and plural forms are functionally identical, e.g.
+ \qml
+ NumberAnimation { target: theItem; property: "x"; to: 500 }
+ \endqml
+ has the same meaning as
+ \qml
+ NumberAnimation { targets: theItem; properties: "x"; to: 500 }
+ \endqml
+ The singular forms are slightly optimized, so if you do have only a single target/property
+ to animate you should try to use them.
+
+ The \c targets property allows multiple targets to be set. For example, this animates the
+ \c x property of both \c itemA and \c itemB:
+
+ \qml
+ NumberAnimation { targets: [itemA, itemB]; properties: "x"; to: 500 }
+ \endqml
+
+ In many cases these properties do not need to be explicitly specified, as they can be
+ inferred from the animation framework:
+
+ \table 80%
+ \row
+ \o Value Source / Behavior
+ \o When an animation is used as a value source or in a Behavior, the default target and property
+ name to be animated can both be inferred.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ NumberAnimation on x { to: 500; loops: Animation.Infinite } //animate theRect's x property
+ Behavior on y { NumberAnimation {} } //animate theRect's y property
+ }
+ \endqml
+ \row
+ \o Transition
+ \o When used in a transition, a property animation is assumed to match \e all targets
+ but \e no properties. In practice, that means you need to specify at least the properties
+ in order for the animation to do anything.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ Item { id: uselessItem }
+ states: State {
+ name: "state1"
+ PropertyChanges { target: theRect; x: 200; y: 200; z: 4 }
+ PropertyChanges { target: uselessItem; x: 10; y: 10; z: 2 }
+ }
+ transitions: Transition {
+ //animate both theRect's and uselessItem's x and y to their final values
+ NumberAnimation { properties: "x,y" }
+
+ //animate theRect's z to its final value
+ NumberAnimation { target: theRect; property: "z" }
+ }
+ }
+ \endqml
+ \row
+ \o Standalone
+ \o When an animation is used standalone, both the target and property need to be
+ explicitly specified.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ //need to explicitly specify target and property
+ NumberAnimation { id: theAnim; target: theRect; property: "x"; to: 500 }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: theAnim.start()
+ }
+ }
+ \endqml
+ \endtable
+
+ As seen in the above example, properties is specified as a comma-separated string of property names to animate.
+
+ \sa exclude, {QML Animation and Transitions}
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAnimation::targets()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return QDeclarativeListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAnimation::exclude
+ This property holds the items not to be affected by this animation.
+ \sa PropertyAnimation::targets
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAnimation::exclude()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return QDeclarativeListProperty<QObject>(this, d->exclude);
+}
+
+QAbstractAnimation *QDeclarativePropertyAnimation::qtAnimation()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return d->va;
+}
+
+void QDeclarativeAnimationPropertyUpdater::setValue(qreal v)
+{
+ bool deleted = false;
+ wasDeleted = &deleted;
+ if (reverse) //QVariantAnimation sends us 1->0 when reversed, but we are expecting 0->1
+ v = 1 - v;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ if (v == 1.)
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ else {
+ if (!fromSourced && !fromDefined) {
+ action.fromValue = action.property.read();
+ if (interpolatorType)
+ QDeclarativePropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType);
+ }
+ if (!interpolatorType) {
+ int propType = action.property.propertyType();
+ if (!prevInterpolatorType || prevInterpolatorType != propType) {
+ prevInterpolatorType = propType;
+ interpolator = QVariantAnimationPrivate::getInterpolator(prevInterpolatorType);
+ }
+ }
+ if (interpolator)
+ QDeclarativePropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ if (deleted)
+ return;
+ }
+ wasDeleted = 0;
+ fromSourced = true;
+}
+
+void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativePropertyAnimation);
+
+ QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
+ for (int ii = 0; ii < props.count(); ++ii)
+ props[ii] = props.at(ii).trimmed();
+ if (!d->propertyName.isEmpty())
+ props << d->propertyName;
+
+ QList<QObject*> targets = d->targets;
+ if (d->target)
+ targets.append(d->target);
+
+ bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
+ bool useType = (props.isEmpty() && d->defaultToInterpolatorType) ? true : false;
+
+ if (d->defaultProperty.isValid() && !hasSelectors) {
+ props << d->defaultProperty.name();
+ targets << d->defaultProperty.object();
+ }
+
+ if (props.isEmpty() && !d->defaultProperties.isEmpty()) {
+ props << d->defaultProperties.split(QLatin1Char(','));
+ }
+
+ QDeclarativeAnimationPropertyUpdater *data = new QDeclarativeAnimationPropertyUpdater;
+ data->interpolatorType = d->interpolatorType;
+ data->interpolator = d->interpolator;
+ data->reverse = direction == Backward ? true : false;
+ data->fromSourced = false;
+ data->fromDefined = d->fromIsDefined;
+
+ bool hasExplicit = false;
+ //an explicit animation has been specified
+ if (d->toIsDefined) {
+ for (int i = 0; i < props.count(); ++i) {
+ for (int j = 0; j < targets.count(); ++j) {
+ QDeclarativeAction myAction;
+ myAction.property = d->createProperty(targets.at(j), props.at(i), this);
+ if (myAction.property.isValid()) {
+ if (d->fromIsDefined) {
+ myAction.fromValue = d->from;
+ d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ }
+ myAction.toValue = d->to;
+ d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+ if (action.property.object() == myAction.property.object() &&
+ myAction.property.name() == action.property.name()) {
+ modified << action.property;
+ break; //### any chance there could be multiples?
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!hasExplicit)
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ QObject *obj = action.property.object();
+ QString propertyName = action.property.name();
+ QObject *sObj = action.specifiedObject;
+ QString sPropertyName = action.specifiedProperty;
+ bool same = (obj == sObj);
+
+ if ((targets.isEmpty() || targets.contains(obj) || (!same && targets.contains(sObj))) &&
+ (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) &&
+ (props.contains(propertyName) || (!same && props.contains(sPropertyName))
+ || (useType && action.property.propertyType() == d->interpolatorType))) {
+ QDeclarativeAction myAction = action;
+
+ if (d->fromIsDefined)
+ myAction.fromValue = d->from;
+ else
+ myAction.fromValue = QVariant();
+ if (d->toIsDefined)
+ myAction.toValue = d->to;
+
+ d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+
+ modified << action.property;
+
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ }
+ }
+
+ 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);
+ d->actions = &data->actions;
+ } else {
+ delete data;
+ d->va->setFromSourcedValue(0); //clear previous data
+ d->va->setAnimValue(0, QAbstractAnimation::DeleteWhenStopped); //clear previous data
+ d->actions = 0;
+ }
+}
+
+/*!
+ \qmlclass ParentAnimation QDeclarativeParentAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The ParentAnimation element animates changes in parent values.
+
+ ParentAnimation is used to animate a parent change for an \l Item.
+
+ For example, the following ParentChange changes \c blueRect to become
+ a child of \c redRect when it is clicked. The inclusion of the
+ ParentAnimation, which defines a NumberAnimation to be applied during
+ the transition, ensures the item animates smoothly as it moves to
+ its new parent:
+
+ \snippet doc/src/snippets/declarative/parentanimation.qml 0
+
+ A ParentAnimation can contain any number of animations. These animations will
+ be run in parallel; to run them sequentially, define them within a
+ SequentialAnimation.
+
+ In some cases, such as when reparenting between items with clipping enabled, it is useful
+ to animate the parent change via another item that does not have clipping
+ enabled. Such an item can be set using the \l via property.
+
+ For convenience, when a ParentAnimation is used in a \l Transition, it will
+ animate any ParentChange that has occurred during the state change.
+ This can be overridden by setting a specific target item using the
+ \l target property.
+
+ Like any other animation element, a ParentAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeParentAnimation::QDeclarativeParentAnimation(QObject *parent)
+ : QDeclarativeAnimationGroup(*(new QDeclarativeParentAnimationPrivate), parent)
+{
+ Q_D(QDeclarativeParentAnimation);
+ 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);
+}
+
+QDeclarativeParentAnimation::~QDeclarativeParentAnimation()
+{
+}
+
+/*!
+ \qmlproperty Item ParentAnimation::target
+ The item to reparent.
+
+ When used in a transition, if no target is specified, all
+ ParentChange occurrences are animated by the ParentAnimation.
+*/
+QDeclarativeItem *QDeclarativeParentAnimation::target() const
+{
+ Q_D(const QDeclarativeParentAnimation);
+ return d->target;
+}
+
+void QDeclarativeParentAnimation::setTarget(QDeclarativeItem *target)
+{
+ Q_D(QDeclarativeParentAnimation);
+ if (target == d->target)
+ return;
+
+ d->target = target;
+ emit targetChanged();
+}
+
+/*!
+ \qmlproperty Item ParentAnimation::newParent
+ The new parent to animate to.
+
+ If the ParentAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+*/
+QDeclarativeItem *QDeclarativeParentAnimation::newParent() const
+{
+ Q_D(const QDeclarativeParentAnimation);
+ return d->newParent;
+}
+
+void QDeclarativeParentAnimation::setNewParent(QDeclarativeItem *newParent)
+{
+ Q_D(QDeclarativeParentAnimation);
+ if (newParent == d->newParent)
+ return;
+
+ d->newParent = newParent;
+ emit newParentChanged();
+}
+
+/*!
+ \qmlproperty Item ParentAnimation::via
+ The item to reparent via. This provides a way to do an unclipped animation
+ when both the old parent and new parent are clipped.
+
+ \qml
+ ParentAnimation {
+ target: myItem
+ via: topLevelItem
+ // ...
+ }
+ \endqml
+*/
+QDeclarativeItem *QDeclarativeParentAnimation::via() const
+{
+ Q_D(const QDeclarativeParentAnimation);
+ return d->via;
+}
+
+void QDeclarativeParentAnimation::setVia(QDeclarativeItem *via)
+{
+ Q_D(QDeclarativeParentAnimation);
+ if (via == d->via)
+ return;
+
+ d->via = via;
+ emit viaChanged();
+}
+
+//### mirrors same-named function in QDeclarativeItem
+QPointF QDeclarativeParentAnimationPrivate::computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const
+{
+ switch(origin) {
+ default:
+ case QDeclarativeItem::TopLeft:
+ return QPointF(0, 0);
+ case QDeclarativeItem::Top:
+ return QPointF(width / 2., 0);
+ case QDeclarativeItem::TopRight:
+ return QPointF(width, 0);
+ case QDeclarativeItem::Left:
+ return QPointF(0, height / 2.);
+ case QDeclarativeItem::Center:
+ return QPointF(width / 2., height / 2.);
+ case QDeclarativeItem::Right:
+ return QPointF(width, height / 2.);
+ case QDeclarativeItem::BottomLeft:
+ return QPointF(0, height);
+ case QDeclarativeItem::Bottom:
+ return QPointF(width / 2., height);
+ case QDeclarativeItem::BottomRight:
+ return QPointF(width, height);
+ }
+}
+
+void QDeclarativeParentAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeParentAnimation);
+
+ struct QDeclarativeParentAnimationData : public QAbstractAnimationAction
+ {
+ QDeclarativeParentAnimationData() {}
+ ~QDeclarativeParentAnimationData() { qDeleteAll(pc); }
+
+ QDeclarativeStateActions actions;
+ //### reverse should probably apply on a per-action basis
+ bool reverse;
+ QList<QDeclarativeParentChange *> 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();
+ }
+ }
+ };
+
+ QDeclarativeParentAnimationData *data = new QDeclarativeParentAnimationData;
+ QDeclarativeParentAnimationData *viaData = new QDeclarativeParentAnimationData;
+
+ bool hasExplicit = false;
+ if (d->target && d->newParent) {
+ data->reverse = false;
+ QDeclarativeAction myAction;
+ QDeclarativeParentChange *pc = new QDeclarativeParentChange;
+ 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;
+ QDeclarativeParentChange *vpc = new QDeclarativeParentChange;
+ 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<QDeclarativeParentChange*>(action.event)->object() == d->target)) {
+
+ QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(action.event);
+ QDeclarativeAction myAction = action;
+ data->reverse = action.reverseEvent;
+
+ //### this logic differs from PropertyAnimation
+ // (probably a result of modified vs. done)
+ if (d->newParent) {
+ QDeclarativeParentChange *epc = new QDeclarativeParentChange;
+ epc->setObject(static_cast<QDeclarativeParentChange*>(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;
+ QDeclarativeParentChange *vpc = new QDeclarativeParentChange;
+ 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;
+ QDeclarativeItem *target = pc->object();
+ QDeclarativeItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent();
+
+ //### this mirrors the logic in QDeclarativeParentChange.
+ bool ok;
+ const QTransform &transform = targetParent->itemTransform(d->via, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(this) << QDeclarativeParentAnimation::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) << QDeclarativeParentAnimation::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) << QDeclarativeParentAnimation::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) << QDeclarativeParentAnimation::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() != QDeclarativeItem::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);
+ }
+ if (!d->via)
+ delete viaData;
+ } 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 *QDeclarativeParentAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeParentAnimation);
+ return d->topLevelGroup;
+}
+
+/*!
+ \qmlclass AnchorAnimation QDeclarativeAnchorAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The AnchorAnimation element animates changes in anchor values.
+
+ AnchorAnimation is used to animate an anchor change.
+
+ In the following snippet we animate the addition of a right anchor to a \l Rectangle:
+
+ \snippet doc/src/snippets/declarative/anchoranimation.qml 0
+
+ For convenience, when an AnchorAnimation is used in a \l Transition, it will
+ animate any AnchorChanges that have occurred during the state change.
+ This can be overridden by setting a specific target item using the
+ \l target property.
+
+ Like any other animation element, an AnchorAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, AnchorChanges
+*/
+
+QDeclarativeAnchorAnimation::QDeclarativeAnchorAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativeAnchorAnimationPrivate), parent)
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ d->va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(d->va, this);
+}
+
+QDeclarativeAnchorAnimation::~QDeclarativeAnchorAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeAnchorAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ return d->va;
+}
+
+/*!
+ \qmlproperty list<Item> AnchorAnimation::targets
+ The items to reanchor.
+
+ If no targets are specified all AnchorChanges will be
+ animated by the AnchorAnimation.
+*/
+QDeclarativeListProperty<QDeclarativeItem> QDeclarativeAnchorAnimation::targets()
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ return QDeclarativeListProperty<QDeclarativeItem>(this, d->targets);
+}
+
+/*!
+ \qmlproperty int AnchorAnimation::duration
+ This property holds the duration of the animation, in milliseconds.
+
+ The default value is 250.
+*/
+int QDeclarativeAnchorAnimation::duration() const
+{
+ Q_D(const QDeclarativeAnchorAnimation);
+ return d->va->duration();
+}
+
+void QDeclarativeAnchorAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QDeclarativeAnchorAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+/*!
+ \qmlproperty enumeration AnchorAnimation::easing.type
+ \qmlproperty real AnchorAnimation::easing.amplitude
+ \qmlproperty real AnchorAnimation::easing.overshoot
+ \qmlproperty real AnchorAnimation::easing.period
+ \brief the easing curve used for the animation.
+
+ To specify an easing curve you need to specify at least the type. For some curves you can also specify
+ amplitude, period and/or overshoot. The default easing curve is
+ Linear.
+
+ \qml
+ AnchorAnimation { easing.type: Easing.InOutQuad }
+ \endqml
+
+ See the \l{PropertyAnimation::easing.type} documentation for information
+ about the different types of easing curves.
+*/
+
+QEasingCurve QDeclarativeAnchorAnimation::easing() const
+{
+ Q_D(const QDeclarativeAnchorAnimation);
+ return d->va->easingCurve();
+}
+
+void QDeclarativeAnchorAnimation::setEasing(const QEasingCurve &e)
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ if (d->va->easingCurve() == e)
+ return;
+
+ d->va->setEasingCurve(e);
+ emit easingChanged(e);
+}
+
+void QDeclarativeAnchorAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(modified);
+ Q_D(QDeclarativeAnchorAnimation);
+ 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<QDeclarativeAnchorChanges*>(action.event)->object()))) {
+ data->actions << static_cast<QDeclarativeAnchorChanges*>(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;
+ }
+}
+
+QDeclarativeScriptActionPrivate::QDeclarativeScriptActionPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), hasRunScriptScript(false), reversing(false), proxy(this), rsa(0) {}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h
new file mode 100644
index 0000000000..34c376c335
--- /dev/null
+++ b/src/declarative/util/qdeclarativeanimation_p.h
@@ -0,0 +1,528 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEANIMATION_H
+#define QDECLARATIVEANIMATION_H
+
+#include "private/qdeclarativetransition_p.h"
+#include "private/qdeclarativestate_p.h"
+#include <QtGui/qvector3d.h>
+
+#include <qdeclarativepropertyvaluesource.h>
+#include <qdeclarative.h>
+#include <qdeclarativescriptstring.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/QAbstractAnimation>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeAbstractAnimationPrivate;
+class QDeclarativeAnimationGroup;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAbstractAnimation : public QObject, public QDeclarativePropertyValueSource, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAbstractAnimation)
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_INTERFACES(QDeclarativePropertyValueSource)
+ Q_ENUMS(Loops)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(bool alwaysRunToEnd READ alwaysRunToEnd WRITE setAlwaysRunToEnd NOTIFY alwaysRunToEndChanged)
+ Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopCountChanged)
+ Q_CLASSINFO("DefaultMethod", "start()")
+
+public:
+ QDeclarativeAbstractAnimation(QObject *parent=0);
+ virtual ~QDeclarativeAbstractAnimation();
+
+ enum Loops { Infinite = -2 };
+
+ bool isRunning() const;
+ void setRunning(bool);
+ bool isPaused() const;
+ void setPaused(bool);
+ bool alwaysRunToEnd() const;
+ void setAlwaysRunToEnd(bool);
+
+ int loops() const;
+ void setLoops(int);
+
+ int currentTime();
+ void setCurrentTime(int);
+
+ QDeclarativeAnimationGroup *group() const;
+ void setGroup(QDeclarativeAnimationGroup *);
+
+ void setDefaultTarget(const QDeclarativeProperty &);
+ void setDisableUserControl();
+
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void started();
+ void completed();
+ void runningChanged(bool);
+ void pausedChanged(bool);
+ void alwaysRunToEndChanged(bool);
+ void loopCountChanged(int);
+
+public Q_SLOTS:
+ void restart();
+ void start();
+ void pause();
+ void resume();
+ void stop();
+ void complete();
+
+protected:
+ QDeclarativeAbstractAnimation(QDeclarativeAbstractAnimationPrivate &dd, QObject *parent);
+
+public:
+ enum TransitionDirection { Forward, Backward };
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation() = 0;
+
+private Q_SLOTS:
+ void timelineComplete();
+ void componentFinalized();
+private:
+ virtual void setTarget(const QDeclarativeProperty &);
+ void notifyRunningChanged(bool running);
+ friend class QDeclarativeBehavior;
+
+
+};
+
+class QDeclarativePauseAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePauseAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePauseAnimation)
+
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+
+public:
+ QDeclarativePauseAnimation(QObject *parent=0);
+ virtual ~QDeclarativePauseAnimation();
+
+ int duration() const;
+ void setDuration(int);
+
+Q_SIGNALS:
+ void durationChanged(int);
+
+protected:
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeScriptActionPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeScriptAction : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeScriptAction)
+
+ Q_PROPERTY(QDeclarativeScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString scriptName READ stateChangeScriptName WRITE setStateChangeScriptName)
+
+public:
+ QDeclarativeScriptAction(QObject *parent=0);
+ virtual ~QDeclarativeScriptAction();
+
+ QDeclarativeScriptString script() const;
+ void setScript(const QDeclarativeScriptString &);
+
+ QString stateChangeScriptName() const;
+ void setStateChangeScriptName(const QString &);
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativePropertyActionPrivate;
+class QDeclarativePropertyAction : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAction)
+
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(QString properties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> targets READ targets)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> exclude READ exclude)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ QDeclarativePropertyAction(QObject *parent=0);
+ virtual ~QDeclarativePropertyAction();
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QDeclarativeListProperty<QObject> targets();
+ QDeclarativeListProperty<QObject> exclude();
+
+ QVariant value() const;
+ void setValue(const QVariant &);
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &);
+ void propertiesChanged(const QString &);
+ void targetChanged();
+ void propertyChanged();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeItem;
+class QDeclarativePropertyAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePropertyAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(QVariant from READ from WRITE setFrom NOTIFY fromChanged)
+ Q_PROPERTY(QVariant to READ to WRITE setTo NOTIFY toChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(QString properties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> targets READ targets)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> exclude READ exclude)
+
+public:
+ QDeclarativePropertyAnimation(QObject *parent=0);
+ virtual ~QDeclarativePropertyAnimation();
+
+ virtual int duration() const;
+ virtual void setDuration(int);
+
+ QVariant from() const;
+ void setFrom(const QVariant &);
+
+ QVariant to() const;
+ void setTo(const QVariant &);
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &);
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QDeclarativeListProperty<QObject> targets();
+ QDeclarativeListProperty<QObject> exclude();
+
+protected:
+ QDeclarativePropertyAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent);
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+
+Q_SIGNALS:
+ void durationChanged(int);
+ void fromChanged(QVariant);
+ void toChanged(QVariant);
+ void easingChanged(const QEasingCurve &);
+ void propertiesChanged(const QString &);
+ void targetChanged();
+ void propertyChanged();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeColorAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+ Q_PROPERTY(QColor from READ from WRITE setFrom)
+ Q_PROPERTY(QColor to READ to WRITE setTo)
+
+public:
+ QDeclarativeColorAnimation(QObject *parent=0);
+ virtual ~QDeclarativeColorAnimation();
+
+ QColor from() const;
+ void setFrom(const QColor &);
+
+ QColor to() const;
+ void setTo(const QColor &);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeNumberAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ Q_PROPERTY(qreal from READ from WRITE setFrom)
+ Q_PROPERTY(qreal to READ to WRITE setTo)
+
+public:
+ QDeclarativeNumberAnimation(QObject *parent=0);
+ virtual ~QDeclarativeNumberAnimation();
+
+ qreal from() const;
+ void setFrom(qreal);
+
+ qreal to() const;
+ void setTo(qreal);
+
+protected:
+ QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent);
+
+private:
+ void init();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeVector3dAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ Q_PROPERTY(QVector3D from READ from WRITE setFrom)
+ Q_PROPERTY(QVector3D to READ to WRITE setTo)
+
+public:
+ QDeclarativeVector3dAnimation(QObject *parent=0);
+ virtual ~QDeclarativeVector3dAnimation();
+
+ QVector3D from() const;
+ void setFrom(QVector3D);
+
+ QVector3D to() const;
+ void setTo(QVector3D);
+};
+
+class QDeclarativeRotationAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeRotationAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeRotationAnimation)
+ Q_ENUMS(RotationDirection)
+
+ Q_PROPERTY(qreal from READ from WRITE setFrom)
+ Q_PROPERTY(qreal to READ to WRITE setTo)
+ Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+
+public:
+ QDeclarativeRotationAnimation(QObject *parent=0);
+ virtual ~QDeclarativeRotationAnimation();
+
+ qreal from() const;
+ void setFrom(qreal);
+
+ qreal to() const;
+ void setTo(qreal);
+
+ enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise };
+ RotationDirection direction() const;
+ void setDirection(RotationDirection direction);
+
+Q_SIGNALS:
+ void directionChanged();
+};
+
+class QDeclarativeAnimationGroupPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeAnimationGroup : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations READ animations)
+
+public:
+ QDeclarativeAnimationGroup(QObject *parent);
+ virtual ~QDeclarativeAnimationGroup();
+
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations();
+ friend class QDeclarativeAbstractAnimation;
+
+protected:
+ QDeclarativeAnimationGroup(QDeclarativeAnimationGroupPrivate &dd, QObject *parent);
+};
+
+class QDeclarativeSequentialAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+public:
+ QDeclarativeSequentialAnimation(QObject *parent=0);
+ virtual ~QDeclarativeSequentialAnimation();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeParallelAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+public:
+ QDeclarativeParallelAnimation(QObject *parent=0);
+ virtual ~QDeclarativeParallelAnimation();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeParentAnimationPrivate;
+class QDeclarativeParentAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeParentAnimation)
+
+ Q_PROPERTY(QDeclarativeItem *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QDeclarativeItem *newParent READ newParent WRITE setNewParent NOTIFY newParentChanged)
+ Q_PROPERTY(QDeclarativeItem *via READ via WRITE setVia NOTIFY viaChanged)
+
+public:
+ QDeclarativeParentAnimation(QObject *parent=0);
+ virtual ~QDeclarativeParentAnimation();
+
+ QDeclarativeItem *target() const;
+ void setTarget(QDeclarativeItem *);
+
+ QDeclarativeItem *newParent() const;
+ void setNewParent(QDeclarativeItem *);
+
+ QDeclarativeItem *via() const;
+ void setVia(QDeclarativeItem *);
+
+Q_SIGNALS:
+ void targetChanged();
+ void newParentChanged();
+ void viaChanged();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeAnchorAnimationPrivate;
+class QDeclarativeAnchorAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnchorAnimation)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeItem> targets READ targets)
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+
+public:
+ QDeclarativeAnchorAnimation(QObject *parent=0);
+ virtual ~QDeclarativeAnchorAnimation();
+
+ QDeclarativeListProperty<QDeclarativeItem> 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(QDeclarativeAbstractAnimation)
+QML_DECLARE_TYPE(QDeclarativePauseAnimation)
+QML_DECLARE_TYPE(QDeclarativeScriptAction)
+QML_DECLARE_TYPE(QDeclarativePropertyAction)
+QML_DECLARE_TYPE(QDeclarativePropertyAnimation)
+QML_DECLARE_TYPE(QDeclarativeColorAnimation)
+QML_DECLARE_TYPE(QDeclarativeNumberAnimation)
+QML_DECLARE_TYPE(QDeclarativeSequentialAnimation)
+QML_DECLARE_TYPE(QDeclarativeParallelAnimation)
+QML_DECLARE_TYPE(QDeclarativeVector3dAnimation)
+QML_DECLARE_TYPE(QDeclarativeRotationAnimation)
+QML_DECLARE_TYPE(QDeclarativeParentAnimation)
+QML_DECLARE_TYPE(QDeclarativeAnchorAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEANIMATION_H
diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h
new file mode 100644
index 0000000000..048ecb1a30
--- /dev/null
+++ b/src/declarative/util/qdeclarativeanimation_p_p.h
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEANIMATION_P_H
+#define QDECLARATIVEANIMATION_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/qdeclarativeanimation_p.h"
+
+#include "private/qdeclarativenullablevalue_p_p.h"
+#include "private/qdeclarativetimeline_p_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativeitem.h>
+#include <qdeclarativecontext.h>
+
+#include <QtCore/QPauseAnimation>
+#include <QtCore/QVariantAnimation>
+#include <QtCore/QAnimationGroup>
+#include <QtGui/QColor>
+#include <QDebug>
+
+#include <private/qobject_p.h>
+#include <private/qvariantanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//interface for classes that provide animation actions for QActionAnimation
+class QAbstractAnimationAction
+{
+public:
+ virtual ~QAbstractAnimationAction() {}
+ virtual void doAction() = 0;
+};
+
+//templated animation action
+//allows us to specify an action that calls a function of a class.
+//(so that class doesn't have to inherit QDeclarativeAbstractAnimationAction)
+template<class T, void (T::*method)()>
+class QAnimationActionProxy : public QAbstractAnimationAction
+{
+public:
+ QAnimationActionProxy(T *p) : m_p(p) {}
+ virtual void doAction() { (m_p->*method)(); }
+
+private:
+ T *m_p;
+};
+
+//performs an action of type QAbstractAnimationAction
+class Q_AUTOTEST_EXPORT QActionAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+public:
+ QActionAnimation(QObject *parent = 0) : QAbstractAnimation(parent), animAction(0), policy(KeepWhenStopped) {}
+ QActionAnimation(QAbstractAnimationAction *action, QObject *parent = 0)
+ : QAbstractAnimation(parent), animAction(action), policy(KeepWhenStopped) {}
+ ~QActionAnimation() { if (policy == DeleteWhenStopped) { delete animAction; animAction = 0; } }
+ virtual int duration() const { return 0; }
+ void setAnimAction(QAbstractAnimationAction *action, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ if (policy == DeleteWhenStopped)
+ delete animAction;
+ animAction = action;
+ policy = p;
+ }
+protected:
+ virtual void updateCurrentTime(int) {}
+
+ virtual void updateState(State newState, State /*oldState*/)
+ {
+ if (newState == Running) {
+ if (animAction) {
+ animAction->doAction();
+ if (state() == Stopped && policy == DeleteWhenStopped) {
+ delete animAction;
+ animAction = 0;
+ }
+ }
+ }
+ }
+
+private:
+ QAbstractAnimationAction *animAction;
+ DeletionPolicy policy;
+};
+
+class QDeclarativeBulkValueUpdater
+{
+public:
+ virtual ~QDeclarativeBulkValueUpdater() {}
+ virtual void setValue(qreal value) = 0;
+};
+
+//animates QDeclarativeBulkValueUpdater (assumes start and end values will be reals or compatible)
+class Q_AUTOTEST_EXPORT QDeclarativeBulkValueAnimator : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ QDeclarativeBulkValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {}
+ ~QDeclarativeBulkValueAnimator() { if (policy == DeleteWhenStopped) { delete animValue; animValue = 0; } }
+ void setAnimValue(QDeclarativeBulkValueUpdater *value, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ if (policy == DeleteWhenStopped)
+ delete animValue;
+ animValue = value;
+ policy = p;
+ }
+ void setFromSourcedValue(bool *value)
+ {
+ fromSourced = value;
+ }
+protected:
+ virtual void updateCurrentValue(const QVariant &value)
+ {
+ if (state() == QAbstractAnimation::Stopped)
+ return;
+
+ if (animValue)
+ animValue->setValue(value.toReal());
+ }
+ virtual void updateState(State newState, State oldState)
+ {
+ QVariantAnimation::updateState(newState, oldState);
+ if (newState == Running) {
+ //check for new from every loop
+ if (fromSourced)
+ *fromSourced = false;
+ }
+ }
+
+private:
+ QDeclarativeBulkValueUpdater *animValue;
+ bool *fromSourced;
+ DeletionPolicy policy;
+};
+
+//an animation that just gives a tick
+template<class T, void (T::*method)(int)>
+class QTickAnimationProxy : public QAbstractAnimation
+{
+ //Q_OBJECT //doesn't work with templating
+public:
+ QTickAnimationProxy(T *p, QObject *parent = 0) : QAbstractAnimation(parent), m_p(p) {}
+ virtual int duration() const { return -1; }
+protected:
+ virtual void updateCurrentTime(int msec) { (m_p->*method)(msec); }
+
+private:
+ T *m_p;
+};
+
+class QDeclarativeAbstractAnimationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAbstractAnimation)
+public:
+ QDeclarativeAbstractAnimationPrivate()
+ : running(false), paused(false), alwaysRunToEnd(false),
+ connectedTimeLine(false), componentComplete(true),
+ avoidPropertyValueSourceStart(false), disableUserControl(false),
+ registered(false), loopCount(1), group(0) {}
+
+ bool running:1;
+ bool paused:1;
+ bool alwaysRunToEnd:1;
+ bool connectedTimeLine:1;
+ bool componentComplete:1;
+ bool avoidPropertyValueSourceStart:1;
+ bool disableUserControl:1;
+ bool registered:1;
+
+ int loopCount;
+
+ void commence();
+
+ QDeclarativeProperty defaultProperty;
+
+ QDeclarativeAnimationGroup *group;
+
+ static QDeclarativeProperty createProperty(QObject *obj, const QString &str, QObject *infoObj);
+};
+
+class QDeclarativePauseAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePauseAnimation)
+public:
+ QDeclarativePauseAnimationPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), pa(0) {}
+
+ void init();
+
+ QPauseAnimation *pa;
+};
+
+class QDeclarativeScriptActionPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeScriptAction)
+public:
+ QDeclarativeScriptActionPrivate();
+
+ void init();
+
+ QDeclarativeScriptString script;
+ QString name;
+ QDeclarativeScriptString runScriptScript;
+ bool hasRunScriptScript;
+ bool reversing;
+
+ void execute();
+
+ QAnimationActionProxy<QDeclarativeScriptActionPrivate,
+ &QDeclarativeScriptActionPrivate::execute> proxy;
+ QActionAnimation *rsa;
+};
+
+class QDeclarativePropertyActionPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyAction)
+public:
+ QDeclarativePropertyActionPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), target(0), spa(0) {}
+
+ void init();
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+
+ QDeclarativeNullableValue<QVariant> value;
+
+ QActionAnimation *spa;
+};
+
+class QDeclarativeAnimationGroupPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnimationGroup)
+public:
+ QDeclarativeAnimationGroupPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), ag(0) {}
+
+ static void append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *role);
+ static void clear_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list);
+ QList<QDeclarativeAbstractAnimation *> animations;
+ QAnimationGroup *ag;
+};
+
+class QDeclarativePropertyAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyAnimation)
+public:
+ QDeclarativePropertyAnimationPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), target(0), fromSourced(false), fromIsDefined(false), toIsDefined(false),
+ rangeIsSet(false), defaultToInterpolatorType(0), interpolatorType(0), interpolator(0), va(0), actions(0) {}
+
+ void init();
+
+ QVariant from;
+ QVariant to;
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+ QString defaultProperties;
+
+ bool fromSourced;
+ bool fromIsDefined:1;
+ bool toIsDefined:1;
+ bool rangeIsSet:1;
+ bool defaultToInterpolatorType:1;
+ int interpolatorType;
+ QVariantAnimation::Interpolator interpolator;
+
+ QDeclarativeBulkValueAnimator *va;
+
+ // for animations that don't use the QDeclarativeBulkValueAnimator
+ QDeclarativeStateActions *actions;
+
+ static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress);
+ static void convertVariant(QVariant &variant, int type);
+};
+
+class QDeclarativeRotationAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeRotationAnimation)
+public:
+ QDeclarativeRotationAnimationPrivate() : direction(QDeclarativeRotationAnimation::Numerical) {}
+
+ QDeclarativeRotationAnimation::RotationDirection direction;
+};
+
+class QDeclarativeParentAnimationPrivate : public QDeclarativeAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeParentAnimation)
+public:
+ QDeclarativeParentAnimationPrivate()
+ : QDeclarativeAnimationGroupPrivate(), target(0), newParent(0),
+ via(0), topLevelGroup(0), startAction(0), endAction(0) {}
+
+ QDeclarativeItem *target;
+ QDeclarativeItem *newParent;
+ QDeclarativeItem *via;
+
+ QSequentialAnimationGroup *topLevelGroup;
+ QActionAnimation *startAction;
+ QActionAnimation *endAction;
+
+ QPointF computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const;
+};
+
+class QDeclarativeAnchorAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnchorAnimation)
+public:
+ QDeclarativeAnchorAnimationPrivate() : rangeIsSet(false), va(0),
+ interpolator(QVariantAnimationPrivate::getInterpolator(QMetaType::QReal)) {}
+
+ bool rangeIsSet;
+ QDeclarativeBulkValueAnimator *va;
+ QVariantAnimation::Interpolator interpolator;
+ QList<QDeclarativeItem*> targets;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeAnimationPropertyUpdater : public QDeclarativeBulkValueUpdater
+{
+public:
+ QDeclarativeStateActions actions;
+ int interpolatorType; //for Number/ColorAnimation
+ int prevInterpolatorType; //for generic
+ QVariantAnimation::Interpolator interpolator;
+ bool reverse;
+ bool fromSourced;
+ bool fromDefined;
+ bool *wasDeleted;
+ QDeclarativeAnimationPropertyUpdater() : prevInterpolatorType(0), wasDeleted(0) {}
+ ~QDeclarativeAnimationPropertyUpdater() { if (wasDeleted) *wasDeleted = true; }
+ void setValue(qreal v);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEANIMATION_P_H
diff --git a/src/declarative/util/qdeclarativeapplication.cpp b/src/declarative/util/qdeclarativeapplication.cpp
new file mode 100644
index 0000000000..3e66e14c67
--- /dev/null
+++ b/src/declarative/util/qdeclarativeapplication.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qdeclarativeapplication_p.h"
+#include <private/qobject_p.h>
+#include <QtGui/QApplication>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeApplicationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeApplication)
+public:
+ QDeclarativeApplicationPrivate() : active(QApplication::activeWindow() != 0),
+ layoutDirection(QApplication::layoutDirection()) {}
+ bool active;
+ Qt::LayoutDirection layoutDirection;
+};
+
+/*
+ This object and its properties are documented as part of the Qt object,
+ in qdeclarativengine.cpp
+*/
+
+QDeclarativeApplication::QDeclarativeApplication(QObject *parent) : QObject(*new QDeclarativeApplicationPrivate(), parent)
+{
+ if (qApp)
+ qApp->installEventFilter(this);
+}
+
+QDeclarativeApplication::~QDeclarativeApplication()
+{
+}
+
+bool QDeclarativeApplication::active() const
+{
+ Q_D(const QDeclarativeApplication);
+ return d->active;
+}
+
+Qt::LayoutDirection QDeclarativeApplication::layoutDirection() const
+{
+ Q_D(const QDeclarativeApplication);
+ return d->layoutDirection;
+}
+
+bool QDeclarativeApplication::eventFilter(QObject *obj, QEvent *event)
+{
+ Q_UNUSED(obj)
+ Q_D(QDeclarativeApplication);
+ if (event->type() == QEvent::ApplicationActivate
+ || event->type() == QEvent::ApplicationDeactivate) {
+ bool active = d->active;
+ if (event->type() == QEvent::ApplicationActivate)
+ active = true;
+ else if (event->type() == QEvent::ApplicationDeactivate)
+ active = false;
+
+ if (d->active != active) {
+ d->active = active;
+ emit activeChanged();
+ }
+ }
+ if (event->type() == QEvent::LayoutDirectionChange) {
+ Qt::LayoutDirection direction = QApplication::layoutDirection();
+ if (d->layoutDirection != direction) {
+ d->layoutDirection = direction;
+ emit layoutDirectionChanged();
+ }
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeapplication_p.h b/src/declarative/util/qdeclarativeapplication_p.h
new file mode 100644
index 0000000000..f59a5fbd70
--- /dev/null
+++ b/src/declarative/util/qdeclarativeapplication_p.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 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 QDECLARATIVEAPPLICATION_P_H
+#define QDECLARATIVEAPPLICATION_P_H
+
+#include <QtCore/QObject>
+#include <qdeclarative.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeApplicationPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeApplication : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection NOTIFY layoutDirectionChanged)
+
+public:
+ explicit QDeclarativeApplication(QObject *parent = 0);
+ virtual ~QDeclarativeApplication();
+ bool active() const;
+ Qt::LayoutDirection layoutDirection() const;
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+Q_SIGNALS:
+ void activeChanged();
+ void layoutDirectionChanged();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeApplication)
+ Q_DECLARE_PRIVATE(QDeclarativeApplication)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeApplication)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEAPPLICATION_P_H
diff --git a/src/declarative/util/qdeclarativebehavior.cpp b/src/declarative/util/qdeclarativebehavior.cpp
new file mode 100644
index 0000000000..a1321e21cf
--- /dev/null
+++ b/src/declarative/util/qdeclarativebehavior.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativebehavior_p.h"
+
+#include "private/qdeclarativeanimation_p.h"
+#include "private/qdeclarativetransition_p.h"
+
+#include <qdeclarativecontext.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativeproperty_p.h>
+#include <qdeclarativeguard_p.h>
+#include <qdeclarativeengine_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBehaviorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeBehavior)
+public:
+ QDeclarativeBehaviorPrivate() : animation(0), enabled(true), finalized(false)
+ , blockRunningChanged(false) {}
+
+ QDeclarativeProperty property;
+ QVariant currentValue;
+ QVariant targetValue;
+ QDeclarativeGuard<QDeclarativeAbstractAnimation> animation;
+ bool enabled;
+ bool finalized;
+ bool blockRunningChanged;
+};
+
+/*!
+ \qmlclass Behavior QDeclarativeBehavior
+ \ingroup qml-animation-transition
+ \since 4.7
+ \brief The Behavior element allows you to specify a default animation for a property change.
+
+ A Behavior defines the default animation to be applied whenever a
+ particular property value changes.
+
+ For example, the following Behavior defines a NumberAnimation to be run
+ whenever the \l Rectangle's \c width value changes. When the MouseArea
+ is clicked, the \c width is changed, triggering the behavior's animation:
+
+ \snippet doc/src/snippets/declarative/behavior.qml 0
+
+ Note that a property cannot have more than one assigned Behavior. To provide
+ multiple animations within a Behavior, use ParallelAnimation or
+ SequentialAnimation.
+
+ If a \l{QML States}{state change} has a \l Transition that matches the same property as a
+ Behavior, the \l Transition animation overrides the Behavior for that
+ state change. For general advice on using Behaviors to animate state changes, see
+ \l{Using QML Behaviors with States}.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/behaviors}{Behavior example}, QtDeclarative
+*/
+
+
+QDeclarativeBehavior::QDeclarativeBehavior(QObject *parent)
+ : QObject(*(new QDeclarativeBehaviorPrivate), parent)
+{
+}
+
+QDeclarativeBehavior::~QDeclarativeBehavior()
+{
+}
+
+/*!
+ \qmlproperty Animation Behavior::animation
+ \default
+
+ This property holds the animation to run when the behavior is triggered.
+*/
+
+QDeclarativeAbstractAnimation *QDeclarativeBehavior::animation()
+{
+ Q_D(QDeclarativeBehavior);
+ return d->animation;
+}
+
+void QDeclarativeBehavior::setAnimation(QDeclarativeAbstractAnimation *animation)
+{
+ Q_D(QDeclarativeBehavior);
+ if (d->animation) {
+ qmlInfo(this) << tr("Cannot change the animation assigned to a Behavior.");
+ return;
+ }
+
+ d->animation = animation;
+ if (d->animation) {
+ d->animation->setDefaultTarget(d->property);
+ d->animation->setDisableUserControl();
+ connect(d->animation->qtAnimation(),
+ SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)),
+ this,
+ SLOT(qtAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State)));
+ }
+}
+
+
+void QDeclarativeBehavior::qtAnimationStateChanged(QAbstractAnimation::State newState,QAbstractAnimation::State)
+{
+ Q_D(QDeclarativeBehavior);
+ if (!d->blockRunningChanged)
+ d->animation->notifyRunningChanged(newState == QAbstractAnimation::Running);
+}
+
+
+/*!
+ \qmlproperty bool Behavior::enabled
+
+ This property holds whether the behavior will be triggered when the tracked
+ property changes value.
+
+ By default a Behavior is enabled.
+*/
+
+bool QDeclarativeBehavior::enabled() const
+{
+ Q_D(const QDeclarativeBehavior);
+ return d->enabled;
+}
+
+void QDeclarativeBehavior::setEnabled(bool enabled)
+{
+ Q_D(QDeclarativeBehavior);
+ if (d->enabled == enabled)
+ return;
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+void QDeclarativeBehavior::write(const QVariant &value)
+{
+ Q_D(QDeclarativeBehavior);
+ qmlExecuteDeferred(this);
+ if (!d->animation || !d->enabled || !d->finalized) {
+ QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ d->targetValue = value;
+ return;
+ }
+
+ if (d->animation->isRunning() && value == d->targetValue)
+ return;
+
+ d->currentValue = d->property.read();
+ d->targetValue = value;
+
+ if (d->animation->qtAnimation()->duration() != -1
+ && d->animation->qtAnimation()->state() != QAbstractAnimation::Stopped) {
+ d->blockRunningChanged = true;
+ d->animation->qtAnimation()->stop();
+ }
+
+ QDeclarativeStateOperation::ActionList actions;
+ QDeclarativeAction action;
+ action.property = d->property;
+ action.fromValue = d->currentValue;
+ action.toValue = value;
+ actions << action;
+
+ QList<QDeclarativeProperty> after;
+ d->animation->transition(actions, after, QDeclarativeAbstractAnimation::Forward);
+ d->animation->qtAnimation()->start();
+ d->blockRunningChanged = false;
+ if (!after.contains(d->property))
+ QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+}
+
+void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property)
+{
+ Q_D(QDeclarativeBehavior);
+ d->property = property;
+ d->currentValue = property.read();
+ if (d->animation)
+ d->animation->setDefaultTarget(property);
+
+ QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
+ engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+}
+
+void QDeclarativeBehavior::componentFinalized()
+{
+ Q_D(QDeclarativeBehavior);
+ d->finalized = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativebehavior_p.h b/src/declarative/util/qdeclarativebehavior_p.h
new file mode 100644
index 0000000000..838aedeb3c
--- /dev/null
+++ b/src/declarative/util/qdeclarativebehavior_p.h
@@ -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 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 QDECLARATIVEBEHAVIOR_H
+#define QDECLARATIVEBEHAVIOR_H
+
+#include "private/qdeclarativestate_p.h"
+
+#include <qdeclarativepropertyvaluesource.h>
+#include <qdeclarativepropertyvalueinterceptor.h>
+#include <qdeclarative.h>
+#include <QtCore/QAbstractAnimation>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeAbstractAnimation;
+class QDeclarativeBehaviorPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeBehavior : public QObject, public QDeclarativePropertyValueInterceptor
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeBehavior)
+
+ Q_INTERFACES(QDeclarativePropertyValueInterceptor)
+ Q_CLASSINFO("DefaultProperty", "animation")
+ Q_PROPERTY(QDeclarativeAbstractAnimation *animation READ animation WRITE setAnimation)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_CLASSINFO("DeferredPropertyNames", "animation")
+
+public:
+ QDeclarativeBehavior(QObject *parent=0);
+ ~QDeclarativeBehavior();
+
+ virtual void setTarget(const QDeclarativeProperty &);
+ virtual void write(const QVariant &value);
+
+ QDeclarativeAbstractAnimation *animation();
+ void setAnimation(QDeclarativeAbstractAnimation *);
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+Q_SIGNALS:
+ void enabledChanged();
+
+private Q_SLOTS:
+ void componentFinalized();
+ void qtAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeBehavior)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEBEHAVIOR_H
diff --git a/src/declarative/util/qdeclarativebind.cpp b/src/declarative/util/qdeclarativebind.cpp
new file mode 100644
index 0000000000..862c9dcf79
--- /dev/null
+++ b/src/declarative/util/qdeclarativebind.cpp
@@ -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 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/qdeclarativebind_p.h"
+
+#include "private/qdeclarativenullablevalue_p_p.h"
+
+#include <qdeclarativeengine.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeproperty.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBindPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeBindPrivate() : when(true), componentComplete(true), obj(0) {}
+
+ bool when : 1;
+ bool componentComplete : 1;
+ QObject *obj;
+ QString prop;
+ QDeclarativeNullableValue<QVariant> value;
+};
+
+
+/*!
+ \qmlclass Binding QDeclarativeBind
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The Binding element allows arbitrary property bindings to be created.
+
+ Sometimes it is necessary to bind to a property of an object that wasn't
+ directly instantiated by QML - generally a property of a class exported
+ to QML by C++. In these cases, regular property binding doesn't work. Binding
+ allows you to bind any value to any property.
+
+ For example, imagine a C++ application that maps an "app.enteredText"
+ property into QML. You could use Binding to update the enteredText property
+ like this.
+ \code
+ TextEdit { id: myTextField; text: "Please type here..." }
+ Binding { target: app; property: "enteredText"; value: myTextField.text }
+ \endcode
+ Whenever the text in the TextEdit is updated, the C++ property will be
+ updated also.
+
+ If the binding target or binding property is changed, the bound value is
+ immediately pushed onto the new target.
+
+ \sa QtDeclarative
+*/
+QDeclarativeBind::QDeclarativeBind(QObject *parent)
+ : QObject(*(new QDeclarativeBindPrivate), parent)
+{
+}
+
+QDeclarativeBind::~QDeclarativeBind()
+{
+}
+
+/*!
+ \qmlproperty bool Binding::when
+
+ This property holds when the binding is active.
+ This should be set to an expression that evaluates to true when you want the binding to be active.
+
+ \code
+ Binding {
+ target: contactName; property: 'text'
+ value: name; when: list.ListView.isCurrentItem
+ }
+ \endcode
+*/
+bool QDeclarativeBind::when() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->when;
+}
+
+void QDeclarativeBind::setWhen(bool v)
+{
+ Q_D(QDeclarativeBind);
+ d->when = v;
+ eval();
+}
+
+/*!
+ \qmlproperty Object Binding::target
+
+ The object to be updated.
+*/
+QObject *QDeclarativeBind::object()
+{
+ Q_D(const QDeclarativeBind);
+ return d->obj;
+}
+
+void QDeclarativeBind::setObject(QObject *obj)
+{
+ Q_D(QDeclarativeBind);
+ d->obj = obj;
+ eval();
+}
+
+/*!
+ \qmlproperty string Binding::property
+
+ The property to be updated.
+*/
+QString QDeclarativeBind::property() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->prop;
+}
+
+void QDeclarativeBind::setProperty(const QString &p)
+{
+ Q_D(QDeclarativeBind);
+ d->prop = p;
+ eval();
+}
+
+/*!
+ \qmlproperty any Binding::value
+
+ The value to be set on the target object and property. This can be a
+ constant (which isn't very useful), or a bound expression.
+*/
+QVariant QDeclarativeBind::value() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->value.value;
+}
+
+void QDeclarativeBind::setValue(const QVariant &v)
+{
+ Q_D(QDeclarativeBind);
+ d->value.value = v;
+ d->value.isNull = false;
+ eval();
+}
+
+void QDeclarativeBind::classBegin()
+{
+ Q_D(QDeclarativeBind);
+ d->componentComplete = false;
+}
+
+void QDeclarativeBind::componentComplete()
+{
+ Q_D(QDeclarativeBind);
+ d->componentComplete = true;
+ eval();
+}
+
+void QDeclarativeBind::eval()
+{
+ Q_D(QDeclarativeBind);
+ if (!d->obj || d->value.isNull || !d->when || !d->componentComplete)
+ return;
+
+ QDeclarativeProperty prop(d->obj, d->prop);
+ prop.write(d->value.value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativebind_p.h b/src/declarative/util/qdeclarativebind_p.h
new file mode 100644
index 0000000000..9fc65c3150
--- /dev/null
+++ b/src/declarative/util/qdeclarativebind_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEBIND_H
+#define QDECLARATIVEBIND_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeBindPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeBind : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeBind)
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QObject *target READ object WRITE setObject)
+ Q_PROPERTY(QString property READ property WRITE setProperty)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(bool when READ when WRITE setWhen)
+
+public:
+ QDeclarativeBind(QObject *parent=0);
+ ~QDeclarativeBind();
+
+ bool when() const;
+ void setWhen(bool);
+
+ QObject *object();
+ void setObject(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QVariant value() const;
+ void setValue(const QVariant &);
+
+protected:
+ virtual void classBegin();
+ virtual void componentComplete();
+
+private:
+ void eval();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeBind)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qdeclarativeconnections.cpp b/src/declarative/util/qdeclarativeconnections.cpp
new file mode 100644
index 0000000000..83a7d83161
--- /dev/null
+++ b/src/declarative/util/qdeclarativeconnections.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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/qdeclarativeconnections_p.h"
+
+#include <qdeclarativeexpression.h>
+#include <qdeclarativeproperty_p.h>
+#include <qdeclarativeboundsignal_p.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativecontext_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeConnectionsPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
+
+ QList<QDeclarativeBoundSignal*> boundsignals;
+ QObject *target;
+
+ bool targetSet;
+ bool ignoreUnknownSignals;
+ bool componentcomplete;
+
+ QByteArray data;
+};
+
+/*!
+ \qmlclass Connections QDeclarativeConnections
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief A Connections element describes generalized connections to signals.
+
+ A Connections object creates a connection to a QML signal.
+
+ When connecting to signals in QML, the usual way is to create an
+ "on<Signal>" handler that reacts when a signal is received, like this:
+
+ \qml
+ MouseArea {
+ onClicked: { foo(parameters) }
+ }
+ \endqml
+
+ However, it is not possible to connect to a signal in this way in some
+ cases, such as when:
+
+ \list
+ \i Multiple connections to the same signal are required
+ \i Creating connections outside the scope of the signal sender
+ \i Connecting to targets not defined in QML
+ \endlist
+
+ When any of these are needed, the Connections element can be used instead.
+
+ For example, the above code can be changed to use a Connections object,
+ like this:
+
+ \qml
+ MouseArea {
+ Connections {
+ onClicked: foo(parameters)
+ }
+ }
+ \endqml
+
+ More generally, the Connections object can be a child of some object other than
+ the sender of the signal:
+
+ \qml
+ MouseArea {
+ id: area
+ }
+ // ...
+ \endqml
+ \qml
+ Connections {
+ target: area
+ onClicked: foo(parameters)
+ }
+ \endqml
+
+ \sa QtDeclarative
+*/
+QDeclarativeConnections::QDeclarativeConnections(QObject *parent) :
+ QObject(*(new QDeclarativeConnectionsPrivate), parent)
+{
+}
+
+QDeclarativeConnections::~QDeclarativeConnections()
+{
+}
+
+/*!
+ \qmlproperty Object Connections::target
+ This property holds the object that sends the signal.
+
+ If this property is not set, the \c target defaults to the parent of the Connection.
+
+ If set to null, no connection is made and any signal handlers are ignored
+ until the target is not null.
+*/
+QObject *QDeclarativeConnections::target() const
+{
+ Q_D(const QDeclarativeConnections);
+ return d->targetSet ? d->target : parent();
+}
+
+void QDeclarativeConnections::setTarget(QObject *obj)
+{
+ Q_D(QDeclarativeConnections);
+ d->targetSet = true; // even if setting to 0, it is *set*
+ if (d->target == obj)
+ return;
+ foreach (QDeclarativeBoundSignal *s, d->boundsignals) {
+ // It is possible that target is being changed due to one of our signal
+ // handlers -> use deleteLater().
+ if (s->isEvaluating())
+ s->deleteLater();
+ else
+ delete s;
+ }
+ d->boundsignals.clear();
+ d->target = obj;
+ connectSignals();
+ emit targetChanged();
+}
+
+/*!
+ \qmlproperty bool Connections::ignoreUnknownSignals
+
+ Normally, a connection to a non-existent signal produces runtime errors.
+
+ If this property is set to \c true, such errors are ignored.
+ This is useful if you intend to connect to different types of objects, handling
+ a different set of signals for each object.
+*/
+bool QDeclarativeConnections::ignoreUnknownSignals() const
+{
+ Q_D(const QDeclarativeConnections);
+ return d->ignoreUnknownSignals;
+}
+
+void QDeclarativeConnections::setIgnoreUnknownSignals(bool ignore)
+{
+ Q_D(QDeclarativeConnections);
+ d->ignoreUnknownSignals = ignore;
+}
+
+
+
+QByteArray
+QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
+{
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ for(int ii = 0; ii < props.count(); ++ii)
+ {
+ QString propName = QString::fromUtf8(props.at(ii).name());
+ if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
+ return QByteArray();
+ }
+
+ QList<QVariant> values = props.at(ii).assignedValues();
+
+ for (int i = 0; i < values.count(); ++i) {
+ const QVariant &value = values.at(i);
+
+ if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
+ return QByteArray();
+ } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
+ return QByteArray();
+ } else {
+ QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(value);
+ if (v.isScript()) {
+ ds << propName;
+ ds << v.asScript();
+ } else {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
+ return QByteArray();
+ }
+ }
+ }
+ }
+
+ return rv;
+}
+
+void QDeclarativeConnectionsParser::setCustomData(QObject *object,
+ const QByteArray &data)
+{
+ QDeclarativeConnectionsPrivate *p =
+ static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
+ p->data = data;
+}
+
+
+void QDeclarativeConnections::connectSignals()
+{
+ Q_D(QDeclarativeConnections);
+ if (!d->componentcomplete || (d->targetSet && !target()))
+ return;
+
+ QDataStream ds(d->data);
+ while (!ds.atEnd()) {
+ QString propName;
+ ds >> propName;
+ QString script;
+ ds >> script;
+ QDeclarativeProperty prop(target(), propName);
+ if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
+ QDeclarativeBoundSignal *signal =
+ new QDeclarativeBoundSignal(target(), prop.method(), this);
+ QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(this), 0, script);
+ QDeclarativeData *ddata = QDeclarativeData::get(this);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ signal->setExpression(expression);
+ d->boundsignals += signal;
+ } else {
+ if (!d->ignoreUnknownSignals)
+ qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
+ }
+ }
+}
+
+void QDeclarativeConnections::classBegin()
+{
+ Q_D(QDeclarativeConnections);
+ d->componentcomplete=false;
+}
+
+void QDeclarativeConnections::componentComplete()
+{
+ Q_D(QDeclarativeConnections);
+ d->componentcomplete=true;
+ connectSignals();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeconnections_p.h b/src/declarative/util/qdeclarativeconnections_p.h
new file mode 100644
index 0000000000..6036018e63
--- /dev/null
+++ b/src/declarative/util/qdeclarativeconnections_p.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 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 QDECLARATIVECONNECTIONS_H
+#define QDECLARATIVECONNECTIONS_H
+
+#include <qdeclarative.h>
+#include <qdeclarativescriptstring.h>
+#include <private/qdeclarativecustomparser_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeBoundSignal;
+class QDeclarativeContext;
+class QDeclarativeConnectionsPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeConnections : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeConnections)
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
+
+public:
+ QDeclarativeConnections(QObject *parent=0);
+ ~QDeclarativeConnections();
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ bool ignoreUnknownSignals() const;
+ void setIgnoreUnknownSignals(bool ignore);
+
+Q_SIGNALS:
+ void targetChanged();
+
+private:
+ void connectSignals();
+ void classBegin();
+ void componentComplete();
+};
+
+class QDeclarativeConnectionsParser : public QDeclarativeCustomParser
+{
+public:
+ virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &);
+ virtual void setCustomData(QObject *, const QByteArray &);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeConnections)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp
new file mode 100644
index 0000000000..eba9cf96ac
--- /dev/null
+++ b/src/declarative/util/qdeclarativefontloader.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativefontloader_p.h"
+
+#include <qdeclarativecontext.h>
+#include <qdeclarativeengine.h>
+
+#include <QStringList>
+#include <QUrl>
+#include <QDebug>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QFontDatabase>
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
+
+class QDeclarativeFontObject : public QObject
+{
+Q_OBJECT
+
+public:
+ QDeclarativeFontObject(int _id);
+
+ void download(const QUrl &url, QNetworkAccessManager *manager);
+
+Q_SIGNALS:
+ void fontDownloaded(const QString&, QDeclarativeFontLoader::Status);
+
+private Q_SLOTS:
+ void replyFinished();
+
+public:
+ int id;
+
+private:
+ QNetworkReply *reply;
+ int redirectCount;
+
+ Q_DISABLE_COPY(QDeclarativeFontObject)
+};
+
+QDeclarativeFontObject::QDeclarativeFontObject(int _id = -1)
+ : QObject(0), id(_id), reply(0), redirectCount(0) {}
+
+
+void QDeclarativeFontObject::download(const QUrl &url, QNetworkAccessManager *manager)
+{
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ reply = manager->get(req);
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+}
+
+void QDeclarativeFontObject::replyFinished()
+{
+ if (reply) {
+ redirectCount++;
+ if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkAccessManager *manager = reply->manager();
+ reply->deleteLater();
+ reply = 0;
+ download(url, manager);
+ return;
+ }
+ }
+ redirectCount = 0;
+
+ if (!reply->error()) {
+ id = QFontDatabase::addApplicationFontFromData(reply->readAll());
+ if (id != -1)
+ emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarativeFontLoader::Ready);
+ else
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ } else {
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ }
+ reply->deleteLater();
+ reply = 0;
+ }
+}
+
+
+class QDeclarativeFontLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeFontLoader)
+
+public:
+ QDeclarativeFontLoaderPrivate() : status(QDeclarativeFontLoader::Null) {}
+
+ QUrl url;
+ QString name;
+ QDeclarativeFontLoader::Status status;
+ static QHash<QUrl, QDeclarativeFontObject*> fonts;
+};
+
+QHash<QUrl, QDeclarativeFontObject*> QDeclarativeFontLoaderPrivate::fonts;
+
+/*!
+ \qmlclass FontLoader QDeclarativeFontLoader
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The FontLoader element allows fonts to be loaded by name or URL.
+
+ The FontLoader element is used to load fonts by name or URL.
+
+ The \l status indicates when the font has been loaded, which is useful
+ for fonts loaded from remote sources.
+
+ For example:
+ \qml
+ import QtQuick 1.0
+
+ Column {
+ FontLoader { id: fixedFont; name: "Courier" }
+ FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
+
+ Text { text: "Fixed-size font"; font.family: fixedFont.name }
+ Text { text: "Fancy font"; font.family: webFont.name }
+ }
+ \endqml
+
+ \sa {declarative/text/fonts}{Fonts example}
+*/
+QDeclarativeFontLoader::QDeclarativeFontLoader(QObject *parent)
+ : QObject(*(new QDeclarativeFontLoaderPrivate), parent)
+{
+}
+
+QDeclarativeFontLoader::~QDeclarativeFontLoader()
+{
+}
+
+/*!
+ \qmlproperty url FontLoader::source
+ The url of the font to load.
+*/
+QUrl QDeclarativeFontLoader::source() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->url;
+}
+
+void QDeclarativeFontLoader::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeFontLoader);
+ if (url == d->url)
+ return;
+ d->url = qmlContext(this)->resolvedUrl(url);
+ emit sourceChanged();
+
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!localFile.isEmpty()) {
+ if (!d->fonts.contains(d->url)) {
+ int id = QFontDatabase::addApplicationFont(localFile);
+ if (id != -1) {
+ updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready);
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject(id);
+ d->fonts[d->url] = fo;
+ } else {
+ updateFontInfo(QString(), Error);
+ }
+ } else {
+ updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready);
+ }
+ } else
+#endif
+ {
+ if (!d->fonts.contains(d->url)) {
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject;
+ d->fonts[d->url] = fo;
+ fo->download(d->url, qmlEngine(this)->networkAccessManager());
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
+ } else {
+ QDeclarativeFontObject *fo = d->fonts[d->url];
+ if (fo->id == -1) {
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
+ }
+ else
+ updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready);
+ }
+ }
+}
+
+void QDeclarativeFontLoader::updateFontInfo(const QString& name, QDeclarativeFontLoader::Status status)
+{
+ Q_D(QDeclarativeFontLoader);
+
+ if (name != d->name) {
+ d->name = name;
+ emit nameChanged();
+ }
+ if (status != d->status) {
+ if (status == Error)
+ qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\"";
+ d->status = status;
+ emit statusChanged();
+ }
+}
+
+/*!
+ \qmlproperty string FontLoader::name
+
+ This property holds the name of the font family.
+ It is set automatically when a font is loaded using the \c url property.
+
+ Use this to set the \c font.family property of a \c Text item.
+
+ Example:
+ \qml
+ Item {
+ width: 200; height: 50
+
+ FontLoader {
+ id: webFont
+ source: "http://www.mysite.com/myfont.ttf"
+ }
+ Text {
+ text: "Fancy font"
+ font.family: webFont.name
+ }
+ }
+ \endqml
+*/
+QString QDeclarativeFontLoader::name() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->name;
+}
+
+void QDeclarativeFontLoader::setName(const QString &name)
+{
+ Q_D(QDeclarativeFontLoader);
+ if (d->name == name)
+ return;
+ d->name = name;
+ emit nameChanged();
+ d->status = Ready;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration FontLoader::status
+
+ This property holds the status of font loading. It can be one of:
+ \list
+ \o FontLoader.Null - no font has been set
+ \o FontLoader.Ready - the font has been loaded
+ \o FontLoader.Loading - the font is currently being loaded
+ \o FontLoader.Error - an error occurred while loading the font
+ \endlist
+
+ Use this status to provide an update or respond to the status change in some way.
+ For example, you could:
+
+ \list
+ \o Trigger a state change:
+ \qml
+ State { name: 'loaded'; when: loader.status == FontLoader.Ready }
+ \endqml
+
+ \o Implement an \c onStatusChanged signal handler:
+ \qml
+ FontLoader {
+ id: loader
+ onStatusChanged: if (loader.status == FontLoader.Ready) console.log('Loaded')
+ }
+ \endqml
+
+ \o Bind to the status value:
+ \qml
+ Text { text: loader.status == FontLoader.Ready ? 'Loaded' : 'Not loaded' }
+ \endqml
+ \endlist
+*/
+QDeclarativeFontLoader::Status QDeclarativeFontLoader::status() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->status;
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativefontloader.moc>
diff --git a/src/declarative/util/qdeclarativefontloader_p.h b/src/declarative/util/qdeclarativefontloader_p.h
new file mode 100644
index 0000000000..46cfb5b129
--- /dev/null
+++ b/src/declarative/util/qdeclarativefontloader_p.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 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 QDECLARATIVEFONTLOADER_H
+#define QDECLARATIVEFONTLOADER_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeFontLoaderPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeFontLoader : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeFontLoader)
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+public:
+ enum Status { Null = 0, Ready, Loading, Error };
+
+ QDeclarativeFontLoader(QObject *parent = 0);
+ ~QDeclarativeFontLoader();
+
+ QUrl source() const;
+ void setSource(const QUrl &url);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ Status status() const;
+
+private Q_SLOTS:
+ void updateFontInfo(const QString&, QDeclarativeFontLoader::Status);
+
+Q_SIGNALS:
+ void sourceChanged();
+ void nameChanged();
+ void statusChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFontLoader)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFONTLOADER_H
+
diff --git a/src/declarative/util/qdeclarativelistaccessor.cpp b/src/declarative/util/qdeclarativelistaccessor.cpp
new file mode 100644
index 0000000000..6c9f0291b5
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistaccessor.cpp
@@ -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 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/qdeclarativelistaccessor_p.h"
+
+#include <qdeclarativemetatype_p.h>
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdebug.h>
+
+// ### Remove me
+#include <qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeListAccessor::QDeclarativeListAccessor()
+: m_type(Invalid)
+{
+}
+
+QDeclarativeListAccessor::~QDeclarativeListAccessor()
+{
+}
+
+QVariant QDeclarativeListAccessor::list() const
+{
+ return d;
+}
+
+void QDeclarativeListAccessor::setList(const QVariant &v, QDeclarativeEngine *engine)
+{
+ d = v;
+
+ QDeclarativeEnginePrivate *enginePrivate = engine?QDeclarativeEnginePrivate::get(engine):0;
+
+ if (!d.isValid()) {
+ m_type = Invalid;
+ } else if (d.userType() == QVariant::StringList) {
+ m_type = StringList;
+ } else if (d.userType() == QMetaType::QVariantList) {
+ m_type = VariantList;
+ } else if (d.canConvert(QVariant::Int)) {
+ m_type = Integer;
+ } else if ((!enginePrivate && QDeclarativeMetaType::isQObject(d.userType())) ||
+ (enginePrivate && enginePrivate->isQObject(d.userType()))) {
+ QObject *data = enginePrivate?enginePrivate->toQObject(v):QDeclarativeMetaType::toQObject(v);
+ d = QVariant::fromValue(data);
+ m_type = Instance;
+ } else if (d.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ m_type = ListProperty;
+ } else {
+ m_type = Instance;
+ }
+}
+
+int QDeclarativeListAccessor::count() const
+{
+ switch(m_type) {
+ case StringList:
+ return qvariant_cast<QStringList>(d).count();
+ case VariantList:
+ return qvariant_cast<QVariantList>(d).count();
+ case ListProperty:
+ return ((QDeclarativeListReference *)d.constData())->count();
+ case Instance:
+ return 1;
+ case Integer:
+ return d.toInt();
+ default:
+ case Invalid:
+ return 0;
+ }
+}
+
+QVariant QDeclarativeListAccessor::at(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < count());
+ switch(m_type) {
+ case StringList:
+ return QVariant::fromValue(qvariant_cast<QStringList>(d).at(idx));
+ case VariantList:
+ return qvariant_cast<QVariantList>(d).at(idx);
+ case ListProperty:
+ return QVariant::fromValue(((QDeclarativeListReference *)d.constData())->at(idx));
+ case Instance:
+ return d;
+ case Integer:
+ return QVariant(idx);
+ default:
+ case Invalid:
+ return QVariant();
+ }
+}
+
+bool QDeclarativeListAccessor::isValid() const
+{
+ return m_type != Invalid;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativelistaccessor_p.h b/src/declarative/util/qdeclarativelistaccessor_p.h
new file mode 100644
index 0000000000..780d7fe617
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistaccessor_p.h
@@ -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 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 QDECLARATIVELISTACCESSOR_H
+#define QDECLARATIVELISTACCESSOR_H
+
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class Q_AUTOTEST_EXPORT QDeclarativeListAccessor
+{
+public:
+ QDeclarativeListAccessor();
+ ~QDeclarativeListAccessor();
+
+ QVariant list() const;
+ void setList(const QVariant &, QDeclarativeEngine * = 0);
+
+ bool isValid() const;
+
+ int count() const;
+ QVariant at(int) const;
+
+ enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer };
+ Type type() const { return m_type; }
+
+private:
+ Type m_type;
+ QVariant d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELISTACCESSOR_H
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
new file mode 100644
index 0000000000..61b2d3463a
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodel.cpp
@@ -0,0 +1,1627 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativelistmodel_p_p.h"
+#include "private/qdeclarativelistmodelworkeragent_p.h"
+#include "private/qdeclarativeopenmetaobject_p.h"
+
+#include <qdeclarativecustomparser_p.h>
+#include <qdeclarativeparser_p.h>
+#include <qdeclarativeengine_p.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstack.h>
+#include <QXmlStreamReader>
+#include <QtScript/qscriptvalueiterator.h>
+
+Q_DECLARE_METATYPE(QListModelInterface *)
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+void qdeclarativelistmodel_move(int from, int to, int n, T *items)
+{
+ if (n == 1) {
+ items->move(from, to);
+ } else {
+ T replaced;
+ int i=0;
+ typename T::ConstIterator it=items->begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=items->begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ typename T::ConstIterator f=replaced.begin();
+ typename T::Iterator t=items->begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+}
+
+QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListModelData::instructions() const
+{
+ return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData));
+}
+
+/*!
+ \qmlclass ListModel QDeclarativeListModel
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The ListModel element defines a free-form list data source.
+
+ The ListModel is a simple container of ListElement definitions, each containing data roles.
+ The contents can be defined dynamically, or explicitly in QML.
+
+ The number of elements in the model can be obtained from its \l count property.
+ A number of familiar methods are also provided to manipulate the contents of the
+ model, including append(), insert(), move(), remove() and set(). These methods
+ accept dictionaries as their arguments; these are translated to ListElement objects
+ by the model.
+
+ Elements can be manipulated via the model using the setProperty() method, which
+ allows the roles of the specified element to be set and changed.
+
+ \section1 Example Usage
+
+ The following example shows a ListModel containing three elements, with the roles
+ "name" and "cost".
+
+ \div {class="float-right"}
+ \inlineimage listmodel.png
+ \enddiv
+
+ \snippet doc/src/snippets/declarative/listmodel.qml 0
+
+ \clearfloat
+ Roles (properties) in each element must begin with a lower-case letter and
+ should be common to all elements in a model. The ListElement documentation
+ provides more guidelines for how elements should be defined.
+
+ Since the example model contains an \c id property, it can be referenced
+ by views, such as the ListView in this example:
+
+ \snippet doc/src/snippets/declarative/listmodel-simple.qml 0
+ \dots 8
+ \snippet doc/src/snippets/declarative/listmodel-simple.qml 1
+
+ It is possible for roles to contain list data. In the following example we
+ create a list of fruit attributes:
+
+ \snippet doc/src/snippets/declarative/listmodel-nested.qml model
+
+ The delegate displays all the fruit attributes:
+
+ \div {class="float-right"}
+ \inlineimage listmodel-nested.png
+ \enddiv
+
+ \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate
+
+ \clearfloat
+ \section1 Modifying List Models
+
+ The content of a ListModel may be created and modified using the clear(),
+ append(), set(), insert() and setProperty() methods. For example:
+
+ \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate
+
+ Note that when creating content dynamically the set of available properties
+ cannot be changed once set. Whatever properties are first added to the model
+ are the only permitted properties in the model.
+
+ \section1 Using Threaded List Models with WorkerScript
+
+ ListModel can be used together with WorkerScript access a list model
+ from multiple threads. This is useful if list modifications are
+ synchronous and take some time: the list operations can be moved to a
+ different thread to avoid blocking of the main GUI thread.
+
+ Here is an example that uses WorkerScript to periodically append the
+ current time to a list model:
+
+ \snippet examples/declarative/threading/threadedlistmodel/timedisplay.qml 0
+
+ The included file, \tt dataloader.js, looks like this:
+
+ \snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0
+
+ The timer in the main example sends messages to the worker script by calling
+ \l WorkerScript::sendMessage(). When this message is received,
+ \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js,
+ which appends the current time to the list model.
+
+ Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()}
+ handler. You must call sync() or else the changes made to the list from the external
+ thread will not be reflected in the list model in the main thread.
+
+ \section1 Restrictions
+
+ If a list model is to be accessed from a WorkerScript, it cannot
+ contain list-type data. So, the following model cannot be used from a WorkerScript
+ because of the list contained in the "attributes" property:
+
+ \code
+ ListModel {
+ id: fruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ attributes: [
+ ListElement { description: "Core" },
+ ListElement { description: "Deciduous" }
+ ]
+ }
+ }
+ \endcode
+
+ In addition, the WorkerScript cannot add list-type data to the model.
+
+ \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative
+*/
+
+
+/*
+ A ListModel internally uses either a NestedListModel or FlatListModel.
+
+ A NestedListModel can contain lists of ListElements (which
+ when retrieved from get() is accessible as a list model within the list
+ model) whereas a FlatListModel cannot.
+
+ ListModel uses a NestedListModel to begin with, and if the model is later
+ used from a WorkerScript, it changes to use a FlatListModel instead. This
+ is because ModelNode (which abstracts the nested list model data) needs
+ access to the declarative engine and script engine, which cannot be
+ safely used from outside of the main thread.
+*/
+
+QDeclarativeListModel::QDeclarativeListModel(QObject *parent)
+: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0)
+{
+}
+
+QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent)
+: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0)
+{
+ m_flat = new FlatListModel(this);
+ m_flat->m_parentAgent = parent;
+
+ if (orig->m_flat) {
+ m_flat->m_roles = orig->m_flat->m_roles;
+ m_flat->m_strings = orig->m_flat->m_strings;
+ m_flat->m_values = orig->m_flat->m_values;
+
+ m_flat->m_nodeData.reserve(m_flat->m_values.count());
+ for (int i=0; i<m_flat->m_values.count(); i++)
+ m_flat->m_nodeData << 0;
+ }
+}
+
+QDeclarativeListModel::~QDeclarativeListModel()
+{
+ if (m_agent)
+ m_agent->release();
+
+ delete m_nested;
+ delete m_flat;
+}
+
+bool QDeclarativeListModel::flatten()
+{
+ if (m_flat)
+ return true;
+
+ QList<int> roles = m_nested->roles();
+
+ QList<QHash<int, QVariant> > values;
+ bool hasNested = false;
+ for (int i=0; i<m_nested->count(); i++) {
+ values.append(m_nested->data(i, roles, &hasNested));
+ if (hasNested)
+ return false;
+ }
+
+ FlatListModel *flat = new FlatListModel(this);
+ flat->m_values = values;
+
+ for (int i=0; i<roles.count(); i++) {
+ QString s = m_nested->toString(roles[i]);
+ flat->m_roles.insert(roles[i], s);
+ flat->m_strings.insert(s, roles[i]);
+ }
+
+ flat->m_nodeData.reserve(flat->m_values.count());
+ for (int i=0; i<flat->m_values.count(); i++)
+ flat->m_nodeData << 0;
+
+ m_flat = flat;
+ delete m_nested;
+ m_nested = 0;
+ return true;
+}
+
+bool QDeclarativeListModel::inWorkerThread() const
+{
+ return m_flat && m_flat->m_parentAgent;
+}
+
+QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent()
+{
+ if (m_agent)
+ return m_agent;
+
+ if (!flatten()) {
+ qmlInfo(this) << "List contains list-type data and cannot be used from a worker script";
+ return 0;
+ }
+
+ m_agent = new QDeclarativeListModelWorkerAgent(this);
+ return m_agent;
+}
+
+QList<int> QDeclarativeListModel::roles() const
+{
+ return m_flat ? m_flat->roles() : m_nested->roles();
+}
+
+QString QDeclarativeListModel::toString(int role) const
+{
+ return m_flat ? m_flat->toString(role) : m_nested->toString(role);
+}
+
+QVariant QDeclarativeListModel::data(int index, int role) const
+{
+ if (index >= count() || index < 0)
+ return QVariant();
+
+ return m_flat ? m_flat->data(index, role) : m_nested->data(index, role);
+}
+
+/*!
+ \qmlproperty int ListModel::count
+ The number of data entries in the model.
+*/
+int QDeclarativeListModel::count() const
+{
+ return m_flat ? m_flat->count() : m_nested->count();
+}
+
+/*!
+ \qmlmethod ListModel::clear()
+
+ Deletes all content from the model.
+
+ \sa append() remove()
+*/
+void QDeclarativeListModel::clear()
+{
+ int cleared = count();
+ if (m_flat)
+ m_flat->clear();
+ else
+ m_nested->clear();
+
+ if (!inWorkerThread()) {
+ emit itemsRemoved(0, cleared);
+ emit countChanged();
+ }
+}
+
+QDeclarativeListModel *ModelNode::model(const NestedListModel *model)
+{
+ if (!modelCache) {
+ modelCache = new QDeclarativeListModel;
+ QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(model->m_listModel));
+ modelCache->m_nested->_root = this; // ListModel defaults to nestable model
+
+ for (int i=0; i<values.count(); ++i) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(values.at(i));
+ if (subNode)
+ subNode->m_model = modelCache->m_nested;
+ }
+ }
+ return modelCache;
+}
+
+ModelObject *ModelNode::object(const NestedListModel *model)
+{
+ if (!objectCache) {
+ objectCache = new ModelObject(this,
+ const_cast<NestedListModel*>(model),
+ QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(model->m_listModel)));
+ QHash<QString, ModelNode *>::iterator it;
+ for (it = properties.begin(); it != properties.end(); ++it) {
+ objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it));
+ }
+ objectCache->setNodeUpdatesEnabled(true);
+ }
+ return objectCache;
+}
+
+/*!
+ \qmlmethod ListModel::remove(int index)
+
+ Deletes the content at \a index from the model.
+
+ \sa clear()
+*/
+void QDeclarativeListModel::remove(int index)
+{
+ if (index < 0 || index >= count()) {
+ qmlInfo(this) << tr("remove: index %1 out of range").arg(index);
+ return;
+ }
+
+ if (m_flat)
+ m_flat->remove(index);
+ else
+ m_nested->remove(index);
+
+ if (!inWorkerThread()) {
+ emit itemsRemoved(index, 1);
+ emit countChanged();
+ }
+}
+
+/*!
+ \qmlmethod ListModel::insert(int index, jsobject dict)
+
+ Adds a new item to the list model at position \a index, with the
+ values in \a dict.
+
+ \code
+ fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be to an existing item in the list, or one past
+ the end of the list (equivalent to append).
+
+ \sa set() append()
+*/
+void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qmlInfo(this) << tr("insert: value is not an object");
+ return;
+ }
+
+ if (index < 0 || index > count()) {
+ qmlInfo(this) << tr("insert: index %1 out of range").arg(index);
+ return;
+ }
+
+ bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap);
+ if (ok && !inWorkerThread()) {
+ emit itemsInserted(index, 1);
+ emit countChanged();
+ }
+}
+
+/*!
+ \qmlmethod ListModel::move(int from, int to, int n)
+
+ Moves \a n items \a from one position \a to another.
+
+ The from and to ranges must exist; for example, to move the first 3 items
+ to the end of the list:
+
+ \code
+ fruitModel.move(0, fruitModel.count - 3, 3)
+ \endcode
+
+ \sa append()
+*/
+void QDeclarativeListModel::move(int from, int to, int n)
+{
+ if (n==0 || from==to)
+ return;
+ if (!canMove(from, to, n)) {
+ qmlInfo(this) << tr("move: out of range");
+ return;
+ }
+
+ int origfrom = from;
+ int origto = to;
+ int orign = n;
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ to = tto+n;
+ n = tfrom-tto;
+ }
+
+ if (m_flat)
+ m_flat->move(from, to, n);
+ else
+ m_nested->move(from, to, n);
+
+ if (!inWorkerThread())
+ emit itemsMoved(origfrom, origto, orign);
+}
+
+/*!
+ \qmlmethod ListModel::append(jsobject dict)
+
+ Adds a new item to the end of the list model, with the
+ values in \a dict.
+
+ \code
+ fruitModel.append({"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ \sa set() remove()
+*/
+void QDeclarativeListModel::append(const QScriptValue& valuemap)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qmlInfo(this) << tr("append: value is not an object");
+ return;
+ }
+
+ insert(count(), valuemap);
+}
+
+/*!
+ \qmlmethod object ListModel::get(int index)
+
+ Returns the item at \a index in the list model. This allows the item
+ data to be accessed or modified from JavaScript:
+
+ \code
+ Component.onCompleted: {
+ fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
+ console.log(fruitModel.get(0).cost);
+ fruitModel.get(0).cost = 10.95;
+ }
+ \endcode
+
+ The \a index must be an element in the list.
+
+ Note that properties of the returned object that are themselves objects
+ will also be models, and this get() method is used to access elements:
+
+ \code
+ fruitModel.append(..., "attributes":
+ [{"name":"spikes","value":"7mm"},
+ {"name":"color","value":"green"}]);
+ fruitModel.get(0).attributes.get(1).value; // == "green"
+ \endcode
+
+ \warning The returned object is not guaranteed to remain valid. It
+ should not be used in \l{Property Binding}{property bindings}.
+
+ \sa append()
+*/
+QScriptValue QDeclarativeListModel::get(int index) const
+{
+ // the internal flat/nested class checks for bad index
+ return m_flat ? m_flat->get(index) : m_nested->get(index);
+}
+
+/*!
+ \qmlmethod ListModel::set(int index, jsobject dict)
+
+ Changes the item at \a index in the list model with the
+ values in \a dict. Properties not appearing in \a dict
+ are left unchanged.
+
+ \code
+ fruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ If \a index is equal to count() then a new item is appended to the
+ list. Otherwise, \a index must be an element in the list.
+
+ \sa append()
+*/
+void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
+{
+ QList<int> roles;
+ set(index, valuemap, &roles);
+ if (!roles.isEmpty() && !inWorkerThread())
+ emit itemsChanged(index, 1, roles);
+}
+
+void QDeclarativeListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qmlInfo(this) << tr("set: value is not an object");
+ return;
+ }
+ if (index > count() || index < 0) {
+ qmlInfo(this) << tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ if (index == count()) {
+ append(valuemap);
+ } else {
+ if (m_flat)
+ m_flat->set(index, valuemap, roles);
+ else
+ m_nested->set(index, valuemap, roles);
+ }
+}
+
+/*!
+ \qmlmethod ListModel::setProperty(int index, string property, variant value)
+
+ Changes the \a property of the item at \a index in the list model to \a value.
+
+ \code
+ fruitModel.setProperty(3, "cost", 5.95)
+ \endcode
+
+ The \a index must be an element in the list.
+
+ \sa append()
+*/
+void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value)
+{
+ QList<int> roles;
+ setProperty(index, property, value, &roles);
+ if (!roles.isEmpty() && !inWorkerThread())
+ emit itemsChanged(index, 1, roles);
+}
+
+void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
+ if (count() == 0 || index >= count() || index < 0) {
+ qmlInfo(this) << tr("set: index %1 out of range").arg(index);
+ return;
+ }
+
+ if (m_flat)
+ m_flat->setProperty(index, property, value, roles);
+ else
+ m_nested->setProperty(index, property, value, roles);
+}
+
+/*!
+ \qmlmethod ListModel::sync()
+
+ Writes any unsaved changes to the list model after it has been modified
+ from a worker script.
+*/
+void QDeclarativeListModel::sync()
+{
+ // This is just a dummy method to make it look like sync() exists in
+ // ListModel (and not just QDeclarativeListModelWorkerAgent) and to let
+ // us document sync().
+ qmlInfo(this) << "List sync() can only be called from a WorkerScript";
+}
+
+bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data)
+{
+ QList<QVariant> values = prop.assignedValues();
+ for(int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if(value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
+ QDeclarativeCustomParserNode node =
+ qvariant_cast<QDeclarativeCustomParserNode>(value);
+
+ if (node.name() != listElementTypeName) {
+ const QMetaObject *mo = resolveType(node.name());
+ if (mo != &QDeclarativeListElement::staticMetaObject) {
+ error(node, QDeclarativeListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ listElementTypeName = node.name(); // cache right name for next time
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Push;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ QList<QDeclarativeCustomParserProperty> props = node.properties();
+ for(int jj = 0; jj < props.count(); ++jj) {
+ const QDeclarativeCustomParserProperty &nodeProp = props.at(jj);
+ if (nodeProp.name().isEmpty()) {
+ error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot contain nested elements"));
+ return false;
+ }
+ if (nodeProp.name() == "id") {
+ error(nodeProp, QDeclarativeListModel::tr("ListElement: cannot use reserved \"id\" property"));
+ return false;
+ }
+
+ ListInstruction li;
+ int ref = data.count();
+ data.append(nodeProp.name());
+ data.append('\0');
+ li.type = ListInstruction::Set;
+ li.dataIdx = ref;
+ instr << li;
+
+ if(!compileProperty(nodeProp, instr, data))
+ return false;
+
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ } else {
+
+ QDeclarativeParser::Variant variant =
+ qvariant_cast<QDeclarativeParser::Variant>(value);
+
+ int ref = data.count();
+
+ QByteArray d;
+ d += char(variant.type()); // type tag
+ if (variant.isString()) {
+ d += variant.asString().toUtf8();
+ } else if (variant.isNumber()) {
+ d += QByteArray::number(variant.asNumber(),'g',20);
+ } else if (variant.isBoolean()) {
+ d += char(variant.asBoolean());
+ } else if (variant.isScript()) {
+ if (definesEmptyList(variant.asScript())) {
+ d[0] = char(QDeclarativeParser::Variant::Invalid); // marks empty list
+ } else {
+ QByteArray script = variant.asScript().toUtf8();
+ int v = evaluateEnum(script);
+ if (v<0) {
+ if (script.startsWith("QT_TR_NOOP(\"") && script.endsWith("\")")) {
+ d[0] = char(QDeclarativeParser::Variant::String);
+ d += script.mid(12,script.length()-14);
+ } else {
+ error(prop, QDeclarativeListModel::tr("ListElement: cannot use script for property value"));
+ return false;
+ }
+ } else {
+ d[0] = char(QDeclarativeParser::Variant::Number);
+ d += QByteArray::number(v);
+ }
+ }
+ }
+ d.append('\0');
+ data.append(d);
+
+ ListInstruction li;
+ li.type = ListInstruction::Value;
+ li.dataIdx = ref;
+ instr << li;
+ }
+ }
+
+ return true;
+}
+
+QByteArray QDeclarativeListModelParser::compile(const QList<QDeclarativeCustomParserProperty> &customProps)
+{
+ QList<ListInstruction> instr;
+ QByteArray data;
+ listElementTypeName = QByteArray(); // unknown
+
+ for(int ii = 0; ii < customProps.count(); ++ii) {
+ const QDeclarativeCustomParserProperty &prop = customProps.at(ii);
+ if(!prop.name().isEmpty()) { // isn't default property
+ error(prop, QDeclarativeListModel::tr("ListModel: undefined property '%1'").arg(QString::fromUtf8(prop.name())));
+ return QByteArray();
+ }
+
+ if(!compileProperty(prop, instr, data)) {
+ return QByteArray();
+ }
+ }
+
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
+ data.count();
+
+ QByteArray rv;
+ rv.resize(size);
+
+ ListModelData *lmd = (ListModelData *)rv.data();
+ lmd->dataOffset = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction);
+ lmd->instrCount = instr.count();
+ for (int ii = 0; ii < instr.count(); ++ii)
+ lmd->instructions()[ii] = instr.at(ii);
+ ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
+
+ return rv;
+}
+
+void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &d)
+{
+ QDeclarativeListModel *rv = static_cast<QDeclarativeListModel *>(obj);
+
+ ModelNode *root = new ModelNode(rv->m_nested);
+ rv->m_nested->_root = root;
+ QStack<ModelNode *> nodes;
+ nodes << root;
+
+ bool processingSet = false;
+
+ const ListModelData *lmd = (const ListModelData *)d.constData();
+ const char *data = ((const char *)lmd) + lmd->dataOffset;
+
+ for (int ii = 0; ii < lmd->instrCount; ++ii) {
+ const ListInstruction &instr = lmd->instructions()[ii];
+
+ switch(instr.type) {
+ case ListInstruction::Push:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode(rv->m_nested);
+ n->values << QVariant::fromValue(n2);
+ nodes.push(n2);
+ if (processingSet)
+ n->isArray = true;
+ }
+ break;
+
+ case ListInstruction::Pop:
+ nodes.pop();
+ break;
+
+ case ListInstruction::Value:
+ {
+ ModelNode *n = nodes.top();
+ switch (QDeclarativeParser::Variant::Type(data[instr.dataIdx])) {
+ case QDeclarativeParser::Variant::Invalid:
+ n->isArray = true;
+ break;
+ case QDeclarativeParser::Variant::Boolean:
+ n->values.append(bool(data[1 + instr.dataIdx]));
+ break;
+ case QDeclarativeParser::Variant::Number:
+ n->values.append(QByteArray(data + 1 + instr.dataIdx).toDouble());
+ break;
+ case QDeclarativeParser::Variant::String:
+ n->values.append(QString::fromUtf8(data + 1 + instr.dataIdx));
+ break;
+ default:
+ Q_ASSERT("Format error in ListInstruction");
+ }
+
+ processingSet = false;
+ }
+ break;
+
+ case ListInstruction::Set:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode(rv->m_nested);
+ n->properties.insert(QString::fromUtf8(data + instr.dataIdx), n2);
+ nodes.push(n2);
+ processingSet = true;
+ }
+ break;
+ }
+ }
+
+ ModelNode *rootNode = rv->m_nested->_root;
+ for (int i=0; i<rootNode->values.count(); ++i) {
+ ModelNode *node = qvariant_cast<ModelNode *>(rootNode->values[i]);
+ node->listIndex = i;
+ node->updateListIndexes();
+ }
+}
+
+bool QDeclarativeListModelParser::definesEmptyList(const QString &s)
+{
+ if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
+ for (int i=1; i<s.length()-1; i++) {
+ if (!s[i].isSpace())
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+/*!
+ \qmlclass ListElement QDeclarativeListElement
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The ListElement element defines a data item in a ListModel.
+
+ List elements are defined inside ListModel definitions, and represent items in a
+ list that will be displayed using ListView or \l Repeater items.
+
+ List elements are defined like other QML elements except that they contain
+ a collection of \e role definitions instead of properties. Using the same
+ syntax as property definitions, roles both define how the data is accessed
+ and include the data itself.
+
+ The names used for roles must begin with a lower-case letter and should be
+ common to all elements in a given model. Values must be simple constants; either
+ strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
+ (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
+
+ \section1 Referencing Roles
+
+ The role names are used by delegates to obtain data from list elements.
+ Each role name is accessible in the delegate's scope, and refers to the
+ corresponding role in the current element. Where a role name would be
+ ambiguous to use, it can be accessed via the \l{ListView::}{model}
+ property (e.g., \c{model.cost} instead of \c{cost}).
+
+ \section1 Example Usage
+
+ The following model defines a series of list elements, each of which
+ contain "name" and "cost" roles and their associated values.
+
+ \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml model
+
+ The delegate obtains the name and cost for each element by simply referring
+ to \c name and \c cost:
+
+ \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml view
+
+ \sa ListModel
+*/
+
+FlatListModel::FlatListModel(QDeclarativeListModel *base)
+ : m_scriptEngine(0), m_listModel(base), m_scriptClass(0), m_parentAgent(0)
+{
+}
+
+FlatListModel::~FlatListModel()
+{
+ qDeleteAll(m_nodeData);
+}
+
+QVariant FlatListModel::data(int index, int role) const
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+ if (m_values[index].contains(role))
+ return m_values[index][role];
+ return QVariant();
+}
+
+QList<int> FlatListModel::roles() const
+{
+ return m_roles.keys();
+}
+
+QString FlatListModel::toString(int role) const
+{
+ if (m_roles.contains(role))
+ return m_roles[role];
+ return QString();
+}
+
+int FlatListModel::count() const
+{
+ return m_values.count();
+}
+
+void FlatListModel::clear()
+{
+ m_values.clear();
+
+ qDeleteAll(m_nodeData);
+ m_nodeData.clear();
+}
+
+void FlatListModel::remove(int index)
+{
+ m_values.removeAt(index);
+ removedNode(index);
+}
+
+bool FlatListModel::insert(int index, const QScriptValue &value)
+{
+ Q_ASSERT(index >= 0 && index <= m_values.count());
+
+ QHash<int, QVariant> row;
+ if (!addValue(value, &row, 0))
+ return false;
+
+ m_values.insert(index, row);
+ insertedNode(index);
+
+ return true;
+}
+
+QScriptValue FlatListModel::get(int index) const
+{
+ QScriptEngine *scriptEngine = m_scriptEngine ? m_scriptEngine : QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(m_listModel));
+
+ if (!scriptEngine)
+ return 0;
+
+ if (index < 0 || index >= m_values.count())
+ return scriptEngine->undefinedValue();
+
+ FlatListModel *that = const_cast<FlatListModel*>(this);
+ if (!m_scriptClass)
+ that->m_scriptClass = new FlatListScriptClass(that, scriptEngine);
+
+ FlatNodeData *data = m_nodeData.value(index);
+ if (!data) {
+ data = new FlatNodeData(index);
+ that->m_nodeData.replace(index, data);
+ }
+
+ return QScriptDeclarativeClass::newObject(scriptEngine, m_scriptClass, new FlatNodeObjectData(data));
+}
+
+void FlatListModel::set(int index, const QScriptValue &value, QList<int> *roles)
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QHash<int, QVariant> row = m_values[index];
+ if (addValue(value, &row, roles))
+ m_values[index] = row;
+}
+
+void FlatListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QHash<QString, int>::Iterator iter = m_strings.find(property);
+ int role;
+ if (iter == m_strings.end()) {
+ role = m_roles.count();
+ m_roles.insert(role, property);
+ m_strings.insert(property, role);
+ } else {
+ role = iter.value();
+ }
+
+ if (m_values[index][role] != value) {
+ roles->append(role);
+ m_values[index][role] = value;
+ }
+}
+
+void FlatListModel::move(int from, int to, int n)
+{
+ qdeclarativelistmodel_move<QList<QHash<int, QVariant> > >(from, to, n, &m_values);
+ moveNodes(from, to, n);
+}
+
+bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles)
+{
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ QScriptValue value = it.value();
+ if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) {
+ qmlInfo(m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
+ return false;
+ }
+
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = m_strings.find(name);
+ if (iter == m_strings.end()) {
+ int role = m_roles.count();
+ m_roles.insert(role, name);
+ iter = m_strings.insert(name, role);
+ if (roles)
+ roles->append(role);
+ } else {
+ int role = iter.value();
+ if (roles && row->contains(role) && row->value(role) != v)
+ roles->append(role);
+ }
+ row->insert(*iter, v);
+ }
+ return true;
+}
+
+void FlatListModel::insertedNode(int index)
+{
+ if (index >= 0 && index <= m_values.count()) {
+ m_nodeData.insert(index, 0);
+
+ for (int i=index + 1; i<m_nodeData.count(); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+ }
+}
+
+void FlatListModel::removedNode(int index)
+{
+ if (index >= 0 && index < m_nodeData.count()) {
+ delete m_nodeData.takeAt(index);
+
+ for (int i=index; i<m_nodeData.count(); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+ }
+}
+
+void FlatListModel::moveNodes(int from, int to, int n)
+{
+ if (!m_listModel->canMove(from, to, n))
+ return;
+
+ qdeclarativelistmodel_move<QList<FlatNodeData *> >(from, to, n, &m_nodeData);
+
+ for (int i=from; i<from + (to-from); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+}
+
+
+
+FlatNodeData::~FlatNodeData()
+{
+ for (QSet<FlatNodeObjectData *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) {
+ FlatNodeObjectData *data = *iter;
+ data->nodeData = 0;
+ }
+}
+
+void FlatNodeData::addData(FlatNodeObjectData *data)
+{
+ objects.insert(data);
+}
+
+void FlatNodeData::removeData(FlatNodeObjectData *data)
+{
+ objects.remove(data);
+}
+
+
+FlatListScriptClass::FlatListScriptClass(FlatListModel *model, QScriptEngine *seng)
+ : QScriptDeclarativeClass(seng),
+ m_model(model)
+{
+}
+
+QScriptDeclarativeClass::Value FlatListScriptClass::property(Object *obj, const Identifier &name)
+{
+ FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj);
+ if (!objData->nodeData) // item at this index has been deleted
+ return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue());
+
+ int index = objData->nodeData->index;
+ QString propName = toString(name);
+ int role = m_model->m_strings.value(propName, -1);
+
+ if (role >= 0 && index >=0 ) {
+ const QHash<int, QVariant> &row = m_model->m_values[index];
+ QScriptValue sv = engine()->toScriptValue<QVariant>(row[role]);
+ return QScriptDeclarativeClass::Value(engine(), sv);
+ }
+
+ return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue());
+}
+
+void FlatListScriptClass::setProperty(Object *obj, const Identifier &name, const QScriptValue &value)
+{
+ if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) {
+ qmlInfo(m_model->m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
+ return;
+ }
+
+ FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj);
+ if (!objData->nodeData) // item at this index has been deleted
+ return;
+
+ int index = objData->nodeData->index;
+ QString propName = toString(name);
+
+ int role = m_model->m_strings.value(propName, -1);
+ if (role >= 0 && index >= 0) {
+ QHash<int, QVariant> &row = m_model->m_values[index];
+ row[role] = value.toVariant();
+
+ QList<int> roles;
+ roles << role;
+ if (m_model->m_parentAgent) {
+ // This is the list in the worker thread, so tell the agent to
+ // emit itemsChanged() later
+ m_model->m_parentAgent->changedData(index, 1, roles);
+ } else {
+ // This is the list in the main thread, so emit itemsChanged()
+ emit m_model->m_listModel->itemsChanged(index, 1, roles);
+ }
+ }
+}
+
+QScriptClass::QueryFlags FlatListScriptClass::queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags)
+{
+ return (QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess);
+}
+
+bool FlatListScriptClass::compare(Object *obj1, Object *obj2)
+{
+ FlatNodeObjectData *data1 = static_cast<FlatNodeObjectData*>(obj1);
+ FlatNodeObjectData *data2 = static_cast<FlatNodeObjectData*>(obj2);
+
+ if (!data1->nodeData || !data2->nodeData)
+ return false;
+
+ return data1->nodeData->index == data2->nodeData->index;
+}
+
+
+
+NestedListModel::NestedListModel(QDeclarativeListModel *base)
+ : _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false)
+{
+}
+
+NestedListModel::~NestedListModel()
+{
+ if (m_ownsRoot)
+ delete _root;
+}
+
+QVariant NestedListModel::valueForNode(ModelNode *node, bool *hasNested) const
+{
+ QObject *rv = 0;
+ if (hasNested)
+ *hasNested = false;
+
+ if (node->isArray) {
+ // List
+ rv = node->model(this);
+ if (hasNested)
+ *hasNested = true;
+ } else {
+ if (!node->properties.isEmpty()) {
+ // Object
+ rv = node->object(this);
+ } else if (node->values.count() == 0) {
+ // Invalid
+ return QVariant();
+ } else if (node->values.count() == 1) {
+ // Value
+ QVariant &var = node->values[0];
+ ModelNode *valueNode = qvariant_cast<ModelNode *>(var);
+ if (valueNode) {
+ if (!valueNode->properties.isEmpty())
+ rv = valueNode->object(this);
+ else
+ rv = valueNode->model(this);
+ } else {
+ return var;
+ }
+ }
+ }
+
+ if (rv) {
+ return QVariant::fromValue(rv);
+ } else {
+ return QVariant();
+ }
+}
+
+QHash<int,QVariant> NestedListModel::data(int index, const QList<int> &roles, bool *hasNested) const
+{
+ Q_ASSERT(_root && index >= 0 && index < _root->values.count());
+ checkRoles();
+ QHash<int, QVariant> rv;
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return rv;
+
+ for (int ii = 0; ii < roles.count(); ++ii) {
+ const QString &roleString = roleStrings.at(roles.at(ii));
+
+ QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString);
+ if (iter != node->properties.end()) {
+ ModelNode *row = *iter;
+ rv.insert(roles.at(ii), valueForNode(row, hasNested));
+ }
+ }
+
+ return rv;
+}
+
+QVariant NestedListModel::data(int index, int role) const
+{
+ Q_ASSERT(_root && index >= 0 && index < _root->values.count());
+ checkRoles();
+ QVariant rv;
+ if (roleStrings.count() < role)
+ return rv;
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return rv;
+
+ const QString &roleString = roleStrings.at(role);
+
+ QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString);
+ if (iter != node->properties.end()) {
+ ModelNode *row = *iter;
+ rv = valueForNode(row);
+ }
+
+ return rv;
+}
+
+int NestedListModel::count() const
+{
+ if (!_root) return 0;
+ return _root->values.count();
+}
+
+void NestedListModel::clear()
+{
+ if (_root)
+ _root->clear();
+}
+
+void NestedListModel::remove(int index)
+{
+ if (!_root)
+ return;
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ _root->values.removeAt(index);
+ if (node)
+ delete node;
+}
+
+bool NestedListModel::insert(int index, const QScriptValue& valuemap)
+{
+ if (!_root) {
+ _root = new ModelNode(this);
+ m_ownsRoot = true;
+ }
+
+ ModelNode *mn = new ModelNode(this);
+ mn->listIndex = index;
+ mn->setObjectValue(valuemap);
+ _root->values.insert(index,QVariant::fromValue(mn));
+ return true;
+}
+
+void NestedListModel::move(int from, int to, int n)
+{
+ if (!_root)
+ return;
+ qdeclarativelistmodel_move<QVariantList>(from, to, n, &_root->values);
+}
+
+QScriptValue NestedListModel::get(int index) const
+{
+ QDeclarativeEngine *eng = qmlEngine(m_listModel);
+ if (!eng)
+ return 0;
+
+ if (index < 0 || index >= count()) {
+ QScriptEngine *seng = QDeclarativeEnginePrivate::getScriptEngine(eng);
+ if (seng)
+ return seng->undefinedValue();
+ return 0;
+ }
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return 0;
+
+ return QDeclarativeEnginePrivate::qmlScriptObject(node->object(this), eng);
+}
+
+void NestedListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+{
+ Q_ASSERT(index >=0 && index < count());
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ bool emitItemsChanged = node->setObjectValue(valuemap);
+ if (!emitItemsChanged)
+ return;
+
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ int r = roleStrings.indexOf(it.name());
+ if (r < 0) {
+ r = roleStrings.count();
+ roleStrings << it.name();
+ }
+ roles->append(r);
+ }
+}
+
+void NestedListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
+ Q_ASSERT(index >=0 && index < count());
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ bool emitItemsChanged = node->setProperty(property, value);
+ if (!emitItemsChanged)
+ return;
+
+ int r = roleStrings.indexOf(property);
+ if (r < 0) {
+ r = roleStrings.count();
+ roleStrings << property;
+ }
+ roles->append(r);
+}
+
+void NestedListModel::checkRoles() const
+{
+ if (_rolesOk || !_root)
+ return;
+
+ for (int i = 0; i<_root->values.count(); ++i) {
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i));
+ if (node) {
+ foreach (const QString &role, node->properties.keys()) {
+ if (!roleStrings.contains(role))
+ roleStrings.append(role);
+ }
+ }
+ }
+
+ _rolesOk = true;
+}
+
+QList<int> NestedListModel::roles() const
+{
+ checkRoles();
+ QList<int> rv;
+ for (int ii = 0; ii < roleStrings.count(); ++ii)
+ rv << ii;
+ return rv;
+}
+
+QString NestedListModel::toString(int role) const
+{
+ checkRoles();
+ if (role < roleStrings.count())
+ return roleStrings.at(role);
+ else
+ return QString();
+}
+
+
+ModelNode::ModelNode(NestedListModel *model)
+: modelCache(0), objectCache(0), isArray(false), m_model(model), listIndex(-1)
+{
+}
+
+ModelNode::~ModelNode()
+{
+ clear();
+ if (modelCache) { modelCache->m_nested->_root = 0/* ==this */; delete modelCache; modelCache = 0; }
+ if (objectCache) { delete objectCache; objectCache = 0; }
+}
+
+void ModelNode::clear()
+{
+ ModelNode *node;
+ for (int ii = 0; ii < values.count(); ++ii) {
+ node = qvariant_cast<ModelNode *>(values.at(ii));
+ if (node) { delete node; node = 0; }
+ }
+ values.clear();
+
+ qDeleteAll(properties.values());
+ properties.clear();
+}
+
+bool ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache)
+{
+ bool emitItemsChanged = false;
+
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ ModelNode *prev = properties.value(it.name());
+ ModelNode *value = new ModelNode(m_model);
+ QScriptValue v = it.value();
+
+ if (v.isArray()) {
+ value->isArray = true;
+ value->setListValue(v);
+ if (writeToCache && objectCache)
+ objectCache->setValue(it.name().toUtf8(), QVariant::fromValue(value->model(m_model)));
+ emitItemsChanged = true; // for now, too inefficient to check whether list and sublists have changed
+ } else {
+ value->values << v.toVariant();
+ if (writeToCache && objectCache)
+ objectCache->setValue(it.name().toUtf8(), value->values.last());
+ if (!emitItemsChanged && prev && prev->values.count() == 1
+ && prev->values[0] != value->values.last()) {
+ emitItemsChanged = true;
+ }
+ }
+ if (properties.contains(it.name()))
+ delete properties[it.name()];
+ properties.insert(it.name(), value);
+ }
+ return emitItemsChanged;
+}
+
+void ModelNode::setListValue(const QScriptValue& valuelist) {
+ values.clear();
+ int size = valuelist.property(QLatin1String("length")).toInt32();
+ for (int i=0; i<size; i++) {
+ ModelNode *value = new ModelNode(m_model);
+ QScriptValue v = valuelist.property(i);
+ if (v.isArray()) {
+ value->isArray = true;
+ value->setListValue(v);
+ } else if (v.isObject()) {
+ value->listIndex = i;
+ value->setObjectValue(v);
+ } else {
+ value->listIndex = i;
+ value->values << v.toVariant();
+ }
+ values.append(QVariant::fromValue(value));
+ }
+}
+
+bool ModelNode::setProperty(const QString& prop, const QVariant& val) {
+ QHash<QString, ModelNode *>::const_iterator it = properties.find(prop);
+ bool emitItemsChanged = false;
+ if (it != properties.end()) {
+ if (val != (*it)->values[0])
+ emitItemsChanged = true;
+ (*it)->values[0] = val;
+ } else {
+ ModelNode *n = new ModelNode(m_model);
+ n->values << val;
+ properties.insert(prop,n);
+ }
+ if (objectCache)
+ objectCache->setValue(prop.toUtf8(), val);
+ return emitItemsChanged;
+}
+
+void ModelNode::updateListIndexes()
+{
+ for (QHash<QString, ModelNode *>::ConstIterator iter = properties.begin(); iter != properties.end(); ++iter) {
+ ModelNode *node = iter.value();
+ if (node->isArray) {
+ for (int i=0; i<node->values.count(); ++i) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(i));
+ if (subNode)
+ subNode->listIndex = i;
+ }
+ }
+ node->updateListIndexes();
+ }
+}
+
+/*
+ Need to call this to emit itemsChanged() for modifications outside of set()
+ and setProperty(), i.e. if an item returned from get() is modified
+*/
+void ModelNode::changedProperty(const QString &name) const
+{
+ if (listIndex < 0)
+ return;
+
+ m_model->checkRoles();
+ QList<int> roles;
+ int role = m_model->roleStrings.indexOf(name);
+ if (role < 0)
+ roles = m_model->roles();
+ else
+ roles << role;
+ emit m_model->m_listModel->itemsChanged(listIndex, 1, roles);
+}
+
+void ModelNode::dump(ModelNode *node, int ind)
+{
+ QByteArray indentBa(ind * 4, ' ');
+ const char *indent = indentBa.constData();
+
+ for (int ii = 0; ii < node->values.count(); ++ii) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(ii));
+ if (subNode) {
+ qWarning().nospace() << indent << "Sub-node " << ii;
+ dump(subNode, ind + 1);
+ } else {
+ qWarning().nospace() << indent << "Sub-node " << ii << ": " << node->values.at(ii).toString();
+ }
+ }
+
+ for (QHash<QString, ModelNode *>::ConstIterator iter = node->properties.begin(); iter != node->properties.end(); ++iter) {
+ qWarning().nospace() << indent << "Property " << iter.key() << ':';
+ dump(iter.value(), ind + 1);
+ }
+}
+
+ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng)
+ : m_model(model),
+ m_node(node),
+ m_meta(new ModelNodeMetaObject(seng, this))
+{
+}
+
+void ModelObject::setValue(const QByteArray &name, const QVariant &val)
+{
+ m_meta->setValue(name, val);
+ //setProperty(name.constData(), val);
+}
+
+void ModelObject::setNodeUpdatesEnabled(bool enable)
+{
+ m_meta->m_enabled = enable;
+}
+
+
+ModelNodeMetaObject::ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object)
+ : QDeclarativeOpenMetaObject(object),
+ m_enabled(false),
+ m_seng(seng),
+ m_obj(object)
+{
+}
+
+void ModelNodeMetaObject::propertyWritten(int index)
+{
+ if (!m_enabled)
+ return;
+
+ QString propName = QString::fromUtf8(name(index));
+ QVariant value = operator[](index);
+
+ QScriptValue sv = m_seng->newObject();
+ sv.setProperty(propName, m_seng->newVariant(value));
+ bool changed = m_obj->m_node->setObjectValue(sv, false);
+ if (changed)
+ m_obj->m_node->changedProperty(propName);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h
new file mode 100644
index 0000000000..7870b4f5fa
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodel_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVELISTMODEL_H
+#define QDECLARATIVELISTMODEL_H
+
+#include <qdeclarative.h>
+#include <private/qdeclarativecustomparser_p.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include <private/qlistmodelinterface_p.h>
+#include <QtScript/qscriptvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class FlatListModel;
+class NestedListModel;
+class QDeclarativeListModelWorkerAgent;
+struct ModelNode;
+class FlatListScriptClass;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeListModel : public QListModelInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+public:
+ QDeclarativeListModel(QObject *parent=0);
+ ~QDeclarativeListModel();
+
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+ virtual int count() const;
+ virtual QVariant data(int index, int role) const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QScriptValue&);
+ Q_INVOKABLE void insert(int index, const QScriptValue&);
+ Q_INVOKABLE QScriptValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QScriptValue&);
+ Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ QDeclarativeListModelWorkerAgent *agent();
+
+Q_SIGNALS:
+ void countChanged();
+
+private:
+ friend class QDeclarativeListModelParser;
+ friend class QDeclarativeListModelWorkerAgent;
+ friend class FlatListModel;
+ friend class FlatListScriptClass;
+ friend struct ModelNode;
+
+ // Constructs a flat list model for a worker agent
+ QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent);
+
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
+
+ bool flatten();
+ bool inWorkerThread() const;
+
+ inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
+
+ QDeclarativeListModelWorkerAgent *m_agent;
+ NestedListModel *m_nested;
+ FlatListModel *m_flat;
+};
+
+// ### FIXME
+class QDeclarativeListElement : public QObject
+{
+Q_OBJECT
+};
+
+class QDeclarativeListModelParser : public QDeclarativeCustomParser
+{
+public:
+ QByteArray compile(const QList<QDeclarativeCustomParserProperty> &);
+ void setCustomData(QObject *, const QByteArray &);
+
+private:
+ struct ListInstruction
+ {
+ enum { Push, Pop, Value, Set } type;
+ int dataIdx;
+ };
+ struct ListModelData
+ {
+ int dataOffset;
+ int instrCount;
+ ListInstruction *instructions() const;
+ };
+ bool compileProperty(const QDeclarativeCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data);
+
+ bool definesEmptyList(const QString &);
+
+ QByteArray listElementTypeName;
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeListModel)
+QML_DECLARE_TYPE(QDeclarativeListElement)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELISTMODEL_H
diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h
new file mode 100644
index 0000000000..7236e8b1be
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodel_p_p.h
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVELISTMODEL_P_P_H
+#define QDECLARATIVELISTMODEL_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/qdeclarativelistmodel_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeopenmetaobject_p.h"
+#include "qdeclarative.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeOpenMetaObject;
+class QScriptEngine;
+class QDeclarativeListModelWorkerAgent;
+struct ModelNode;
+class FlatListScriptClass;
+class FlatNodeData;
+
+class FlatListModel
+{
+public:
+ FlatListModel(QDeclarativeListModel *base);
+ ~FlatListModel();
+
+ QVariant data(int index, int role) const;
+
+ QList<int> roles() const;
+ QString toString(int role) const;
+
+ int count() const;
+ void clear();
+ void remove(int index);
+ bool insert(int index, const QScriptValue&);
+ QScriptValue get(int index) const;
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
+ void move(int from, int to, int count);
+
+private:
+ friend class QDeclarativeListModelWorkerAgent;
+ friend class QDeclarativeListModel;
+ friend class FlatListScriptClass;
+ friend class FlatNodeData;
+
+ bool addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles);
+ void insertedNode(int index);
+ void removedNode(int index);
+ void moveNodes(int from, int to, int n);
+
+ QScriptEngine *m_scriptEngine;
+ QHash<int, QString> m_roles;
+ QHash<QString, int> m_strings;
+ QList<QHash<int, QVariant> > m_values;
+ QDeclarativeListModel *m_listModel;
+
+ FlatListScriptClass *m_scriptClass;
+ QList<FlatNodeData *> m_nodeData;
+ QDeclarativeListModelWorkerAgent *m_parentAgent;
+};
+
+
+/*
+ Created when get() is called on a FlatListModel. This allows changes to the
+ object returned by get() to be tracked, and passed onto the model.
+*/
+class FlatListScriptClass : public QScriptDeclarativeClass
+{
+public:
+ FlatListScriptClass(FlatListModel *model, QScriptEngine *seng);
+
+ Value property(Object *, const Identifier &);
+ void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags);
+ bool compare(Object *, Object *);
+
+private:
+ FlatListModel *m_model;
+};
+
+/*
+ FlatNodeData and FlatNodeObjectData allow objects returned by get() to still
+ point to the correct list index if move(), insert() or remove() are called.
+*/
+struct FlatNodeObjectData;
+class FlatNodeData
+{
+public:
+ FlatNodeData(int i)
+ : index(i) {}
+
+ ~FlatNodeData();
+
+ void addData(FlatNodeObjectData *data);
+ void removeData(FlatNodeObjectData *data);
+
+ int index;
+
+private:
+ QSet<FlatNodeObjectData*> objects;
+};
+
+struct FlatNodeObjectData : public QScriptDeclarativeClass::Object
+{
+ FlatNodeObjectData(FlatNodeData *data) : nodeData(data) {
+ nodeData->addData(this);
+ }
+
+ ~FlatNodeObjectData() {
+ if (nodeData)
+ nodeData->removeData(this);
+ }
+
+ FlatNodeData *nodeData;
+};
+
+
+
+class NestedListModel
+{
+public:
+ NestedListModel(QDeclarativeListModel *base);
+ ~NestedListModel();
+
+ QHash<int,QVariant> data(int index, const QList<int> &roles, bool *hasNested = 0) const;
+ QVariant data(int index, int role) const;
+
+ QList<int> roles() const;
+ QString toString(int role) const;
+
+ int count() const;
+ void clear();
+ void remove(int index);
+ bool insert(int index, const QScriptValue&);
+ QScriptValue get(int index) const;
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
+ void move(int from, int to, int count);
+
+ QVariant valueForNode(ModelNode *, bool *hasNested = 0) const;
+ void checkRoles() const;
+
+ ModelNode *_root;
+ bool m_ownsRoot;
+ QDeclarativeListModel *m_listModel;
+
+private:
+ friend struct ModelNode;
+ mutable QStringList roleStrings;
+ mutable bool _rolesOk;
+};
+
+
+class ModelNodeMetaObject;
+class ModelObject : public QObject
+{
+ Q_OBJECT
+public:
+ ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng);
+ void setValue(const QByteArray &name, const QVariant &val);
+ void setNodeUpdatesEnabled(bool enable);
+
+ NestedListModel *m_model;
+ ModelNode *m_node;
+
+private:
+ ModelNodeMetaObject *m_meta;
+};
+
+class ModelNodeMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object);
+
+ bool m_enabled;
+
+protected:
+ void propertyWritten(int index);
+
+private:
+ QScriptEngine *m_seng;
+ ModelObject *m_obj;
+};
+
+
+/*
+ A ModelNode is created for each item in a NestedListModel.
+*/
+struct ModelNode
+{
+ ModelNode(NestedListModel *model);
+ ~ModelNode();
+
+ QList<QVariant> values;
+ QHash<QString, ModelNode *> properties;
+
+ void clear();
+
+ QDeclarativeListModel *model(const NestedListModel *model);
+ ModelObject *object(const NestedListModel *model);
+
+ bool setObjectValue(const QScriptValue& valuemap, bool writeToCache = true);
+ void setListValue(const QScriptValue& valuelist);
+ bool setProperty(const QString& prop, const QVariant& val);
+ void changedProperty(const QString &name) const;
+ void updateListIndexes();
+ static void dump(ModelNode *node, int ind);
+
+ QDeclarativeListModel *modelCache;
+ ModelObject *objectCache;
+ bool isArray;
+
+ NestedListModel *m_model;
+ int listIndex; // only used for top-level nodes within a list
+};
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(ModelNode *)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELISTMODEL_P_P_H
+
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
new file mode 100644
index 0000000000..befa8ebb5a
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativelistmodelworkeragent_p.h"
+#include "private/qdeclarativelistmodel_p_p.h"
+#include "private/qdeclarativedata_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "qdeclarativeinfo.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+void QDeclarativeListModelWorkerAgent::Data::clearChange()
+{
+ changes.clear();
+}
+
+void QDeclarativeListModelWorkerAgent::Data::insertChange(int index, int count)
+{
+ Change c = { Change::Inserted, index, count, 0, QList<int>() };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::removeChange(int index, int count)
+{
+ Change c = { Change::Removed, index, count, 0, QList<int>() };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::moveChange(int index, int count, int to)
+{
+ Change c = { Change::Moved, index, count, to, QList<int>() };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count, const QList<int> &roles)
+{
+ Change c = { Change::Changed, index, count, 0, roles };
+ changes << c;
+}
+
+QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model)
+ : m_engine(0),
+ m_ref(1),
+ m_orig(model),
+ m_copy(new QDeclarativeListModel(model, this))
+{
+}
+
+QDeclarativeListModelWorkerAgent::~QDeclarativeListModelWorkerAgent()
+{
+}
+
+void QDeclarativeListModelWorkerAgent::setScriptEngine(QScriptEngine *eng)
+{
+ m_engine = eng;
+ if (m_copy->m_flat)
+ m_copy->m_flat->m_scriptEngine = eng;
+}
+
+QScriptEngine *QDeclarativeListModelWorkerAgent::scriptEngine() const
+{
+ return m_engine;
+}
+
+void QDeclarativeListModelWorkerAgent::addref()
+{
+ m_ref.ref();
+}
+
+void QDeclarativeListModelWorkerAgent::release()
+{
+ bool del = !m_ref.deref();
+
+ if (del)
+ delete this;
+}
+
+int QDeclarativeListModelWorkerAgent::count() const
+{
+ return m_copy->count();
+}
+
+void QDeclarativeListModelWorkerAgent::clear()
+{
+ data.clearChange();
+ data.removeChange(0, m_copy->count());
+ m_copy->clear();
+}
+
+void QDeclarativeListModelWorkerAgent::remove(int index)
+{
+ int count = m_copy->count();
+ m_copy->remove(index);
+
+ if (m_copy->count() != count)
+ data.removeChange(index, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::append(const QScriptValue &value)
+{
+ int count = m_copy->count();
+ m_copy->append(value);
+
+ if (m_copy->count() != count)
+ data.insertChange(m_copy->count() - 1, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::insert(int index, const QScriptValue &value)
+{
+ int count = m_copy->count();
+ m_copy->insert(index, value);
+
+ if (m_copy->count() != count)
+ data.insertChange(index, 1);
+}
+
+QScriptValue QDeclarativeListModelWorkerAgent::get(int index) const
+{
+ return m_copy->get(index);
+}
+
+void QDeclarativeListModelWorkerAgent::set(int index, const QScriptValue &value)
+{
+ QList<int> roles;
+ m_copy->set(index, value, &roles);
+ if (!roles.isEmpty())
+ data.changedChange(index, 1, roles);
+}
+
+void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
+{
+ QList<int> roles;
+ m_copy->setProperty(index, property, value, &roles);
+ if (!roles.isEmpty())
+ data.changedChange(index, 1, roles);
+}
+
+void QDeclarativeListModelWorkerAgent::move(int from, int to, int count)
+{
+ m_copy->move(from, to, count);
+ data.moveChange(from, to, count);
+}
+
+void QDeclarativeListModelWorkerAgent::sync()
+{
+ Sync *s = new Sync;
+ s->data = data;
+ s->list = m_copy;
+ data.changes.clear();
+
+ mutex.lock();
+ QCoreApplication::postEvent(this, s);
+ syncDone.wait(&mutex);
+ mutex.unlock();
+}
+
+void QDeclarativeListModelWorkerAgent::changedData(int index, int count, const QList<int> &roles)
+{
+ data.changedChange(index, count, roles);
+}
+
+bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ QMutexLocker locker(&mutex);
+ Sync *s = static_cast<Sync *>(e);
+
+ const QList<Change> &changes = s->data.changes;
+
+ if (m_copy) {
+ bool cc = m_orig->count() != s->list->count();
+
+ FlatListModel *orig = m_orig->m_flat;
+ FlatListModel *copy = s->list->m_flat;
+ if (!orig || !copy) {
+ syncDone.wakeAll();
+ return QObject::event(e);
+ }
+
+ orig->m_roles = copy->m_roles;
+ orig->m_strings = copy->m_strings;
+ orig->m_values = copy->m_values;
+
+ // update the orig->m_nodeData list
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+ switch (change.type) {
+ case Change::Inserted:
+ orig->insertedNode(change.index);
+ break;
+ case Change::Removed:
+ orig->removedNode(change.index);
+ break;
+ case Change::Moved:
+ orig->moveNodes(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ break;
+ }
+ }
+
+ syncDone.wakeAll();
+ locker.unlock();
+
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+ switch (change.type) {
+ case Change::Inserted:
+ emit m_orig->itemsInserted(change.index, change.count);
+ break;
+ case Change::Removed:
+ emit m_orig->itemsRemoved(change.index, change.count);
+ break;
+ case Change::Moved:
+ emit m_orig->itemsMoved(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ emit m_orig->itemsChanged(change.index, change.count, change.roles);
+ break;
+ }
+ }
+
+ if (cc)
+ emit m_orig->countChanged();
+ } else {
+ syncDone.wakeAll();
+ }
+ }
+
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
new file mode 100644
index 0000000000..4c800e9ad0
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent_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 QDECLARATIVELISTMODELWORKERAGENT_P_H
+#define QDECLARATIVELISTMODELWORKERAGENT_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 <QtScript/qscriptvalue.h>
+#include <QtGui/qevent.h>
+#include <QMutex>
+#include <QWaitCondition>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeListModel;
+class FlatListScriptClass;
+
+class QDeclarativeListModelWorkerAgent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count)
+
+public:
+ QDeclarativeListModelWorkerAgent(QDeclarativeListModel *);
+ ~QDeclarativeListModelWorkerAgent();
+
+ void setScriptEngine(QScriptEngine *eng);
+ QScriptEngine *scriptEngine() const;
+
+ void addref();
+ void release();
+
+ int count() const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QScriptValue &);
+ Q_INVOKABLE void insert(int index, const QScriptValue&);
+ Q_INVOKABLE QScriptValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QScriptValue &);
+ Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ struct VariantRef
+ {
+ VariantRef() : a(0) {}
+ VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
+ VariantRef(QDeclarativeListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
+ ~VariantRef() { if (a) a->release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ if (o.a) o.a->addref();
+ if (a) a->release(); a = o.a;
+ return *this;
+ }
+
+ QDeclarativeListModelWorkerAgent *a;
+ };
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ friend class QDeclarativeWorkerScriptEnginePrivate;
+ friend class FlatListScriptClass;
+ QScriptEngine *m_engine;
+
+ struct Change {
+ enum { Inserted, Removed, Moved, Changed } type;
+ int index; // Inserted/Removed/Moved/Changed
+ int count; // Inserted/Removed/Moved/Changed
+ int to; // Moved
+ QList<int> roles;
+ };
+
+ struct Data {
+ QList<Change> changes;
+
+ void clearChange();
+ void insertChange(int index, int count);
+ void removeChange(int index, int count);
+ void moveChange(int index, int count, int to);
+ void changedChange(int index, int count, const QList<int> &roles);
+ };
+ Data data;
+
+ struct Sync : public QEvent {
+ Sync() : QEvent(QEvent::User) {}
+ Data data;
+ QDeclarativeListModel *list;
+ };
+
+ void changedData(int index, int count, const QList<int> &roles);
+
+ QAtomicInt m_ref;
+ QDeclarativeListModel *m_orig;
+ QDeclarativeListModel *m_copy;
+ QMutex mutex;
+ QWaitCondition syncDone;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeListModelWorkerAgent::VariantRef)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEWORKERSCRIPT_P_H
+
diff --git a/src/declarative/util/qdeclarativenullablevalue_p_p.h b/src/declarative/util/qdeclarativenullablevalue_p_p.h
new file mode 100644
index 0000000000..6d5e878305
--- /dev/null
+++ b/src/declarative/util/qdeclarativenullablevalue_p_p.h
@@ -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 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 QDECLARATIVENULLABLEVALUE_P_H
+#define QDECLARATIVENULLABLEVALUE_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+struct QDeclarativeNullableValue
+{
+ QDeclarativeNullableValue()
+ : isNull(true), value(T()) {}
+ QDeclarativeNullableValue(const QDeclarativeNullableValue<T> &o)
+ : isNull(o.isNull), value(o.value) {}
+ QDeclarativeNullableValue(const T &t)
+ : isNull(false), value(t) {}
+ QDeclarativeNullableValue<T> &operator=(const T &t)
+ { isNull = false; value = t; return *this; }
+ QDeclarativeNullableValue<T> &operator=(const QDeclarativeNullableValue<T> &o)
+ { isNull = o.isNull; value = o.value; return *this; }
+ operator T() const { return value; }
+
+ void invalidate() { isNull = true; }
+ bool isValid() const { return !isNull; }
+ bool isNull;
+ T value;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVENULLABLEVALUE_P_H
diff --git a/src/declarative/util/qdeclarativeopenmetaobject.cpp b/src/declarative/util/qdeclarativeopenmetaobject.cpp
new file mode 100644
index 0000000000..8a8d05e222
--- /dev/null
+++ b/src/declarative/util/qdeclarativeopenmetaobject.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativeopenmetaobject_p.h"
+#include "private/qdeclarativepropertycache_p.h"
+#include "private/qdeclarativedata_p.h"
+#include <qmetaobjectbuilder_p.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QDeclarativeOpenMetaObjectTypePrivate
+{
+public:
+ QDeclarativeOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {}
+
+ void init(const QMetaObject *metaObj);
+
+ int propertyOffset;
+ int signalOffset;
+ QHash<QByteArray, int> names;
+ QMetaObjectBuilder mob;
+ QMetaObject *mem;
+ QDeclarativePropertyCache *cache;
+ QDeclarativeEngine *engine;
+ QSet<QDeclarativeOpenMetaObject*> referers;
+};
+
+QDeclarativeOpenMetaObjectType::QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine)
+ : d(new QDeclarativeOpenMetaObjectTypePrivate)
+{
+ d->engine = engine;
+ d->init(base);
+}
+
+QDeclarativeOpenMetaObjectType::~QDeclarativeOpenMetaObjectType()
+{
+ if (d->mem)
+ qFree(d->mem);
+ if (d->cache)
+ d->cache->release();
+ delete d;
+}
+
+
+int QDeclarativeOpenMetaObjectType::propertyOffset() const
+{
+ return d->propertyOffset;
+}
+
+int QDeclarativeOpenMetaObjectType::signalOffset() const
+{
+ return d->signalOffset;
+}
+
+int QDeclarativeOpenMetaObjectType::createProperty(const QByteArray &name)
+{
+ int id = d->mob.propertyCount();
+ d->mob.addSignal("__" + QByteArray::number(id) + "()");
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
+ propertyCreated(id, build);
+ qFree(d->mem);
+ d->mem = d->mob.toMetaObject();
+ d->names.insert(name, id);
+ QSet<QDeclarativeOpenMetaObject*>::iterator it = d->referers.begin();
+ while (it != d->referers.end()) {
+ QDeclarativeOpenMetaObject *omo = *it;
+ *static_cast<QMetaObject *>(omo) = *d->mem;
+ if (d->cache)
+ d->cache->update(d->engine, omo);
+ ++it;
+ }
+
+ return d->propertyOffset + id;
+}
+
+void QDeclarativeOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
+{
+ if (d->referers.count())
+ (*d->referers.begin())->propertyCreated(id, builder);
+}
+
+void QDeclarativeOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
+{
+ if (!mem) {
+ mob.setSuperClass(metaObj);
+ mob.setClassName(metaObj->className());
+ mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ mem = mob.toMetaObject();
+
+ propertyOffset = mem->propertyOffset();
+ signalOffset = mem->methodOffset();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+class QDeclarativeOpenMetaObjectPrivate
+{
+public:
+ QDeclarativeOpenMetaObjectPrivate(QDeclarativeOpenMetaObject *_q)
+ : q(_q), parent(0), type(0), cacheProperties(false) {}
+
+ inline QVariant &getData(int idx) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ if (!prop.second) {
+ prop.first = q->initialValue(idx);
+ prop.second = true;
+ }
+ return prop.first;
+ }
+
+ inline void writeData(int idx, const QVariant &value) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ prop.first = value;
+ prop.second = true;
+ }
+
+ inline bool hasData(int idx) const {
+ if (idx >= data.count())
+ return false;
+ return data[idx].second;
+ }
+
+ bool autoCreate;
+ QDeclarativeOpenMetaObject *q;
+ QAbstractDynamicMetaObject *parent;
+ QList<QPair<QVariant, bool> > data;
+ QObject *object;
+ QDeclarativeOpenMetaObjectType *type;
+ bool cacheProperties;
+};
+
+QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, bool automatic)
+: d(new QDeclarativeOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = new QDeclarativeOpenMetaObjectType(obj->metaObject(), 0);
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QDeclarativeOpenMetaObject::QDeclarativeOpenMetaObject(QObject *obj, QDeclarativeOpenMetaObjectType *type, bool automatic)
+: d(new QDeclarativeOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = type;
+ d->type->addref();
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QDeclarativeOpenMetaObject::~QDeclarativeOpenMetaObject()
+{
+ if (d->parent)
+ delete d->parent;
+ d->type->d->referers.remove(this);
+ d->type->release();
+ delete d;
+}
+
+QDeclarativeOpenMetaObjectType *QDeclarativeOpenMetaObject::type() const
+{
+ return d->type;
+}
+
+int QDeclarativeOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty)
+ && id >= d->type->d->propertyOffset) {
+ int propId = id - d->type->d->propertyOffset;
+ if (c == QMetaObject::ReadProperty) {
+ propertyRead(propId);
+ *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId);
+ } else if (c == QMetaObject::WriteProperty) {
+ if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
+ propertyWrite(propId);
+ d->writeData(propId, *reinterpret_cast<QVariant *>(a[0]));
+ propertyWritten(propId);
+ activate(d->object, d->type->d->signalOffset + propId, 0);
+ }
+ }
+ return -1;
+ } else {
+ if (d->parent)
+ return d->parent->metaCall(c, id, a);
+ else
+ return d->object->qt_metacall(c, id, a);
+ }
+}
+
+QAbstractDynamicMetaObject *QDeclarativeOpenMetaObject::parent() const
+{
+ return d->parent;
+}
+
+QVariant QDeclarativeOpenMetaObject::value(int id) const
+{
+ return d->getData(id);
+}
+
+void QDeclarativeOpenMetaObject::setValue(int id, const QVariant &value)
+{
+ d->writeData(id, value);
+ activate(d->object, id + d->type->d->signalOffset, 0);
+}
+
+QVariant QDeclarativeOpenMetaObject::value(const QByteArray &name) const
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ if (iter == d->type->d->names.end())
+ return QVariant();
+
+ return d->getData(*iter);
+}
+
+QVariant &QDeclarativeOpenMetaObject::operator[](const QByteArray &name)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ Q_ASSERT(iter != d->type->d->names.end());
+
+ return d->getData(*iter);
+}
+
+QVariant &QDeclarativeOpenMetaObject::operator[](int id)
+{
+ return d->getData(id);
+}
+
+void QDeclarativeOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+
+ int id = -1;
+ if (iter == d->type->d->names.end()) {
+ id = createProperty(name.constData(), "") - d->type->d->propertyOffset;
+ } else {
+ id = *iter;
+ }
+
+ if (id >= 0) {
+ QVariant &dataVal = d->getData(id);
+ if (dataVal == val)
+ return;
+
+ dataVal = val;
+ activate(d->object, id + d->type->d->signalOffset, 0);
+ }
+}
+
+// returns true if this value has been initialized by a call to either value() or setValue()
+bool QDeclarativeOpenMetaObject::hasValue(int id) const
+{
+ return d->hasData(id);
+}
+
+void QDeclarativeOpenMetaObject::setCached(bool c)
+{
+ if (c == d->cacheProperties || !d->type->d->engine)
+ return;
+
+ d->cacheProperties = c;
+
+ QDeclarativeData *qmldata = QDeclarativeData::get(d->object, true);
+ if (d->cacheProperties) {
+ if (!d->type->d->cache)
+ d->type->d->cache = new QDeclarativePropertyCache(d->type->d->engine, this);
+ qmldata->propertyCache = d->type->d->cache;
+ d->type->d->cache->addref();
+ } else {
+ if (d->type->d->cache)
+ d->type->d->cache->release();
+ qmldata->propertyCache = 0;
+ }
+}
+
+
+int QDeclarativeOpenMetaObject::createProperty(const char *name, const char *)
+{
+ if (d->autoCreate)
+ return d->type->createProperty(name);
+ else
+ return -1;
+}
+
+void QDeclarativeOpenMetaObject::propertyRead(int)
+{
+}
+
+void QDeclarativeOpenMetaObject::propertyWrite(int)
+{
+}
+
+void QDeclarativeOpenMetaObject::propertyWritten(int)
+{
+}
+
+void QDeclarativeOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &)
+{
+}
+
+QVariant QDeclarativeOpenMetaObject::initialValue(int)
+{
+ return QVariant();
+}
+
+int QDeclarativeOpenMetaObject::count() const
+{
+ return d->type->d->names.count();
+}
+
+QByteArray QDeclarativeOpenMetaObject::name(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+
+ return d->type->d->mob.property(idx).name();
+}
+
+QObject *QDeclarativeOpenMetaObject::object() const
+{
+ return d->object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeopenmetaobject_p.h b/src/declarative/util/qdeclarativeopenmetaobject_p.h
new file mode 100644
index 0000000000..f364177e5f
--- /dev/null
+++ b/src/declarative/util/qdeclarativeopenmetaobject_p.h
@@ -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 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 QDECLARATIVEOPENMETAOBJECT_H
+#define QDECLARATIVEOPENMETAOBJECT_H
+
+#include <QtCore/QMetaObject>
+#include <QtCore/QObject>
+
+#include <private/qdeclarativerefcount_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class QMetaPropertyBuilder;
+class QDeclarativeOpenMetaObjectTypePrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObjectType : public QDeclarativeRefCount
+{
+public:
+ QDeclarativeOpenMetaObjectType(const QMetaObject *base, QDeclarativeEngine *engine);
+ ~QDeclarativeOpenMetaObjectType();
+
+ int createProperty(const QByteArray &name);
+
+ int propertyOffset() const;
+ int signalOffset() const;
+
+protected:
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+private:
+ QDeclarativeOpenMetaObjectTypePrivate *d;
+ friend class QDeclarativeOpenMetaObject;
+ friend class QDeclarativeOpenMetaObjectPrivate;
+};
+
+class QDeclarativeOpenMetaObjectPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeOpenMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QDeclarativeOpenMetaObject(QObject *, bool = true);
+ QDeclarativeOpenMetaObject(QObject *, QDeclarativeOpenMetaObjectType *, bool = true);
+ ~QDeclarativeOpenMetaObject();
+
+ QVariant value(const QByteArray &) const;
+ void setValue(const QByteArray &, const QVariant &);
+ QVariant value(int) const;
+ void setValue(int, const QVariant &);
+ QVariant &operator[](const QByteArray &);
+ QVariant &operator[](int);
+ bool hasValue(int) const;
+
+ int count() const;
+ QByteArray name(int) const;
+
+ QObject *object() const;
+ virtual QVariant initialValue(int);
+
+ // Be careful - once setCached(true) is called createProperty() is no
+ // longer automatically called for new properties.
+ void setCached(bool);
+
+ QDeclarativeOpenMetaObjectType *type() const;
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+ virtual int createProperty(const char *, const char *);
+
+ virtual void propertyRead(int);
+ virtual void propertyWrite(int);
+ virtual void propertyWritten(int);
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+ QAbstractDynamicMetaObject *parent() const;
+
+private:
+ QDeclarativeOpenMetaObjectPrivate *d;
+ friend class QDeclarativeOpenMetaObjectType;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEOPENMETAOBJECT_H
diff --git a/src/declarative/util/qdeclarativepackage.cpp b/src/declarative/util/qdeclarativepackage.cpp
new file mode 100644
index 0000000000..530201763c
--- /dev/null
+++ b/src/declarative/util/qdeclarativepackage.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepackage_p.h"
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Package QDeclarativePackage
+ \ingroup qml-working-with-data
+ \brief Package provides a collection of named items.
+
+ The Package class is used in conjunction with
+ VisualDataModel to enable delegates with a shared context
+ to be provided to multiple views.
+
+ Any item within a Package may be assigned a name via the
+ \l{Package::name}{Package.name} attached property.
+
+ The example below creates a Package containing two named items;
+ \e list and \e grid. The third element in the package (the \l Rectangle) is parented to whichever
+ delegate it should appear in. This allows an item to move
+ between views.
+
+ \snippet examples/declarative/modelviews/package/Delegate.qml 0
+
+ These named items are used as the delegates by the two views who
+ reference the special \l{VisualDataModel::parts} property to select
+ a model which provides the chosen delegate.
+
+ \snippet examples/declarative/modelviews/package/view.qml 0
+
+ \sa {declarative/modelviews/package}{Package example}, {demos/declarative/photoviewer}{Photo Viewer demo}, QtDeclarative
+*/
+
+/*!
+ \qmlattachedproperty string Package::name
+ This attached property holds the name of an item within a Package.
+*/
+
+
+class QDeclarativePackagePrivate : public QObjectPrivate
+{
+public:
+ QDeclarativePackagePrivate() {}
+
+ struct DataGuard : public QDeclarativeGuard<QObject>
+ {
+ DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QDeclarativeGuard<QObject>&)*this = obj; }
+ QList<DataGuard> *list;
+ void objectDestroyed(QObject *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+
+ QList<DataGuard> dataList;
+ static void data_append(QDeclarativeListProperty<QObject> *prop, QObject *o) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->append(DataGuard(o, list));
+ }
+ static void data_clear(QDeclarativeListProperty<QObject> *prop) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->clear();
+ }
+ static QObject *data_at(QDeclarativeListProperty<QObject> *prop, int index) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ return list->at(index);
+ }
+ static int data_count(QDeclarativeListProperty<QObject> *prop) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ return list->count();
+ }
+};
+
+QHash<QObject *, QDeclarativePackageAttached *> QDeclarativePackageAttached::attached;
+
+QDeclarativePackageAttached::QDeclarativePackageAttached(QObject *parent)
+: QObject(parent)
+{
+ attached.insert(parent, this);
+}
+
+QDeclarativePackageAttached::~QDeclarativePackageAttached()
+{
+ attached.remove(parent());
+}
+
+QString QDeclarativePackageAttached::name() const
+{
+ return _name;
+}
+
+void QDeclarativePackageAttached::setName(const QString &n)
+{
+ _name = n;
+}
+
+QDeclarativePackage::QDeclarativePackage(QObject *parent)
+ : QObject(*(new QDeclarativePackagePrivate), parent)
+{
+}
+
+QDeclarativePackage::~QDeclarativePackage()
+{
+ Q_D(QDeclarativePackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ obj->setParent(this);
+ }
+}
+
+QDeclarativeListProperty<QObject> QDeclarativePackage::data()
+{
+ Q_D(QDeclarativePackage);
+ return QDeclarativeListProperty<QObject>(this, &d->dataList, QDeclarativePackagePrivate::data_append,
+ QDeclarativePackagePrivate::data_count,
+ QDeclarativePackagePrivate::data_at,
+ QDeclarativePackagePrivate::data_clear);
+}
+
+bool QDeclarativePackage::hasPart(const QString &name)
+{
+ Q_D(QDeclarativePackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ QDeclarativePackageAttached *a = QDeclarativePackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return true;
+ }
+ return false;
+}
+
+QObject *QDeclarativePackage::part(const QString &name)
+{
+ Q_D(QDeclarativePackage);
+ if (name.isEmpty() && !d->dataList.isEmpty())
+ return d->dataList.at(0);
+
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ QDeclarativePackageAttached *a = QDeclarativePackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return obj;
+ }
+
+ if (name == QLatin1String("default") && !d->dataList.isEmpty())
+ return d->dataList.at(0);
+
+ return 0;
+}
+
+QDeclarativePackageAttached *QDeclarativePackage::qmlAttachedProperties(QObject *o)
+{
+ return new QDeclarativePackageAttached(o);
+}
+
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepackage_p.h b/src/declarative/util/qdeclarativepackage_p.h
new file mode 100644
index 0000000000..117fb4c7c1
--- /dev/null
+++ b/src/declarative/util/qdeclarativepackage_p.h
@@ -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 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 QDECLARATIVEPACKAGE_H
+#define QDECLARATIVEPACKAGE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePackagePrivate;
+class QDeclarativePackageAttached;
+class Q_AUTOTEST_EXPORT QDeclarativePackage : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePackage)
+
+ Q_CLASSINFO("DefaultProperty", "data")
+ Q_PROPERTY(QDeclarativeListProperty<QObject> data READ data SCRIPTABLE false)
+
+public:
+ QDeclarativePackage(QObject *parent=0);
+ virtual ~QDeclarativePackage();
+
+ QDeclarativeListProperty<QObject> data();
+
+ QObject *part(const QString & = QString());
+ bool hasPart(const QString &);
+
+ static QDeclarativePackageAttached *qmlAttachedProperties(QObject *);
+};
+
+class QDeclarativePackageAttached : public QObject
+{
+Q_OBJECT
+Q_PROPERTY(QString name READ name WRITE setName)
+public:
+ QDeclarativePackageAttached(QObject *parent);
+ virtual ~QDeclarativePackageAttached();
+
+ QString name() const;
+ void setName(const QString &n);
+
+ static QHash<QObject *, QDeclarativePackageAttached *> attached;
+private:
+ QString _name;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePackage)
+QML_DECLARE_TYPEINFO(QDeclarativePackage, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPACKAGE_H
diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
new file mode 100644
index 0000000000..a29854fa84
--- /dev/null
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -0,0 +1,1080 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepixmapcache_p.h"
+#include "qdeclarativenetworkaccessmanagerfactory.h"
+#include "qdeclarativeimageprovider.h"
+
+#include <qdeclarativeengine.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <QCoreApplication>
+#include <QImageReader>
+#include <QHash>
+#include <QNetworkReply>
+#include <QPixmapCache>
+#include <QFile>
+#include <QThread>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QWaitCondition>
+#include <QBuffer>
+#include <QWaitCondition>
+#include <QtCore/qdebug.h>
+#include <private/qobject_p.h>
+#include <QSslError>
+
+#define IMAGEREQUEST_MAX_REQUEST_COUNT 8
+#define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16
+#define CACHE_EXPIRE_TIME 30
+#define CACHE_REMOVAL_FRACTION 4
+
+QT_BEGIN_NAMESPACE
+
+// The cache limit describes the maximum "junk" in the cache.
+// These are the same defaults as QPixmapCache
+#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
+#endif
+
+class QDeclarativePixmapReader;
+class QDeclarativePixmapData;
+class QDeclarativePixmapReply : public QObject
+{
+ Q_OBJECT
+public:
+ enum ReadError { NoError, Loading, Decoding };
+
+ QDeclarativePixmapReply(QDeclarativePixmapData *);
+ ~QDeclarativePixmapReply();
+
+ QDeclarativePixmapData *data;
+ QDeclarativePixmapReader *reader;
+ QSize requestSize;
+
+ bool loading;
+ int redirectCount;
+
+ class Event : public QEvent {
+ public:
+ Event(ReadError, const QString &, const QSize &, const QImage &);
+
+ ReadError error;
+ QString errorString;
+ QSize implicitSize;
+ QImage image;
+ };
+ void postReply(ReadError, const QString &, const QSize &, const QImage &);
+
+
+Q_SIGNALS:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QDeclarativePixmapReply)
+
+public:
+ static int finishedIndex;
+ static int downloadProgressIndex;
+};
+
+class QDeclarativePixmapReaderThreadObject : public QObject {
+ Q_OBJECT
+public:
+ QDeclarativePixmapReaderThreadObject(QDeclarativePixmapReader *);
+ void processJobs();
+ virtual bool event(QEvent *e);
+private slots:
+ void networkRequestDone();
+private:
+ QDeclarativePixmapReader *reader;
+};
+
+class QDeclarativePixmapData;
+class QDeclarativePixmapReader : public QThread
+{
+ Q_OBJECT
+public:
+ QDeclarativePixmapReader(QDeclarativeEngine *eng);
+ ~QDeclarativePixmapReader();
+
+ QDeclarativePixmapReply *getImage(QDeclarativePixmapData *);
+ void cancel(QDeclarativePixmapReply *rep);
+
+ static QDeclarativePixmapReader *instance(QDeclarativeEngine *engine);
+
+protected:
+ void run();
+
+private:
+ friend class QDeclarativePixmapReaderThreadObject;
+ void processJobs();
+ void processJob(QDeclarativePixmapReply *, const QUrl &, const QSize &);
+ void networkRequestDone(QNetworkReply *);
+
+ QList<QDeclarativePixmapReply*> jobs;
+ QList<QDeclarativePixmapReply*> cancelled;
+ QDeclarativeEngine *engine;
+ QObject *eventLoopQuitHack;
+
+ QMutex mutex;
+ QDeclarativePixmapReaderThreadObject *threadObject;
+ QWaitCondition waitCondition;
+
+ QNetworkAccessManager *networkAccessManager();
+ QNetworkAccessManager *accessManager;
+
+ QHash<QNetworkReply*,QDeclarativePixmapReply*> replies;
+
+ static int replyDownloadProgress;
+ static int replyFinished;
+ static int downloadProgress;
+ static int threadNetworkRequestDone;
+ static QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> readers;
+ static QMutex readerMutex;
+};
+
+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),
+ 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),
+ 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),
+ 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),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ }
+
+ int cost() const;
+ void addref();
+ void release();
+ void addToCache();
+ void removeFromCache();
+
+ uint refCount;
+
+ bool inCache:1;
+ bool privatePixmap:1;
+
+ QDeclarativePixmap::Status pixmapStatus;
+ QUrl url;
+ QString errorString;
+ QPixmap pixmap;
+ QSize implicitSize;
+ QSize requestSize;
+
+ QDeclarativePixmapReply *reply;
+
+ QDeclarativePixmapData *prevUnreferenced;
+ QDeclarativePixmapData**prevUnreferencedPtr;
+ QDeclarativePixmapData *nextUnreferenced;
+};
+
+int QDeclarativePixmapReply::finishedIndex = -1;
+int QDeclarativePixmapReply::downloadProgressIndex = -1;
+
+// XXX
+QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> QDeclarativePixmapReader::readers;
+QMutex QDeclarativePixmapReader::readerMutex;
+
+int QDeclarativePixmapReader::replyDownloadProgress = -1;
+int QDeclarativePixmapReader::replyFinished = -1;
+int QDeclarativePixmapReader::downloadProgress = -1;
+int QDeclarativePixmapReader::threadNetworkRequestDone = -1;
+
+
+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));
+}
+
+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)
+{
+}
+
+QNetworkAccessManager *QDeclarativePixmapReader::networkAccessManager()
+{
+ if (!accessManager) {
+ Q_ASSERT(threadObject);
+ accessManager = QDeclarativeEnginePrivate::get(engine)->createNetworkAccessManager(threadObject);
+ }
+ return accessManager;
+}
+
+static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
+ const QSize &requestSize)
+{
+ QImageReader imgio(dev);
+
+ bool force_scale = false;
+ if (url.path().endsWith(QLatin1String(".svg"),Qt::CaseInsensitive)) {
+ imgio.setFormat("svg"); // QSvgPlugin::capabilities bug QTBUG-9053
+ force_scale = true;
+ }
+
+ bool scaled = false;
+ if (requestSize.width() > 0 || requestSize.height() > 0) {
+ QSize s = imgio.size();
+ if (requestSize.width() && (force_scale || requestSize.width() < s.width())) {
+ if (requestSize.height() <= 0)
+ s.setHeight(s.height()*requestSize.width()/s.width());
+ s.setWidth(requestSize.width()); scaled = true;
+ }
+ if (requestSize.height() && (force_scale || requestSize.height() < s.height())) {
+ if (requestSize.width() <= 0)
+ s.setWidth(s.width()*requestSize.height()/s.height());
+ s.setHeight(requestSize.height()); scaled = true;
+ }
+ if (scaled) { imgio.setScaledSize(s); }
+ }
+
+ if (impsize)
+ *impsize = imgio.size();
+
+ if (imgio.read(image)) {
+ if (impsize && impsize->width() < 0)
+ *impsize = image->size();
+ return true;
+ } else {
+ if (errorString)
+ *errorString = QDeclarativePixmap::tr("Error decoding: %1: %2").arg(url.toString())
+ .arg(imgio.errorString());
+ return false;
+ }
+}
+
+QDeclarativePixmapReader::QDeclarativePixmapReader(QDeclarativeEngine *eng)
+: QThread(eng), engine(eng), threadObject(0), accessManager(0)
+{
+ eventLoopQuitHack = new QObject;
+ eventLoopQuitHack->moveToThread(this);
+ connect(eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection);
+ start(QThread::IdlePriority);
+}
+
+QDeclarativePixmapReader::~QDeclarativePixmapReader()
+{
+ readerMutex.lock();
+ readers.remove(engine);
+ readerMutex.unlock();
+
+ eventLoopQuitHack->deleteLater();
+ wait();
+}
+
+void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
+{
+ QDeclarativePixmapReply *job = replies.take(reply);
+
+ if (job) {
+ job->redirectCount++;
+ if (job->redirectCount < IMAGEREQUEST_MAX_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+
+ reply->deleteLater();
+ reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, job, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone);
+
+ replies.insert(reply, job);
+ return;
+ }
+ }
+
+ QImage image;
+ QDeclarativePixmapReply::ReadError error = QDeclarativePixmapReply::NoError;
+ QString errorString;
+ QSize readSize;
+ if (reply->error()) {
+ error = QDeclarativePixmapReply::Loading;
+ errorString = reply->errorString();
+ } else {
+ QByteArray all = reply->readAll();
+ QBuffer buff(&all);
+ buff.open(QIODevice::ReadOnly);
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize)) {
+ error = QDeclarativePixmapReply::Decoding;
+ }
+ }
+ // send completion event to the QDeclarativePixmapReply
+ mutex.lock();
+ if (!cancelled.contains(job)) job->postReply(error, errorString, readSize, image);
+ mutex.unlock();
+ }
+ reply->deleteLater();
+
+ // kick off event loop again incase we have dropped below max request count
+ threadObject->processJobs();
+}
+
+QDeclarativePixmapReaderThreadObject::QDeclarativePixmapReaderThreadObject(QDeclarativePixmapReader *i)
+: reader(i)
+{
+}
+
+void QDeclarativePixmapReaderThreadObject::processJobs()
+{
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+bool QDeclarativePixmapReaderThreadObject::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ reader->processJobs();
+ return true;
+ } else {
+ return QObject::event(e);
+ }
+}
+
+void QDeclarativePixmapReaderThreadObject::networkRequestDone()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reader->networkRequestDone(reply);
+}
+
+void QDeclarativePixmapReader::processJobs()
+{
+ QMutexLocker locker(&mutex);
+
+ while (true) {
+ if (cancelled.isEmpty() && (jobs.isEmpty() || replies.count() >= IMAGEREQUEST_MAX_REQUEST_COUNT))
+ return; // Nothing else to do
+
+ // Clean cancelled jobs
+ if (cancelled.count()) {
+ for (int i = 0; i < cancelled.count(); ++i) {
+ QDeclarativePixmapReply *job = cancelled.at(i);
+ QNetworkReply *reply = replies.key(job, 0);
+ if (reply && reply->isRunning()) {
+ // cancel any jobs already started
+ replies.remove(reply);
+ reply->close();
+ }
+ // deleteLater, since not owned by this thread
+ job->deleteLater();
+ }
+ cancelled.clear();
+ }
+
+ if (!jobs.isEmpty() && replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT) {
+ QDeclarativePixmapReply *runningJob = jobs.takeLast();
+ runningJob->loading = true;
+
+ QUrl url = runningJob->data->url;
+ QSize requestSize = runningJob->data->requestSize;
+ locker.unlock();
+ processJob(runningJob, url, requestSize);
+ locker.relock();
+ }
+ }
+}
+
+void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, const QUrl &url,
+ const QSize &requestSize)
+{
+ // fetch
+ if (url.scheme() == QLatin1String("image")) {
+ // Use QmlImageProvider
+ QSize readSize;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ 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)) runningJob->postReply(errorCode, errorStr, readSize, image);
+ mutex.unlock();
+ } else {
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+ if (!lf.isEmpty()) {
+ // Image is local - load/decode immediately
+ QImage image;
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ QFile f(lf);
+ QSize readSize;
+ if (f.open(QIODevice::ReadOnly)) {
+ if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize))
+ errorCode = QDeclarativePixmapReply::Loading;
+ } 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);
+ mutex.unlock();
+ } else {
+ // Network resource
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ QNetworkReply *reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone);
+
+ replies.insert(reply, runningJob);
+ }
+ }
+}
+
+QDeclarativePixmapReader *QDeclarativePixmapReader::instance(QDeclarativeEngine *engine)
+{
+ readerMutex.lock();
+ QDeclarativePixmapReader *reader = readers.value(engine);
+ if (!reader) {
+ reader = new QDeclarativePixmapReader(engine);
+ readers.insert(engine, reader);
+ }
+ readerMutex.unlock();
+
+ return reader;
+}
+
+QDeclarativePixmapReply *QDeclarativePixmapReader::getImage(QDeclarativePixmapData *data)
+{
+ mutex.lock();
+ QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(data);
+ reply->reader = this;
+ jobs.append(reply);
+ // XXX
+ if (threadObject) threadObject->processJobs();
+ mutex.unlock();
+ return reply;
+}
+
+void QDeclarativePixmapReader::cancel(QDeclarativePixmapReply *reply)
+{
+ mutex.lock();
+ if (reply->loading) {
+ cancelled.append(reply);
+ reply->data = 0;
+ // XXX
+ if (threadObject) threadObject->processJobs();
+ } else {
+ jobs.removeAll(reply);
+ delete reply;
+ }
+ mutex.unlock();
+}
+
+void QDeclarativePixmapReader::run()
+{
+ if (replyDownloadProgress == -1) {
+ const QMetaObject *nr = &QNetworkReply::staticMetaObject;
+ const QMetaObject *pr = &QDeclarativePixmapReply::staticMetaObject;
+ const QMetaObject *ir = &QDeclarativePixmapReaderThreadObject::staticMetaObject;
+ replyDownloadProgress = nr->indexOfSignal("downloadProgress(qint64,qint64)");
+ replyFinished = nr->indexOfSignal("finished()");
+ downloadProgress = pr->indexOfSignal("downloadProgress(qint64,qint64)");
+ threadNetworkRequestDone = ir->indexOfSlot("networkRequestDone()");
+ }
+
+ mutex.lock();
+ threadObject = new QDeclarativePixmapReaderThreadObject(this);
+ mutex.unlock();
+
+ processJobs();
+ exec();
+
+ delete threadObject;
+ threadObject = 0;
+}
+
+class QDeclarativePixmapKey
+{
+public:
+ const QUrl *url;
+ const QSize *size;
+};
+
+inline bool operator==(const QDeclarativePixmapKey &lhs, const QDeclarativePixmapKey &rhs)
+{
+ return *lhs.size == *rhs.size && *lhs.url == *rhs.url;
+}
+
+inline uint qHash(const QDeclarativePixmapKey &key)
+{
+ return qHash(*key.url) ^ key.size->width() ^ key.size->height();
+}
+
+class QDeclarativePixmapStore : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativePixmapStore();
+
+ void unreferencePixmap(QDeclarativePixmapData *);
+ void referencePixmap(QDeclarativePixmapData *);
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+public:
+ QHash<QDeclarativePixmapKey, QDeclarativePixmapData *> m_cache;
+
+private:
+ void shrinkCache(int remove);
+
+ QDeclarativePixmapData *m_unreferencedPixmaps;
+ QDeclarativePixmapData *m_lastUnreferencedPixmap;
+
+ int m_unreferencedCost;
+ int m_timerId;
+};
+Q_GLOBAL_STATIC(QDeclarativePixmapStore, pixmapStore);
+
+QDeclarativePixmapStore::QDeclarativePixmapStore()
+: m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1)
+{
+}
+
+void QDeclarativePixmapStore::unreferencePixmap(QDeclarativePixmapData *data)
+{
+ Q_ASSERT(data->prevUnreferenced == 0);
+ Q_ASSERT(data->prevUnreferencedPtr == 0);
+ Q_ASSERT(data->nextUnreferenced == 0);
+
+ data->nextUnreferenced = m_unreferencedPixmaps;
+ data->prevUnreferencedPtr = &m_unreferencedPixmaps;
+
+ m_unreferencedPixmaps = data;
+ if (m_unreferencedPixmaps->nextUnreferenced) {
+ m_unreferencedPixmaps->nextUnreferenced->prevUnreferenced = m_unreferencedPixmaps;
+ m_unreferencedPixmaps->nextUnreferenced->prevUnreferencedPtr = &m_unreferencedPixmaps->nextUnreferenced;
+ }
+
+ if (!m_lastUnreferencedPixmap)
+ m_lastUnreferencedPixmap = data;
+
+ m_unreferencedCost += data->cost();
+
+ shrinkCache(-1); // Shrink the cache incase it has become larger than cache_limit
+
+ if (m_timerId == -1 && m_unreferencedPixmaps)
+ m_timerId = startTimer(CACHE_EXPIRE_TIME * 1000);
+}
+
+void QDeclarativePixmapStore::referencePixmap(QDeclarativePixmapData *data)
+{
+ Q_ASSERT(data->prevUnreferencedPtr);
+
+ *data->prevUnreferencedPtr = data->nextUnreferenced;
+ if (data->nextUnreferenced) {
+ data->nextUnreferenced->prevUnreferencedPtr = data->prevUnreferencedPtr;
+ data->nextUnreferenced->prevUnreferenced = data->prevUnreferenced;
+ }
+ if (m_lastUnreferencedPixmap == data)
+ m_lastUnreferencedPixmap = data->prevUnreferenced;
+
+ data->nextUnreferenced = 0;
+ data->prevUnreferencedPtr = 0;
+ data->prevUnreferenced = 0;
+
+ m_unreferencedCost -= data->cost();
+}
+
+void QDeclarativePixmapStore::shrinkCache(int remove)
+{
+ while ((remove > 0 || m_unreferencedCost > cache_limit) && m_lastUnreferencedPixmap) {
+ QDeclarativePixmapData *data = m_lastUnreferencedPixmap;
+ Q_ASSERT(data->nextUnreferenced == 0);
+
+ *data->prevUnreferencedPtr = 0;
+ m_lastUnreferencedPixmap = data->prevUnreferenced;
+ data->prevUnreferencedPtr = 0;
+ data->prevUnreferenced = 0;
+
+ remove -= data->cost();
+ m_unreferencedCost -= data->cost();
+ data->removeFromCache();
+ delete data;
+ }
+}
+
+void QDeclarativePixmapStore::timerEvent(QTimerEvent *)
+{
+ int removalCost = m_unreferencedCost / CACHE_REMOVAL_FRACTION;
+
+ shrinkCache(removalCost);
+
+ if (m_unreferencedPixmaps == 0) {
+ killTimer(m_timerId);
+ m_timerId = -1;
+ }
+}
+
+QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativePixmapData *d)
+: data(d), reader(0), requestSize(d->requestSize), loading(false), redirectCount(0)
+{
+ if (finishedIndex == -1) {
+ finishedIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()");
+ downloadProgressIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
+ }
+}
+
+QDeclarativePixmapReply::~QDeclarativePixmapReply()
+{
+}
+
+bool QDeclarativePixmapReply::event(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+
+ if (data) {
+ Event *de = static_cast<Event *>(event);
+ data->pixmapStatus = (de->error == NoError) ? QDeclarativePixmap::Ready : QDeclarativePixmap::Error;
+
+ if (data->pixmapStatus == QDeclarativePixmap::Ready) {
+ data->pixmap = QPixmap::fromImage(de->image);
+ data->implicitSize = de->implicitSize;
+ } else {
+ data->errorString = de->errorString;
+ data->removeFromCache(); // We don't continue to cache error'd pixmaps
+ }
+
+ data->reply = 0;
+ emit finished();
+ }
+
+ delete this;
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+int QDeclarativePixmapData::cost() const
+{
+ return (pixmap.width() * pixmap.height() * pixmap.depth()) / 8;
+}
+
+void QDeclarativePixmapData::addref()
+{
+ ++refCount;
+ if (prevUnreferencedPtr)
+ pixmapStore()->referencePixmap(this);
+}
+
+void QDeclarativePixmapData::release()
+{
+ Q_ASSERT(refCount > 0);
+ --refCount;
+
+ if (refCount == 0) {
+ if (reply) {
+ reply->reader->cancel(reply);
+ reply = 0;
+ }
+
+ if (pixmapStatus == QDeclarativePixmap::Ready) {
+ pixmapStore()->unreferencePixmap(this);
+ } else {
+ removeFromCache();
+ delete this;
+ }
+ }
+}
+
+void QDeclarativePixmapData::addToCache()
+{
+ if (!inCache) {
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ pixmapStore()->m_cache.insert(key, this);
+ inCache = true;
+ }
+}
+
+void QDeclarativePixmapData::removeFromCache()
+{
+ if (inCache) {
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ pixmapStore()->m_cache.remove(key);
+ inCache = false;
+ }
+}
+
+static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool *ok)
+{
+ if (url.scheme() == QLatin1String("image")) {
+ QSize readSize;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+
+ switch (imageType) {
+ case QDeclarativeImageProvider::Image:
+ {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ if (!image.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+ }
+ }
+ case QDeclarativeImageProvider::Pixmap:
+ {
+ QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
+ if (!pixmap.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, pixmap, readSize, requestSize);
+ }
+ }
+ }
+
+ // no matching provider, or provider has bad image type, or provider returned null image
+ return new QDeclarativePixmapData(url, requestSize,
+ QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()));
+ }
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+ if (localFile.isEmpty())
+ return 0;
+
+ QFile f(localFile);
+ QSize readSize;
+ QString errorString;
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QImage image;
+ if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+ }
+ } else {
+ errorString = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
+ }
+ return new QDeclarativePixmapData(url, requestSize, errorString);
+}
+
+
+struct QDeclarativePixmapNull {
+ QUrl url;
+ QPixmap pixmap;
+ QSize size;
+};
+Q_GLOBAL_STATIC(QDeclarativePixmapNull, nullPixmap);
+
+QDeclarativePixmap::QDeclarativePixmap()
+: d(0)
+{
+}
+
+QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url)
+: d(0)
+{
+ load(engine, url);
+}
+
+QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url, const QSize &size)
+: d(0)
+{
+ load(engine, url, size);
+}
+
+QDeclarativePixmap::~QDeclarativePixmap()
+{
+ if (d) {
+ d->release();
+ d = 0;
+ }
+}
+
+bool QDeclarativePixmap::isNull() const
+{
+ return d == 0;
+}
+
+bool QDeclarativePixmap::isReady() const
+{
+ return status() == Ready;
+}
+
+bool QDeclarativePixmap::isError() const
+{
+ return status() == Error;
+}
+
+bool QDeclarativePixmap::isLoading() const
+{
+ return status() == Loading;
+}
+
+QString QDeclarativePixmap::error() const
+{
+ if (d)
+ return d->errorString;
+ else
+ return QString();
+}
+
+QDeclarativePixmap::Status QDeclarativePixmap::status() const
+{
+ if (d)
+ return d->pixmapStatus;
+ else
+ return Null;
+}
+
+const QUrl &QDeclarativePixmap::url() const
+{
+ if (d)
+ return d->url;
+ else
+ return nullPixmap()->url;
+}
+
+const QSize &QDeclarativePixmap::implicitSize() const
+{
+ if (d)
+ return d->implicitSize;
+ else
+ return nullPixmap()->size;
+}
+
+const QSize &QDeclarativePixmap::requestSize() const
+{
+ if (d)
+ return d->requestSize;
+ else
+ return nullPixmap()->size;
+}
+
+const QPixmap &QDeclarativePixmap::pixmap() const
+{
+ if (d)
+ return d->pixmap;
+ else
+ return nullPixmap()->pixmap;
+}
+
+void QDeclarativePixmap::setPixmap(const QPixmap &p)
+{
+ clear();
+
+ if (!p.isNull())
+ d = new QDeclarativePixmapData(p);
+}
+
+int QDeclarativePixmap::width() const
+{
+ if (d)
+ return d->pixmap.width();
+ else
+ return 0;
+}
+
+int QDeclarativePixmap::height() const
+{
+ if (d)
+ return d->pixmap.height();
+ else
+ return 0;
+}
+
+QRect QDeclarativePixmap::rect() const
+{
+ if (d)
+ return d->pixmap.rect();
+ else
+ return QRect();
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url)
+{
+ load(engine, url, QSize(), QDeclarativePixmap::Cache);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, QDeclarativePixmap::Options options)
+{
+ load(engine, url, QSize(), options);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &size)
+{
+ load(engine, url, size, QDeclarativePixmap::Cache);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, QDeclarativePixmap::Options options)
+{
+ if (d) { d->release(); d = 0; }
+
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ QDeclarativePixmapStore *store = pixmapStore();
+
+ QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::Iterator iter = store->m_cache.find(key);
+
+ if (iter == store->m_cache.end()) {
+ if (options & QDeclarativePixmap::Asynchronous) {
+ // pixmaps can only be loaded synchronously
+ if (url.scheme() == QLatin1String("image")
+ && QDeclarativeEnginePrivate::get(engine)->getImageProviderType(url) == QDeclarativeImageProvider::Pixmap) {
+ options &= ~QDeclarativePixmap::Asynchronous;
+ }
+ }
+
+ if (!(options & QDeclarativePixmap::Asynchronous)) {
+ bool ok = false;
+ d = createPixmapDataSync(engine, url, requestSize, &ok);
+ if (ok) {
+ if (options & QDeclarativePixmap::Cache)
+ d->addToCache();
+ return;
+ }
+ if (d) // loadable, but encountered error while loading
+ return;
+ }
+
+ if (!engine)
+ return;
+
+ QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine);
+
+ d = new QDeclarativePixmapData(url, requestSize);
+ if (options & QDeclarativePixmap::Cache)
+ d->addToCache();
+
+ d->reply = reader->getImage(d);
+ } else {
+ d = *iter;
+ d->addref();
+ }
+}
+
+void QDeclarativePixmap::clear()
+{
+ if (d) {
+ d->release();
+ d = 0;
+ }
+}
+
+void QDeclarativePixmap::clear(QObject *obj)
+{
+ if (d) {
+ if (d->reply)
+ QObject::disconnect(d->reply, 0, obj, 0);
+ d->release();
+ d = 0;
+ }
+}
+
+bool QDeclarativePixmap::connectFinished(QObject *object, const char *method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectFinished() called when not loading.");
+ return false;
+ }
+
+ return QObject::connect(d->reply, SIGNAL(finished()), object, method);
+}
+
+bool QDeclarativePixmap::connectFinished(QObject *object, int method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectFinished() called when not loading.");
+ return false;
+ }
+
+ return QMetaObject::connect(d->reply, QDeclarativePixmapReply::finishedIndex, object, method);
+}
+
+bool QDeclarativePixmap::connectDownloadProgress(QObject *object, const char *method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading.");
+ return false;
+ }
+
+ return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), object, method);
+}
+
+bool QDeclarativePixmap::connectDownloadProgress(QObject *object, int method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading.");
+ return false;
+ }
+
+ return QMetaObject::connect(d->reply, QDeclarativePixmapReply::downloadProgressIndex, object, method);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativepixmapcache.moc>
diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h
new file mode 100644
index 0000000000..1cf76dda71
--- /dev/null
+++ b/src/declarative/util/qdeclarativepixmapcache_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 QDECLARATIVEPIXMAPCACHE_H
+#define QDECLARATIVEPIXMAPCACHE_H
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qpixmap.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class QDeclarativePixmapData;
+class Q_DECLARATIVE_EXPORT QDeclarativePixmap
+{
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmap)
+public:
+ QDeclarativePixmap();
+ QDeclarativePixmap(QDeclarativeEngine *, const QUrl &);
+ QDeclarativePixmap(QDeclarativeEngine *, const QUrl &, const QSize &);
+ ~QDeclarativePixmap();
+
+ enum Status { Null, Ready, Error, Loading };
+
+ enum Option {
+ Asynchronous = 0x00000001,
+ Cache = 0x00000002
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ Status status() const;
+ QString error() const;
+ const QUrl &url() const;
+ const QSize &implicitSize() const;
+ const QSize &requestSize() const;
+ const QPixmap &pixmap() const;
+ void setPixmap(const QPixmap &);
+
+ QRect rect() const;
+ int width() const;
+ int height() const;
+ inline operator const QPixmap &() const;
+
+ void load(QDeclarativeEngine *, const QUrl &);
+ void load(QDeclarativeEngine *, const QUrl &, QDeclarativePixmap::Options options);
+ void load(QDeclarativeEngine *, const QUrl &, const QSize &);
+ void load(QDeclarativeEngine *, const QUrl &, const QSize &, QDeclarativePixmap::Options options);
+
+ void clear();
+ void clear(QObject *);
+
+ bool connectFinished(QObject *, const char *);
+ bool connectFinished(QObject *, int);
+ bool connectDownloadProgress(QObject *, const char *);
+ bool connectDownloadProgress(QObject *, int);
+
+private:
+ Q_DISABLE_COPY(QDeclarativePixmap)
+ QDeclarativePixmapData *d;
+};
+
+inline QDeclarativePixmap::operator const QPixmap &() const
+{
+ return pixmap();
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePixmap::Options)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPIXMAPCACHE_H
diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp
new file mode 100644
index 0000000000..b03630d854
--- /dev/null
+++ b/src/declarative/util/qdeclarativepropertychanges.cpp
@@ -0,0 +1,797 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativepropertychanges_p.h"
+
+#include "private/qdeclarativeopenmetaobject_p.h"
+#include "private/qdeclarativerewrite_p.h"
+#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativecompiler_p.h"
+
+#include <qdeclarativeinfo.h>
+#include <qdeclarativecustomparser_p.h>
+#include <qdeclarativeparser_p.h>
+#include <qdeclarativeexpression.h>
+#include <qdeclarativebinding_p.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeguard_p.h>
+#include <qdeclarativeproperty_p.h>
+#include <qdeclarativecontext_p.h>
+#include <qdeclarativestate_p_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass PropertyChanges QDeclarativePropertyChanges
+ \ingroup qml-state-elements
+ \since 4.7
+ \brief The PropertyChanges element describes new property bindings or values for a state.
+
+ PropertyChanges is used to define the property values or bindings in a
+ \l State. This enables an item's property values to be changed when it
+ \l {QML States}{changes between states}.
+
+ To create a PropertyChanges object, specify the \l target item whose
+ properties are to be modified, and define the new property values or
+ bindings. For example:
+
+ \snippet doc/src/snippets/declarative/propertychanges.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/propertychanges.qml 0
+
+ When the mouse is pressed, the \l Rectangle changes to the \e resized
+ state. In this state, the PropertyChanges object sets the rectangle's
+ color to blue and the \c height value to that of \c container.height.
+
+ Note this automatically binds \c rect.height to \c container.height
+ in the \e resized state. If a property binding should not be
+ established, and the height should just be set to the value of
+ \c container.height at the time of the state change, set the \l explicit
+ property to \c true.
+
+ A PropertyChanges object can also override the default signal handler
+ for an object to implement a signal handler specific to the new state:
+
+ \qml
+ PropertyChanges {
+ target: myMouseArea
+ onClicked: doSomethingDifferent()
+ }
+ \endqml
+
+ \note PropertyChanges can be used to change anchor margins, but not other anchor
+ values; use AnchorChanges for this instead. Similarly, to change an \l Item's
+ \l {Item::}{parent} value, use ParentChanges instead.
+
+
+ \section2 Resetting property values
+
+ The \c undefined value can be used to reset the property value for a state.
+ In the following example, when \c theText changes to the \e widerText
+ state, its \c width property is reset, giving the text its natural width
+ and displaying the whole string on a single line.
+
+ \snippet doc/src/snippets/declarative/propertychanges.qml reset
+
+
+ \section2 Immediate property changes in transitions
+
+ When \l{QML Animation and Transitions}{Transitions} are used to animate
+ state changes, they animate properties from their values in the current
+ state to those defined in the new state (as defined by PropertyChanges
+ objects). However, it is sometimes desirable to set a property value
+ \e immediately during a \l Transition, without animation; in these cases,
+ the PropertyAction element can be used to force an immediate property
+ change.
+
+ See the PropertyAction documentation for more details.
+
+ \sa {declarative/animation/states}{states example}, {qmlstate}{States}, QtDeclarative
+*/
+
+/*!
+ \qmlproperty Object PropertyChanges::target
+ This property holds the object which contains the properties to be changed.
+*/
+
+class QDeclarativeReplaceSignalHandler : public QDeclarativeActionEvent
+{
+public:
+ QDeclarativeReplaceSignalHandler() : expression(0), reverseExpression(0),
+ rewindExpression(0), ownedExpression(0) {}
+ ~QDeclarativeReplaceSignalHandler() {
+ delete ownedExpression;
+ }
+
+ virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
+
+ QDeclarativeProperty property;
+ QDeclarativeExpression *expression;
+ QDeclarativeExpression *reverseExpression;
+ QDeclarativeExpression *rewindExpression;
+ QDeclarativeGuard<QDeclarativeExpression> ownedExpression;
+
+ virtual void execute(Reason) {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
+ if (ownedExpression == expression)
+ ownedExpression = 0;
+ }
+
+ virtual bool isReversable() { return true; }
+ virtual void reverse(Reason) {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
+ if (ownedExpression == reverseExpression)
+ ownedExpression = 0;
+ }
+
+ virtual void saveOriginals() {
+ saveCurrentValues();
+ reverseExpression = rewindExpression;
+ }
+
+ /*virtual void copyOriginals(QDeclarativeActionEvent *other)
+ {
+ QDeclarativeReplaceSignalHandler *rsh = static_cast<QDeclarativeReplaceSignalHandler*>(other);
+ saveCurrentValues();
+ if (rsh == this)
+ return;
+ reverseExpression = rsh->reverseExpression;
+ if (rsh->ownedExpression == reverseExpression) {
+ ownedExpression = rsh->ownedExpression;
+ rsh->ownedExpression = 0;
+ }
+ }*/
+
+ virtual void rewind() {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression);
+ if (ownedExpression == rewindExpression)
+ ownedExpression = 0;
+ }
+ virtual void saveCurrentValues() {
+ rewindExpression = QDeclarativePropertyPrivate::signalExpression(property);
+ }
+
+ virtual bool override(QDeclarativeActionEvent*other) {
+ if (other == this)
+ return true;
+ if (other->typeName() != typeName())
+ return false;
+ if (static_cast<QDeclarativeReplaceSignalHandler*>(other)->property == property)
+ return true;
+ return false;
+ }
+};
+
+
+class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyChanges)
+public:
+ QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
+ isExplicit(false) {}
+
+ QDeclarativeGuard<QObject> object;
+ QByteArray data;
+
+ bool decoded : 1;
+ bool restore : 1;
+ bool isExplicit : 1;
+
+ void decode();
+
+ class ExpressionChange {
+ public:
+ ExpressionChange(const QString &_name,
+ QDeclarativeBinding::Identifier _id,
+ QDeclarativeExpression *_expr)
+ : name(_name), id(_id), expression(_expr) {}
+ QString name;
+ QDeclarativeBinding::Identifier id;
+ QDeclarativeExpression *expression;
+ };
+
+ QList<QPair<QString, QVariant> > properties;
+ QList<ExpressionChange> expressions;
+ QList<QDeclarativeReplaceSignalHandler*> signalReplacements;
+
+ QDeclarativeProperty property(const QString &);
+};
+
+void
+QDeclarativePropertyChangesParser::compileList(QList<QPair<QByteArray, QVariant> > &list,
+ const QByteArray &pre,
+ const QDeclarativeCustomParserProperty &prop)
+{
+ QByteArray propName = pre + prop.name();
+
+ QList<QVariant> values = prop.assignedValues();
+ for (int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
+ error(qvariant_cast<QDeclarativeCustomParserNode>(value),
+ QDeclarativePropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
+ continue;
+ } else if(value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
+
+ QDeclarativeCustomParserProperty prop =
+ qvariant_cast<QDeclarativeCustomParserProperty>(value);
+ QByteArray pre = propName + '.';
+ compileList(list, pre, prop);
+
+ } else {
+ list << qMakePair(propName, value);
+ }
+ }
+}
+
+QByteArray
+QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
+{
+ QList<QPair<QByteArray, QVariant> > data;
+ for(int ii = 0; ii < props.count(); ++ii)
+ compileList(data, QByteArray(), props.at(ii));
+
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ ds << data.count();
+ for(int ii = 0; ii < data.count(); ++ii) {
+ QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(data.at(ii).second);
+ QVariant var;
+ bool isScript = v.isScript();
+ QDeclarativeBinding::Identifier id = 0;
+ switch(v.type()) {
+ case QDeclarativeParser::Variant::Boolean:
+ var = QVariant(v.asBoolean());
+ break;
+ case QDeclarativeParser::Variant::Number:
+ var = QVariant(v.asNumber());
+ break;
+ case QDeclarativeParser::Variant::String:
+ var = QVariant(v.asString());
+ break;
+ case QDeclarativeParser::Variant::Invalid:
+ case QDeclarativeParser::Variant::Script:
+ var = QVariant(v.asScript());
+ {
+ // Pre-rewrite the expression
+ QString expression = v.asScript();
+ id = rewriteBinding(expression, data.at(ii).first); //### recreates the AST, which is slow
+ }
+ break;
+ }
+
+ ds << QString::fromUtf8(data.at(ii).first) << isScript << var;
+ if (isScript)
+ ds << id;
+ }
+
+ return rv;
+}
+
+void QDeclarativePropertyChangesPrivate::decode()
+{
+ Q_Q(QDeclarativePropertyChanges);
+ if (decoded)
+ return;
+
+ QDataStream ds(&data, QIODevice::ReadOnly);
+
+ int count;
+ ds >> count;
+ for (int ii = 0; ii < count; ++ii) {
+ QString name;
+ bool isScript;
+ QVariant data;
+ QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid;
+ ds >> name;
+ ds >> isScript;
+ ds >> data;
+ if (isScript)
+ ds >> id;
+
+ QDeclarativeProperty prop = property(name); //### better way to check for signal property?
+ if (prop.type() & QDeclarativeProperty::SignalProperty) {
+ QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
+ QDeclarativeData *ddata = QDeclarativeData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ QDeclarativeReplaceSignalHandler *handler = new QDeclarativeReplaceSignalHandler;
+ handler->property = prop;
+ handler->expression = expression;
+ signalReplacements << handler;
+ } else if (isScript) {
+ QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
+ QDeclarativeData *ddata = QDeclarativeData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ expressions << ExpressionChange(name, id, expression);
+ } else {
+ properties << qMakePair(name, data);
+ }
+ }
+
+ decoded = true;
+ data.clear();
+}
+
+void QDeclarativePropertyChangesParser::setCustomData(QObject *object,
+ const QByteArray &data)
+{
+ QDeclarativePropertyChangesPrivate *p =
+ static_cast<QDeclarativePropertyChangesPrivate *>(QObjectPrivate::get(object));
+ p->data = data;
+ p->decoded = false;
+}
+
+QDeclarativePropertyChanges::QDeclarativePropertyChanges()
+: QDeclarativeStateOperation(*(new QDeclarativePropertyChangesPrivate))
+{
+}
+
+QDeclarativePropertyChanges::~QDeclarativePropertyChanges()
+{
+ Q_D(QDeclarativePropertyChanges);
+ for(int ii = 0; ii < d->expressions.count(); ++ii)
+ delete d->expressions.at(ii).expression;
+ for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
+ delete d->signalReplacements.at(ii);
+}
+
+QObject *QDeclarativePropertyChanges::object() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->object;
+}
+
+void QDeclarativePropertyChanges::setObject(QObject *o)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->object = o;
+}
+
+/*!
+ \qmlproperty bool PropertyChanges::restoreEntryValues
+
+ This property holds whether the previous values should be restored when
+ leaving the state.
+
+ The default value is \c true. Setting this value to \c false creates a
+ temporary state that has permanent effects on property values.
+*/
+bool QDeclarativePropertyChanges::restoreEntryValues() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->restore;
+}
+
+void QDeclarativePropertyChanges::setRestoreEntryValues(bool v)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->restore = v;
+}
+
+QDeclarativeProperty
+QDeclarativePropertyChangesPrivate::property(const QString &property)
+{
+ Q_Q(QDeclarativePropertyChanges);
+ QDeclarativeProperty prop(object, property, qmlContext(q));
+ if (!prop.isValid()) {
+ qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
+ return QDeclarativeProperty();
+ } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) {
+ qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
+ return QDeclarativeProperty();
+ }
+ return prop;
+}
+
+QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
+{
+ Q_D(QDeclarativePropertyChanges);
+
+ d->decode();
+
+ ActionList list;
+
+ for (int ii = 0; ii < d->properties.count(); ++ii) {
+
+ QDeclarativeAction a(d->object, d->properties.at(ii).first,
+ qmlContext(this), d->properties.at(ii).second);
+
+ if (a.property.isValid()) {
+ a.restore = restoreEntryValues();
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
+
+ QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
+
+ if (handler->property.isValid()) {
+ QDeclarativeAction a;
+ a.event = handler;
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->expressions.count(); ++ii) {
+
+ const QString &property = d->expressions.at(ii).name;
+ QDeclarativeProperty prop = d->property(property);
+
+ if (prop.isValid()) {
+ QDeclarativeAction a;
+ a.restore = restoreEntryValues();
+ a.property = prop;
+ a.fromValue = a.property.read();
+ a.specifiedObject = d->object;
+ a.specifiedProperty = property;
+
+ if (d->isExplicit) {
+ a.toValue = d->expressions.at(ii).expression->evaluate();
+ } else {
+ QDeclarativeExpression *e = d->expressions.at(ii).expression;
+
+ QDeclarativeBinding::Identifier id = d->expressions.at(ii).id;
+ QDeclarativeBinding *newBinding = id != QDeclarativeBinding::Invalid ? QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0;
+ if (!newBinding) {
+ newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
+ newBinding->setSourceLocation(e->sourceFile(), e->lineNumber());
+ }
+ newBinding->setTarget(prop);
+ a.toBinding = newBinding;
+ a.deletableToBinding = true;
+ }
+
+ list << a;
+ }
+ }
+
+ return list;
+}
+
+/*!
+ \qmlproperty bool PropertyChanges::explicit
+
+ If explicit is set to true, any potential bindings will be interpreted as
+ once-off assignments that occur when the state is entered.
+
+ In the following example, the addition of explicit prevents \c myItem.width from
+ being bound to \c parent.width. Instead, it is assigned the value of \c parent.width
+ at the time of the state change.
+ \qml
+ PropertyChanges {
+ target: myItem
+ explicit: true
+ width: parent.width
+ }
+ \endqml
+
+ By default, explicit is false.
+*/
+bool QDeclarativePropertyChanges::isExplicit() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->isExplicit;
+}
+
+void QDeclarativePropertyChanges::setIsExplicit(bool e)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->isExplicit = e;
+}
+
+bool QDeclarativePropertyChanges::containsValue(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsExpression(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsProperty(const QString &name) const
+{
+ return containsValue(name) || containsExpression(name);
+}
+
+void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ expressionIterator.remove();
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+ d->property(name).write(value);
+ }
+
+ d->properties.append(PropertyEntry(name, value));
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ entry.second = value;
+ if (state() && state()->isStateActive())
+ d->property(name).write(value);
+ return;
+ }
+ }
+
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = name;
+ action.toValue = value;
+
+ propertyIterator.insert(PropertyEntry(name, value));
+ if (state() && state()->isStateActive()) {
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ d->property(name).write(value);
+ }
+}
+
+void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ bool hadValue = false;
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ hadValue = true;
+ break;
+ }
+ }
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ entry.expression->setExpression(expression);
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ return;
+ }
+ }
+
+ QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
+ expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
+
+ if (state() && state()->isStateActive()) {
+ if (hadValue) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ state()->changeBindingInRevertList(object(), name, oldBinding);
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ } else {
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = name;
+
+
+ if (d->isExplicit) {
+ action.toValue = newExpression->evaluate();
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ action.toBinding = newBinding;
+ action.deletableToBinding = true;
+
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+
+ QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ }
+ }
+ // what about the signal handler?
+}
+
+QVariant QDeclarativePropertyChanges::property(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return QVariant(entry.expression->expression());
+ }
+ }
+
+ return QVariant();
+}
+
+void QDeclarativePropertyChanges::removeProperty(const QString &name)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ expressionIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+}
+
+QVariant QDeclarativePropertyChanges::value(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ return QVariant();
+}
+
+QString QDeclarativePropertyChanges::expression(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return entry.expression->expression();
+ }
+ }
+
+ return QString();
+}
+
+void QDeclarativePropertyChanges::detachFromState()
+{
+ if (state())
+ state()->removeAllEntriesFromRevertList(object());
+}
+
+void QDeclarativePropertyChanges::attachToState()
+{
+ if (state())
+ state()->addEntriesToRevertList(actions());
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepropertychanges_p.h b/src/declarative/util/qdeclarativepropertychanges_p.h
new file mode 100644
index 0000000000..09e3a16d3f
--- /dev/null
+++ b/src/declarative/util/qdeclarativepropertychanges_p.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPROPERTYCHANGES_H
+#define QDECLARATIVEPROPERTYCHANGES_H
+
+#include "private/qdeclarativestateoperations_p.h"
+#include <private/qdeclarativecustomparser_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePropertyChangesPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyChanges)
+
+ Q_PROPERTY(QObject *target READ object WRITE setObject)
+ Q_PROPERTY(bool restoreEntryValues READ restoreEntryValues WRITE setRestoreEntryValues)
+ Q_PROPERTY(bool explicit READ isExplicit WRITE setIsExplicit)
+public:
+ QDeclarativePropertyChanges();
+ ~QDeclarativePropertyChanges();
+
+ QObject *object() const;
+ void setObject(QObject *);
+
+ bool restoreEntryValues() const;
+ void setRestoreEntryValues(bool);
+
+ bool isExplicit() const;
+ void setIsExplicit(bool);
+
+ virtual ActionList actions();
+
+ bool containsProperty(const QString &name) const;
+ bool containsValue(const QString &name) const;
+ bool containsExpression(const QString &name) const;
+ void changeValue(const QString &name, const QVariant &value);
+ void changeExpression(const QString &name, const QString &expression);
+ void removeProperty(const QString &name);
+ QVariant value(const QString &name) const;
+ QString expression(const QString &name) const;
+
+ void detachFromState();
+ void attachToState();
+
+ QVariant property(const QString &name) const;
+};
+
+class QDeclarativePropertyChangesParser : public QDeclarativeCustomParser
+{
+public:
+ QDeclarativePropertyChangesParser()
+ : QDeclarativeCustomParser(AcceptsAttachedProperties) {}
+
+ void compileList(QList<QPair<QByteArray, QVariant> > &list, const QByteArray &pre, const QDeclarativeCustomParserProperty &prop);
+
+ virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &);
+ virtual void setCustomData(QObject *, const QByteArray &);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePropertyChanges)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROPERTYCHANGES_H
diff --git a/src/declarative/util/qdeclarativepropertymap.cpp b/src/declarative/util/qdeclarativepropertymap.cpp
new file mode 100644
index 0000000000..915f027e9a
--- /dev/null
+++ b/src/declarative/util/qdeclarativepropertymap.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativepropertymap.h"
+
+#include <private/qmetaobjectbuilder_p.h>
+#include "private/qdeclarativeopenmetaobject_p.h"
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+//QDeclarativePropertyMapMetaObject lets us listen for changes coming from QML
+//so we can emit the changed signal.
+class QDeclarativePropertyMapMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv);
+
+protected:
+ virtual void propertyWritten(int index);
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+private:
+ QDeclarativePropertyMap *map;
+ QDeclarativePropertyMapPrivate *priv;
+};
+
+class QDeclarativePropertyMapPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyMap)
+public:
+ QDeclarativePropertyMapMetaObject *mo;
+ QStringList keys;
+ void emitChanged(const QString &key, const QVariant &value);
+};
+
+void QDeclarativePropertyMapPrivate::emitChanged(const QString &key, const QVariant &value)
+{
+ Q_Q(QDeclarativePropertyMap);
+ emit q->valueChanged(key, value);
+}
+
+QDeclarativePropertyMapMetaObject::QDeclarativePropertyMapMetaObject(QDeclarativePropertyMap *obj, QDeclarativePropertyMapPrivate *objPriv) : QDeclarativeOpenMetaObject(obj)
+{
+ map = obj;
+ priv = objPriv;
+}
+
+void QDeclarativePropertyMapMetaObject::propertyWritten(int index)
+{
+ priv->emitChanged(QString::fromUtf8(name(index)), operator[](index));
+}
+
+void QDeclarativePropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
+{
+ priv->keys.append(QString::fromUtf8(b.name()));
+}
+
+/*!
+ \class QDeclarativePropertyMap
+ \since 4.7
+ \brief The QDeclarativePropertyMap class allows you to set key-value pairs that can be used in QML bindings.
+
+ QDeclarativePropertyMap provides a convenient way to expose domain data to the UI layer.
+ The following example shows how you might declare data in C++ and then
+ access it in QML.
+
+ In the C++ file:
+ \code
+ // create our data
+ QDeclarativePropertyMap ownerData;
+ ownerData.insert("name", QVariant(QString("John Smith")));
+ ownerData.insert("phone", QVariant(QString("555-5555")));
+
+ // expose it to the UI layer
+ QDeclarativeView view;
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("owner", &ownerData);
+
+ view.setSource(QUrl::fromLocalFile("main.qml"));
+ view.show();
+ \endcode
+
+ Then, in \c main.qml:
+ \code
+ Text { text: owner.name + " " + owner.phone }
+ \endcode
+
+ The binding is dynamic - whenever a key's value is updated, anything bound to that
+ key will be updated as well.
+
+ To detect value changes made in the UI layer you can connect to the valueChanged() signal.
+ However, note that valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+
+ \note It is not possible to remove keys from the map; once a key has been added, you can only
+ modify or clear its associated value.
+*/
+
+/*!
+ Constructs a bindable map with parent object \a parent.
+*/
+QDeclarativePropertyMap::QDeclarativePropertyMap(QObject *parent)
+: QObject(*(new QDeclarativePropertyMapPrivate), parent)
+{
+ Q_D(QDeclarativePropertyMap);
+ d->mo = new QDeclarativePropertyMapMetaObject(this, d);
+}
+
+/*!
+ Destroys the bindable map.
+*/
+QDeclarativePropertyMap::~QDeclarativePropertyMap()
+{
+}
+
+/*!
+ Clears the value (if any) associated with \a key.
+*/
+void QDeclarativePropertyMap::clear(const QString &key)
+{
+ Q_D(QDeclarativePropertyMap);
+ d->mo->setValue(key.toUtf8(), QVariant());
+}
+
+/*!
+ Returns the value associated with \a key.
+
+ If no value has been set for this key (or if the value has been cleared),
+ an invalid QVariant is returned.
+*/
+QVariant QDeclarativePropertyMap::value(const QString &key) const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->mo->value(key.toUtf8());
+}
+
+/*!
+ Sets the value associated with \a key to \a value.
+
+ If the key doesn't exist, it is automatically created.
+*/
+void QDeclarativePropertyMap::insert(const QString &key, const QVariant &value)
+{
+ Q_D(QDeclarativePropertyMap);
+ //The following strings shouldn't be used as property names
+ if (key != QLatin1String("keys")
+ && key != QLatin1String("valueChanged")
+ && key != QLatin1String("QObject")
+ && key != QLatin1String("destroyed")
+ && key != QLatin1String("deleteLater")) {
+ d->mo->setValue(key.toUtf8(), value);
+ } else {
+ qWarning() << "Creating property with name"
+ << key
+ << "is not permitted, conflicts with internal symbols.";
+ }
+}
+
+/*!
+ Returns the list of keys.
+
+ Keys that have been cleared will still appear in this list, even though their
+ associated values are invalid QVariants.
+*/
+QStringList QDeclarativePropertyMap::keys() const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->keys;
+}
+
+/*!
+ \overload
+
+ Same as size().
+*/
+int QDeclarativePropertyMap::count() const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->keys.count();
+}
+
+/*!
+ Returns the number of keys in the map.
+
+ \sa isEmpty(), count()
+*/
+int QDeclarativePropertyMap::size() const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->keys.size();
+}
+
+/*!
+ Returns true if the map contains no keys; otherwise returns
+ false.
+
+ \sa size()
+*/
+bool QDeclarativePropertyMap::isEmpty() const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->keys.isEmpty();
+}
+
+/*!
+ Returns true if the map contains \a key.
+
+ \sa size()
+*/
+bool QDeclarativePropertyMap::contains(const QString &key) const
+{
+ Q_D(const QDeclarativePropertyMap);
+ return d->keys.contains(key);
+}
+
+/*!
+ Returns the value associated with the key \a key as a modifiable
+ reference.
+
+ If the map contains no item with key \a key, the function inserts
+ an invalid QVariant into the map with key \a key, and
+ returns a reference to it.
+
+ \sa insert(), value()
+*/
+QVariant &QDeclarativePropertyMap::operator[](const QString &key)
+{
+ //### optimize
+ Q_D(QDeclarativePropertyMap);
+ QByteArray utf8key = key.toUtf8();
+ if (!d->keys.contains(key))
+ insert(key, QVariant());//force creation -- needed below
+
+ return (*(d->mo))[utf8key];
+}
+
+/*!
+ \overload
+
+ Same as value().
+*/
+QVariant QDeclarativePropertyMap::operator[](const QString &key) const
+{
+ return value(key);
+}
+
+/*!
+ \fn void QDeclarativePropertyMap::valueChanged(const QString &key, const QVariant &value)
+ This signal is emitted whenever one of the values in the map is changed. \a key
+ is the key corresponding to the \a value that was changed.
+
+ \note valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepropertymap.h b/src/declarative/util/qdeclarativepropertymap.h
new file mode 100644
index 0000000000..21bf974b6a
--- /dev/null
+++ b/src/declarative/util/qdeclarativepropertymap.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 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 QDECLARATIVEPROPERTYMAP_H
+#define QDECLARATIVEPROPERTYMAP_H
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePropertyMapPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativePropertyMap : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativePropertyMap(QObject *parent = 0);
+ virtual ~QDeclarativePropertyMap();
+
+ QVariant value(const QString &key) const;
+ void insert(const QString &key, const QVariant &value);
+ void clear(const QString &key);
+
+ Q_INVOKABLE QStringList keys() const;
+
+ int count() const;
+ int size() const;
+ bool isEmpty() const;
+ bool contains(const QString &key) const;
+
+ QVariant &operator[](const QString &key);
+ QVariant operator[](const QString &key) const;
+
+Q_SIGNALS:
+ void valueChanged(const QString &key, const QVariant &value);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativePropertyMap)
+ Q_DISABLE_COPY(QDeclarativePropertyMap)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qdeclarativesmoothedanimation.cpp b/src/declarative/util/qdeclarativesmoothedanimation.cpp
new file mode 100644
index 0000000000..9def5b4ca8
--- /dev/null
+++ b/src/declarative/util/qdeclarativesmoothedanimation.cpp
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativesmoothedanimation_p.h"
+#include "private/qdeclarativesmoothedanimation_p_p.h"
+
+#include "private/qdeclarativeanimation_p_p.h"
+
+#include <qdeclarativeproperty.h>
+#include "private/qdeclarativeproperty_p.h"
+
+#include "private/qdeclarativeglobal_p.h"
+
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+#define DELAY_STOP_TIMER_INTERVAL 32
+
+QT_BEGIN_NAMESPACE
+
+QSmoothedAnimation::QSmoothedAnimation(QObject *parent)
+ : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1),
+ reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0),
+ trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0)
+{
+ delayedStopTimer.setInterval(DELAY_STOP_TIMER_INTERVAL);
+ delayedStopTimer.setSingleShot(true);
+ connect(&delayedStopTimer, SIGNAL(timeout()), this, SLOT(stop()));
+}
+
+void QSmoothedAnimation::restart()
+{
+ initialVelocity = trackVelocity;
+ if (state() != QAbstractAnimation::Running)
+ start();
+ else
+ init();
+}
+
+void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
+{
+ if (newState == QAbstractAnimation::Running)
+ init();
+}
+
+void QSmoothedAnimation::delayedStop()
+{
+ if (!delayedStopTimer.isActive())
+ delayedStopTimer.start();
+}
+
+int QSmoothedAnimation::duration() const
+{
+ return -1;
+}
+
+bool QSmoothedAnimation::recalc()
+{
+ s = to - initialValue;
+ vi = initialVelocity;
+
+ s = (invert? -1.0: 1.0) * s;
+
+ if (userDuration > 0 && velocity > 0) {
+ tf = s / velocity;
+ if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.);
+ } else if (userDuration > 0) {
+ tf = userDuration / 1000.;
+ } else if (velocity > 0) {
+ tf = s / velocity;
+ } else {
+ return false;
+ }
+
+ finalDuration = ceil(tf * 1000.0);
+
+ if (maximumEasingTime == 0) {
+ a = 0;
+ d = 0;
+ tp = 0;
+ td = tf;
+ vp = velocity;
+ sp = 0;
+ sd = s;
+ } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) {
+ qreal met = maximumEasingTime / 1000.;
+ td = tf - met;
+
+ qreal c1 = td;
+ qreal c2 = (tf - td) * vi - tf * velocity;
+ qreal c3 = -0.5 * (tf - td) * vi * vi;
+
+ qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+
+ vp = vp1;
+ a = vp / met;
+ d = a;
+ tp = (vp - vi) / a;
+ sp = vi * tp + 0.5 * a * tp * tp;
+ sd = sp + (td - tp) * vp;
+ } else {
+ qreal c1 = 0.25 * tf * tf;
+ qreal c2 = 0.5 * vi * tf - s;
+ qreal c3 = -0.25 * vi * vi;
+
+ qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+
+ qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
+ qreal vp1 = a1 * tp1 + vi;
+
+ qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
+
+ a = a1;
+ d = a1;
+ tp = tp1;
+ td = tp1;
+ vp = vp1;
+ sp = sp1;
+ sd = sp1;
+ }
+ return true;
+}
+
+qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
+{
+ qreal value;
+ if (time_seconds < tp) {
+ trackVelocity = vi + time_seconds * a;
+ value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
+ } else if (time_seconds < td) {
+ time_seconds -= tp;
+ trackVelocity = vp;
+ value = sp + time_seconds * vp;
+ } else if (time_seconds < tf) {
+ time_seconds -= td;
+ trackVelocity = vp - time_seconds * a;
+ value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
+ } else {
+ trackVelocity = 0;
+ value = s;
+ delayedStop();
+ }
+
+ // to normalize 's' between [0..1], divide 'value' by 's'
+ return value;
+}
+
+void QSmoothedAnimation::updateCurrentTime(int t)
+{
+ qreal time_seconds = qreal(t - lastTime) / 1000.;
+
+ qreal value = easeFollow(time_seconds);
+ value *= (invert? -1.0: 1.0);
+ QDeclarativePropertyPrivate::write(target, initialValue + value,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+}
+
+void QSmoothedAnimation::init()
+{
+ if (velocity == 0) {
+ stop();
+ return;
+ }
+
+ if (delayedStopTimer.isActive())
+ delayedStopTimer.stop();
+
+ initialValue = target.read().toReal();
+ lastTime = this->currentTime();
+
+ if (to == initialValue) {
+ stop();
+ return;
+ }
+
+ bool hasReversed = trackVelocity != 0. &&
+ ((!invert) == ((initialValue - to) > 0));
+
+ if (hasReversed) {
+ switch (reversingMode) {
+ default:
+ case QDeclarativeSmoothedAnimation::Eased:
+ initialVelocity = -trackVelocity;
+ break;
+ case QDeclarativeSmoothedAnimation::Sync:
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ trackVelocity = 0;
+ stop();
+ return;
+ case QDeclarativeSmoothedAnimation::Immediate:
+ initialVelocity = 0;
+ break;
+ }
+ }
+
+ trackVelocity = initialVelocity;
+
+ invert = (to < initialValue);
+
+ if (!recalc()) {
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ stop();
+ return;
+ }
+}
+
+/*!
+ \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits NumberAnimation
+ \brief The SmoothedAnimation element allows a property to smoothly track a value.
+
+ A SmoothedAnimation animates a property's value to a set target value
+ using an ease in/out quad easing curve. When the target value changes,
+ the easing curves used to animate between the old and new target values
+ are smoothly spliced together to create a smooth movement to the new
+ target value that maintains the current velocity.
+
+ The follow example shows one \l Rectangle tracking the position of another
+ using SmoothedAnimation. The green rectangle's \c x and \c y values are
+ bound to those of the red rectangle. Whenever these values change, the
+ green rectangle smoothly animates to its new position:
+
+ \snippet doc/src/snippets/declarative/smoothedanimation.qml 0
+
+ A SmoothedAnimation can be configured by setting the \l velocity at which the
+ animation should occur, or the \l duration that the animation should take.
+ If both the \l velocity and \l duration are specified, the one that results in
+ the quickest animation is chosen for each change in the target value.
+
+ For example, animating from 0 to 800 will take 4 seconds if a velocity
+ of 200 is set, will take 8 seconds with a duration of 8000 set, and will
+ take 4 seconds with both a velocity of 200 and a duration of 8000 set.
+ Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set,
+ will take 8 seconds with a duration of 8000 set, and will take 8 seconds
+ with both a velocity of 200 and a duration of 8000 set.
+
+ The default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the
+ value being animated is small, then the velocity will need to be adjusted
+ appropriately. For example, the opacity of an item ranges from 0 - 1.0.
+ To enable a smooth animation in this range the velocity will need to be
+ set to a value such as 0.5 units/second. Animating from 0 to 1.0 with a velocity
+ of 0.5 will take 2000 ms to complete.
+
+ Like any other animation element, a SmoothedAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa SpringAnimation, NumberAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent)
+: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent)
+{
+}
+
+QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation()
+{
+}
+
+QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate()
+ : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation)
+{
+ Q_Q(QDeclarativeSmoothedAnimation);
+ QDeclarative_setParent_noEvent(wrapperGroup, q);
+ QDeclarative_setParent_noEvent(anim, q);
+}
+
+void QDeclarativeSmoothedAnimationPrivate::updateRunningAnimations()
+{
+ foreach(QSmoothedAnimation* ease, activeAnimations.values()){
+ ease->maximumEasingTime = anim->maximumEasingTime;
+ ease->reversingMode = anim->reversingMode;
+ ease->velocity = anim->velocity;
+ ease->userDuration = anim->userDuration;
+ ease->init();
+ }
+}
+
+QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ return d->wrapperGroup;
+}
+
+void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ QDeclarativeNumberAnimation::transition(actions, modified, direction);
+
+ if (!d->actions)
+ return;
+
+ QSet<QAbstractAnimation*> anims;
+ for (int i = 0; i < d->actions->size(); i++) {
+ QSmoothedAnimation *ease;
+ bool needsRestart;
+ if (!d->activeAnimations.contains((*d->actions)[i].property)) {
+ ease = new QSmoothedAnimation();
+ d->wrapperGroup->addAnimation(ease);
+ d->activeAnimations.insert((*d->actions)[i].property, ease);
+ needsRestart = false;
+ } else {
+ ease = d->activeAnimations.value((*d->actions)[i].property);
+ needsRestart = true;
+ }
+ ease->target = (*d->actions)[i].property;
+ ease->to = (*d->actions)[i].toValue.toReal();
+
+ // copying public members from main value holder animation
+ ease->maximumEasingTime = d->anim->maximumEasingTime;
+ ease->reversingMode = d->anim->reversingMode;
+ ease->velocity = d->anim->velocity;
+ ease->userDuration = d->anim->userDuration;
+
+ ease->initialVelocity = ease->trackVelocity;
+
+ if (needsRestart)
+ ease->init();
+ anims.insert(ease);
+ }
+
+ for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) {
+ if (!anims.contains(d->wrapperGroup->animationAt(i))) {
+ QSmoothedAnimation *ease = static_cast<QSmoothedAnimation*>(d->wrapperGroup->animationAt(i));
+ d->activeAnimations.remove(ease->target);
+ d->wrapperGroup->takeAnimation(i);
+ delete ease;
+ }
+ }
+}
+
+/*!
+ \qmlproperty enumeration SmoothedAnimation::reversingMode
+
+ Sets how the SmoothedAnimation behaves if an animation direction is reversed.
+
+ Possible values are:
+
+ \list
+ \o SmoothedAnimation.Eased (default) - the animation will smoothly decelerate, and then reverse direction
+ \o SmoothedAnimation.Immediate - the animation will immediately begin accelerating in the reverse direction, beginning with a velocity of 0
+ \o SmoothedAnimation.Sync - the property is immediately set to the target value
+ \endlist
+*/
+QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode;
+}
+
+void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->reversingMode == m)
+ return;
+
+ d->anim->reversingMode = m;
+ emit reversingModeChanged();
+ d->updateRunningAnimations();
+}
+
+/*!
+ \qmlproperty int SmoothedAnimation::duration
+
+ This property holds the animation duration, in msecs, used when tracking the source.
+
+ Setting this to -1 (the default) disables the duration value.
+
+ If the velocity value and the duration value are both enabled, then the animation will
+ use whichever gives the shorter duration.
+*/
+int QDeclarativeSmoothedAnimation::duration() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->userDuration;
+}
+
+void QDeclarativeSmoothedAnimation::setDuration(int duration)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (duration != -1)
+ QDeclarativeNumberAnimation::setDuration(duration);
+ if(duration == d->anim->userDuration)
+ return;
+ d->anim->userDuration = duration;
+ d->updateRunningAnimations();
+}
+
+qreal QDeclarativeSmoothedAnimation::velocity() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->velocity;
+}
+
+/*!
+ \qmlproperty real SmoothedAnimation::velocity
+
+ This property holds the average velocity allowed when tracking the 'to' value.
+
+ The default velocity of SmoothedAnimation is 200 units/second.
+
+ Setting this to -1 disables the velocity value.
+
+ If the velocity value and the duration value are both enabled, then the animation will
+ use whichever gives the shorter duration.
+*/
+void QDeclarativeSmoothedAnimation::setVelocity(qreal v)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->velocity == v)
+ return;
+
+ d->anim->velocity = v;
+ emit velocityChanged();
+ d->updateRunningAnimations();
+}
+
+/*!
+ \qmlproperty int SmoothedAnimation::maximumEasingTime
+
+ This property specifies the maximum time, in msecs, any "eases" during the follow should take.
+ Setting this property causes the velocity to "level out" after at a time. Setting
+ a negative value reverts to the normal mode of easing over the entire animation
+ duration.
+
+ The default value is -1.
+*/
+int QDeclarativeSmoothedAnimation::maximumEasingTime() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->maximumEasingTime;
+}
+
+void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if(v == d->anim->maximumEasingTime)
+ return;
+ d->anim->maximumEasingTime = v;
+ emit maximumEasingTimeChanged();
+ d->updateRunningAnimations();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativesmoothedanimation_p.h b/src/declarative/util/qdeclarativesmoothedanimation_p.h
new file mode 100644
index 0000000000..259f118039
--- /dev/null
+++ b/src/declarative/util/qdeclarativesmoothedanimation_p.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 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 QDECLARATIVESMOOTHEDANIMATION_H
+#define QDECLARATIVESMOOTHEDANIMATION_H
+
+#include <qdeclarative.h>
+#include "private/qdeclarativeanimation_p.h"
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeProperty;
+class QDeclarativeSmoothedAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSmoothedAnimation : public QDeclarativeNumberAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeSmoothedAnimation)
+ Q_ENUMS(ReversingMode)
+
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged)
+ Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged)
+
+public:
+ enum ReversingMode { Eased, Immediate, Sync };
+
+ QDeclarativeSmoothedAnimation(QObject *parent = 0);
+ ~QDeclarativeSmoothedAnimation();
+
+ ReversingMode reversingMode() const;
+ void setReversingMode(ReversingMode);
+
+ virtual int duration() const;
+ virtual void setDuration(int);
+
+ qreal velocity() const;
+ void setVelocity(qreal);
+
+ int maximumEasingTime() const;
+ void setMaximumEasingTime(int);
+
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ QAbstractAnimation* qtAnimation();
+
+Q_SIGNALS:
+ void velocityChanged();
+ void reversingModeChanged();
+ void maximumEasingTimeChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSmoothedAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESMOOTHEDANIMATION_H
diff --git a/src/declarative/util/qdeclarativesmoothedanimation_p_p.h b/src/declarative/util/qdeclarativesmoothedanimation_p_p.h
new file mode 100644
index 0000000000..cf3dadc9d6
--- /dev/null
+++ b/src/declarative/util/qdeclarativesmoothedanimation_p_p.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 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 QDECLARATIVESMOOTHEDANIMATION_P_H
+#define QDECLARATIVESMOOTHEDANIMATION_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/qdeclarativesmoothedanimation_p.h"
+#include "private/qdeclarativeanimation_p.h"
+
+#include "private/qdeclarativeanimation_p_p.h"
+
+#include <qparallelanimationgroup.h>
+
+#include <private/qobject_p.h>
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QSmoothedAnimation : public QAbstractAnimation
+{
+public:
+ QSmoothedAnimation(QObject *parent=0);
+
+ qreal to;
+ qreal velocity;
+ int userDuration;
+
+ int maximumEasingTime;
+ QDeclarativeSmoothedAnimation::ReversingMode reversingMode;
+
+ qreal initialVelocity;
+ qreal trackVelocity;
+
+ QDeclarativeProperty target;
+
+ int duration() const;
+ void restart();
+ void init();
+
+protected:
+ virtual void updateCurrentTime(int);
+ virtual void updateState(QAbstractAnimation::State, QAbstractAnimation::State);
+
+private:
+ qreal easeFollow(qreal);
+ qreal initialValue;
+
+ bool invert;
+
+ int finalDuration;
+
+ // Parameters for use in updateCurrentTime()
+ qreal a; // Acceleration
+ qreal d; // Deceleration
+ qreal tf; // Total time
+ qreal tp; // Time at which peak velocity occurs
+ qreal td; // Time at which decelleration begins
+ qreal vp; // Velocity at tp
+ qreal sp; // Displacement at tp
+ qreal sd; // Displacement at td
+ qreal vi; // "Normalized" initialvelocity
+ qreal s; // Total s
+
+ int lastTime;
+
+ bool recalc();
+ void delayedStop();
+
+ QTimer delayedStopTimer;
+};
+
+class QDeclarativeSmoothedAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeSmoothedAnimation)
+public:
+ QDeclarativeSmoothedAnimationPrivate();
+ void updateRunningAnimations();
+
+ QParallelAnimationGroup *wrapperGroup;
+ QSmoothedAnimation *anim;
+ QHash<QDeclarativeProperty, QSmoothedAnimation*> activeAnimations;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESMOOTHEDANIMATION_P_H
diff --git a/src/declarative/util/qdeclarativespringanimation.cpp b/src/declarative/util/qdeclarativespringanimation.cpp
new file mode 100644
index 0000000000..bb58b0a7c4
--- /dev/null
+++ b/src/declarative/util/qdeclarativespringanimation.cpp
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativespringanimation_p.h"
+
+#include "private/qdeclarativeanimation_p_p.h"
+#include <qdeclarativeproperty_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+#include <limits.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QDeclarativeSpringAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeSpringAnimation)
+public:
+
+
+ struct SpringAnimation {
+ SpringAnimation()
+ : currentValue(0), to(0), velocity(0), start(0), duration(0) {}
+ qreal currentValue;
+ qreal to;
+ qreal velocity;
+ int start;
+ int duration;
+ };
+ QHash<QDeclarativeProperty, SpringAnimation> activeAnimations;
+
+ qreal maxVelocity;
+ qreal velocityms;
+ int lastTime;
+ qreal mass;
+ qreal spring;
+ qreal damping;
+ qreal epsilon;
+ qreal modulus;
+
+ bool useMass : 1;
+ bool haveModulus : 1;
+
+ enum Mode {
+ Track,
+ Velocity,
+ Spring
+ };
+ Mode mode;
+
+ QDeclarativeSpringAnimationPrivate()
+ : maxVelocity(0), velocityms(0), lastTime(0)
+ , mass(1.0), spring(0.), damping(0.), epsilon(0.01)
+ , modulus(0.0), useMass(false), haveModulus(false)
+ , mode(Track), clock(0)
+ { }
+
+ void tick(int time);
+ bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed);
+ void updateMode();
+
+ typedef QTickAnimationProxy<QDeclarativeSpringAnimationPrivate, &QDeclarativeSpringAnimationPrivate::tick> Clock;
+ Clock *clock;
+};
+
+void QDeclarativeSpringAnimationPrivate::tick(int time)
+{
+ if (mode == Track) {
+ clock->stop();
+ return;
+ }
+ int elapsed = time - lastTime;
+ if (!elapsed)
+ return;
+
+ if (mode == Spring) {
+ if (elapsed < 16) // capped at 62fps.
+ return;
+ int count = elapsed / 16;
+ lastTime = time - (elapsed - count * 16);
+ } else {
+ lastTime = time;
+ }
+
+ QMutableHashIterator<QDeclarativeProperty, SpringAnimation> it(activeAnimations);
+ while (it.hasNext()) {
+ it.next();
+ if (animate(it.key(), it.value(), elapsed))
+ it.remove();
+ }
+
+ if (activeAnimations.isEmpty())
+ clock->stop();
+}
+
+bool QDeclarativeSpringAnimationPrivate::animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed)
+{
+ qreal srcVal = animation.to;
+
+ bool stop = false;
+
+ if (haveModulus) {
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ srcVal = fmod(srcVal, modulus);
+ }
+ if (mode == Spring) {
+ // Real men solve the spring DEs using RK4.
+ // We'll do something much simpler which gives a result that looks fine.
+ int count = elapsed / 16;
+ for (int i = 0; i < count; ++i) {
+ qreal diff = srcVal - animation.currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (useMass)
+ animation.velocity = animation.velocity + (spring * diff - damping * animation.velocity) / mass;
+ else
+ animation.velocity = animation.velocity + spring * diff - damping * animation.velocity;
+ if (maxVelocity > 0.) {
+ // limit velocity
+ if (animation.velocity > maxVelocity)
+ animation.velocity = maxVelocity;
+ else if (animation.velocity < -maxVelocity)
+ animation.velocity = -maxVelocity;
+ }
+ animation.currentValue += animation.velocity * 16.0 / 1000.0;
+ if (haveModulus) {
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ if (animation.currentValue < 0.0)
+ animation.currentValue += modulus;
+ }
+ }
+ if (qAbs(animation.velocity) < epsilon && qAbs(srcVal - animation.currentValue) < epsilon) {
+ animation.velocity = 0.0;
+ animation.currentValue = srcVal;
+ stop = true;
+ }
+ } else {
+ qreal moveBy = elapsed * velocityms;
+ qreal diff = srcVal - animation.currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (diff > 0) {
+ animation.currentValue += moveBy;
+ if (haveModulus)
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ } else {
+ animation.currentValue -= moveBy;
+ if (haveModulus && animation.currentValue < 0.0)
+ animation.currentValue = fmod(animation.currentValue, modulus) + modulus;
+ }
+ if (lastTime - animation.start >= animation.duration) {
+ animation.currentValue = animation.to;
+ stop = true;
+ }
+ }
+
+ qreal old_to = animation.to;
+
+ QDeclarativePropertyPrivate::write(property, animation.currentValue,
+ QDeclarativePropertyPrivate::BypassInterceptor |
+ QDeclarativePropertyPrivate::DontRemoveBinding);
+
+ return (stop && old_to == animation.to); // do not stop if we got restarted
+}
+
+void QDeclarativeSpringAnimationPrivate::updateMode()
+{
+ if (spring == 0. && maxVelocity == 0.)
+ mode = Track;
+ else if (spring > 0.)
+ mode = Spring;
+ else {
+ mode = Velocity;
+ QHash<QDeclarativeProperty, SpringAnimation>::iterator it;
+ for (it = activeAnimations.begin(); it != activeAnimations.end(); ++it) {
+ SpringAnimation &animation = *it;
+ animation.start = lastTime;
+ qreal dist = qAbs(animation.currentValue - animation.to);
+ if (haveModulus && dist > modulus / 2)
+ dist = modulus - fmod(dist, modulus);
+ animation.duration = dist / velocityms;
+ }
+ }
+}
+
+/*!
+ \qmlclass SpringAnimation QDeclarativeSpringAnimation
+ \ingroup qml-animation-transition
+ \inherits NumberAnimation
+ \since 4.7
+
+ \brief The SpringAnimation element allows a property to track a value in a spring-like motion.
+
+ SpringAnimation mimics the oscillatory behavior of a spring, with the appropriate \l spring constant to
+ control the acceleration and the \l damping to control how quickly the effect dies away.
+
+ You can also limit the maximum \l velocity of the animation.
+
+ The following \l Rectangle moves to the position of the mouse using a
+ SpringAnimation when the mouse is clicked. The use of the \l Behavior
+ on the \c x and \c y values indicates that whenever these values are
+ changed, a SpringAnimation should be applied.
+
+ \snippet doc/src/snippets/declarative/springanimation.qml 0
+
+ Like any other animation element, a SpringAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa SmoothedAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example}
+*/
+
+QDeclarativeSpringAnimation::QDeclarativeSpringAnimation(QObject *parent)
+: QDeclarativeNumberAnimation(*(new QDeclarativeSpringAnimationPrivate),parent)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->clock = new QDeclarativeSpringAnimationPrivate::Clock(d, this);
+}
+
+QDeclarativeSpringAnimation::~QDeclarativeSpringAnimation()
+{
+}
+
+/*!
+ \qmlproperty real SpringAnimation::velocity
+
+ This property holds the maximum velocity allowed when tracking the source.
+
+ The default value is 0 (no maximum velocity).
+*/
+
+qreal QDeclarativeSpringAnimation::velocity() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->maxVelocity;
+}
+
+void QDeclarativeSpringAnimation::setVelocity(qreal velocity)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->maxVelocity = velocity;
+ d->velocityms = velocity / 1000.0;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty real SpringAnimation::spring
+
+ This property describes how strongly the target is pulled towards the
+ source. The default value is 0 (that is, the spring-like motion is disabled).
+
+ The useful value range is 0 - 5.0.
+
+ When this property is set and the \l velocity value is greater than 0,
+ the \l velocity limits the maximum speed.
+*/
+qreal QDeclarativeSpringAnimation::spring() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->spring;
+}
+
+void QDeclarativeSpringAnimation::setSpring(qreal spring)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->spring = spring;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty real SpringAnimation::damping
+ This property holds the spring damping value.
+
+ This value describes how quickly the spring-like motion comes to rest.
+ The default value is 0.
+
+ The useful value range is 0 - 1.0. The lower the value, the faster it
+ comes to rest.
+*/
+qreal QDeclarativeSpringAnimation::damping() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->damping;
+}
+
+void QDeclarativeSpringAnimation::setDamping(qreal damping)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (damping > 1.)
+ damping = 1.;
+
+ d->damping = damping;
+}
+
+
+/*!
+ \qmlproperty real SpringAnimation::epsilon
+ This property holds the spring epsilon.
+
+ The epsilon is the rate and amount of change in the value which is close enough
+ to 0 to be considered equal to zero. This will depend on the usage of the value.
+ For pixel positions, 0.25 would suffice. For scale, 0.005 will suffice.
+
+ The default is 0.01. Tuning this value can provide small performance improvements.
+*/
+qreal QDeclarativeSpringAnimation::epsilon() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->epsilon;
+}
+
+void QDeclarativeSpringAnimation::setEpsilon(qreal epsilon)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->epsilon = epsilon;
+}
+
+/*!
+ \qmlproperty real SpringAnimation::modulus
+ This property holds the modulus value. The default value is 0.
+
+ Setting a \a modulus forces the target value to "wrap around" at the modulus.
+ For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10.
+*/
+qreal QDeclarativeSpringAnimation::modulus() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->modulus;
+}
+
+void QDeclarativeSpringAnimation::setModulus(qreal modulus)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (d->modulus != modulus) {
+ d->haveModulus = modulus != 0.0;
+ d->modulus = modulus;
+ d->updateMode();
+ emit modulusChanged();
+ }
+}
+
+/*!
+ \qmlproperty real SpringAnimation::mass
+ This property holds the "mass" of the property being moved.
+
+ The value is 1.0 by default.
+
+ A greater mass causes slower movement and a greater spring-like
+ motion when an item comes to rest.
+*/
+qreal QDeclarativeSpringAnimation::mass() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->mass;
+}
+
+void QDeclarativeSpringAnimation::setMass(qreal mass)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (d->mass != mass && mass > 0.0) {
+ d->useMass = mass != 1.0;
+ d->mass = mass;
+ emit massChanged();
+ }
+}
+
+void QDeclarativeSpringAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ Q_UNUSED(direction);
+
+ if (d->clock->state() != QAbstractAnimation::Running) {
+ d->lastTime = 0;
+ }
+
+ QDeclarativeNumberAnimation::transition(actions, modified, direction);
+
+ if (!d->actions)
+ return;
+
+ if (!d->actions->isEmpty()) {
+ for (int i = 0; i < d->actions->size(); ++i) {
+ const QDeclarativeProperty &property = d->actions->at(i).property;
+ QDeclarativeSpringAnimationPrivate::SpringAnimation &animation
+ = d->activeAnimations[property];
+ animation.to = d->actions->at(i).toValue.toReal();
+ animation.start = d->lastTime;
+ if (d->fromIsDefined)
+ animation.currentValue = d->actions->at(i).fromValue.toReal();
+ else
+ animation.currentValue = property.read().toReal();
+ if (d->mode == QDeclarativeSpringAnimationPrivate::Velocity) {
+ qreal dist = qAbs(animation.currentValue - animation.to);
+ if (d->haveModulus && dist > d->modulus / 2)
+ dist = d->modulus - fmod(dist, d->modulus);
+ animation.duration = dist / d->velocityms;
+ }
+ }
+ }
+}
+
+
+QAbstractAnimation *QDeclarativeSpringAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeSpringAnimation);
+ return d->clock;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativespringanimation_p.h b/src/declarative/util/qdeclarativespringanimation_p.h
new file mode 100644
index 0000000000..4073947e6f
--- /dev/null
+++ b/src/declarative/util/qdeclarativespringanimation_p.h
@@ -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 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 QDECLARATIVESPRINGANIMATION_H
+#define QDECLARATIVESPRINGANIMATION_H
+
+#include <qdeclarative.h>
+#include "private/qdeclarativeanimation_p.h"
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeSpringAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSpringAnimation : public QDeclarativeNumberAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeSpringAnimation)
+ Q_INTERFACES(QDeclarativePropertyValueSource)
+
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity)
+ Q_PROPERTY(qreal spring READ spring WRITE setSpring)
+ Q_PROPERTY(qreal damping READ damping WRITE setDamping)
+ Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon)
+ Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged)
+ Q_PROPERTY(qreal mass READ mass WRITE setMass NOTIFY massChanged)
+
+public:
+ QDeclarativeSpringAnimation(QObject *parent=0);
+ ~QDeclarativeSpringAnimation();
+
+ qreal velocity() const;
+ void setVelocity(qreal velocity);
+
+ qreal spring() const;
+ void setSpring(qreal spring);
+
+ qreal damping() const;
+ void setDamping(qreal damping);
+
+ qreal epsilon() const;
+ void setEpsilon(qreal epsilon);
+
+ qreal mass() const;
+ void setMass(qreal modulus);
+
+ qreal modulus() const;
+ void setModulus(qreal modulus);
+
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+
+protected:
+ virtual QAbstractAnimation *qtAnimation();
+
+Q_SIGNALS:
+ void modulusChanged();
+ void massChanged();
+ void syncChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSpringAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESPRINGANIMATION_H
diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp
new file mode 100644
index 0000000000..5718e29f90
--- /dev/null
+++ b/src/declarative/util/qdeclarativestate.cpp
@@ -0,0 +1,730 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativestate_p_p.h"
+#include "private/qdeclarativestate_p.h"
+
+#include "private/qdeclarativetransition_p.h"
+#include "private/qdeclarativestategroup_p.h"
+#include "private/qdeclarativestateoperations_p.h"
+#include "private/qdeclarativeanimation_p.h"
+#include "private/qdeclarativeanimation_p_p.h"
+
+#include <qdeclarativebinding_p.h>
+#include <qdeclarativeglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+QDeclarativeAction::QDeclarativeAction()
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), event(0),
+ specifiedObject(0)
+{
+}
+
+QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
+ const QVariant &value)
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
+ property(target, propertyName, qmlEngine(target)), toValue(value),
+ fromBinding(0), event(0),
+ specifiedObject(target), specifiedProperty(propertyName)
+{
+ if (property.isValid())
+ fromValue = property.read();
+}
+
+QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
+ QDeclarativeContext *context, const QVariant &value)
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
+ property(target, propertyName, context), toValue(value),
+ fromBinding(0), event(0),
+ specifiedObject(target), specifiedProperty(propertyName)
+{
+ if (property.isValid())
+ fromValue = property.read();
+}
+
+
+QDeclarativeActionEvent::~QDeclarativeActionEvent()
+{
+}
+
+QString QDeclarativeActionEvent::typeName() const
+{
+ return QString();
+}
+
+void QDeclarativeActionEvent::execute(Reason)
+{
+}
+
+bool QDeclarativeActionEvent::isReversable()
+{
+ return false;
+}
+
+void QDeclarativeActionEvent::reverse(Reason)
+{
+}
+
+bool QDeclarativeActionEvent::changesBindings()
+{
+ return false;
+}
+
+void QDeclarativeActionEvent::clearBindings()
+{
+}
+
+bool QDeclarativeActionEvent::override(QDeclarativeActionEvent *other)
+{
+ Q_UNUSED(other);
+ return false;
+}
+
+QDeclarativeStateOperation::QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlclass State QDeclarativeState
+ \ingroup qml-state-elements
+ \since 4.7
+ \brief The State element defines configurations of objects and properties.
+
+ A \e state is a set of batched changes from the default configuration.
+
+ All items have a default state that defines the default configuration of objects
+ and property values. New states can be defined by adding State items to the \l {Item::states}{states} property to
+ allow items to switch between different configurations. These configurations
+ can, for example, be used to apply different sets of property values or execute
+ different scripts.
+
+ The following example displays a single \l Rectangle. In the default state, the rectangle
+ is colored black. In the "clicked" state, a PropertyChanges element changes the
+ rectangle's color to red. Clicking within the MouseArea toggles the rectangle's state
+ between the default state and the "clicked" state, thus toggling the color of the
+ rectangle between black and red.
+
+ \snippet doc/src/snippets/declarative/state.qml 0
+
+ Notice the default state is referred to using an empty string ("").
+
+ States are commonly used together with \l{QML Animation and Transitions}{Transitions} to provide
+ animations when state changes occur.
+
+ \note Setting the state of an object from within another state of the same object is
+ not allowed.
+
+ \sa {declarative/animation/states}{states example}, {qmlstates}{States},
+ {QML Animation and Transitions}{Transitions}, QtDeclarative
+*/
+QDeclarativeState::QDeclarativeState(QObject *parent)
+: QObject(*(new QDeclarativeStatePrivate), parent)
+{
+ Q_D(QDeclarativeState);
+ d->transitionManager.setState(this);
+}
+
+QDeclarativeState::~QDeclarativeState()
+{
+ Q_D(QDeclarativeState);
+ if (d->group)
+ d->group->removeState(this);
+}
+
+/*!
+ \qmlproperty string State::name
+ This property holds the name of the state.
+
+ Each state should have a unique name within its item.
+*/
+QString QDeclarativeState::name() const
+{
+ Q_D(const QDeclarativeState);
+ return d->name;
+}
+
+void QDeclarativeState::setName(const QString &n)
+{
+ Q_D(QDeclarativeState);
+ d->name = n;
+ d->named = true;
+}
+
+bool QDeclarativeState::isNamed() const
+{
+ Q_D(const QDeclarativeState);
+ return d->named;
+}
+
+bool QDeclarativeState::isWhenKnown() const
+{
+ Q_D(const QDeclarativeState);
+ return d->when != 0;
+}
+
+/*!
+ \qmlproperty bool State::when
+ This property holds when the state should be applied.
+
+ This should be set to an expression that evaluates to \c true when you want the state to
+ be applied. For example, the following \l Rectangle changes in and out of the "hidden"
+ state when the \l MouseArea is pressed:
+
+ \snippet doc/src/snippets/declarative/state-when.qml 0
+
+ If multiple states in a group have \c when clauses that evaluate to \c true
+ at the same time, the first matching state will be applied. For example, in
+ the following snippet \c state1 will always be selected rather than
+ \c state2 when sharedCondition becomes \c true.
+ \qml
+ Item {
+ states: [
+ State { name: "state1"; when: sharedCondition },
+ State { name: "state2"; when: sharedCondition }
+ ]
+ // ...
+ }
+ \endqml
+*/
+QDeclarativeBinding *QDeclarativeState::when() const
+{
+ Q_D(const QDeclarativeState);
+ return d->when;
+}
+
+void QDeclarativeState::setWhen(QDeclarativeBinding *when)
+{
+ Q_D(QDeclarativeState);
+ d->when = when;
+ if (d->group)
+ d->group->updateAutoState();
+}
+
+/*!
+ \qmlproperty string State::extend
+ This property holds the state that this state extends.
+
+ When a state extends another state, it inherits all the changes of that state.
+
+ The state being extended is treated as the base state in regards to
+ the changes specified by the extending state.
+*/
+QString QDeclarativeState::extends() const
+{
+ Q_D(const QDeclarativeState);
+ return d->extends;
+}
+
+void QDeclarativeState::setExtends(const QString &extends)
+{
+ Q_D(QDeclarativeState);
+ d->extends = extends;
+}
+
+/*!
+ \qmlproperty list<Change> State::changes
+ This property holds the changes to apply for this state
+ \default
+
+ By default these changes are applied against the default state. If the state
+ extends another state, then the changes are applied against the state being
+ extended.
+*/
+QDeclarativeListProperty<QDeclarativeStateOperation> QDeclarativeState::changes()
+{
+ Q_D(QDeclarativeState);
+ return QDeclarativeListProperty<QDeclarativeStateOperation>(this, &d->operations, QDeclarativeStatePrivate::operations_append,
+ QDeclarativeStatePrivate::operations_count, QDeclarativeStatePrivate::operations_at,
+ QDeclarativeStatePrivate::operations_clear);
+}
+
+int QDeclarativeState::operationCount() const
+{
+ Q_D(const QDeclarativeState);
+ return d->operations.count();
+}
+
+QDeclarativeStateOperation *QDeclarativeState::operationAt(int index) const
+{
+ Q_D(const QDeclarativeState);
+ return d->operations.at(index);
+}
+
+QDeclarativeState &QDeclarativeState::operator<<(QDeclarativeStateOperation *op)
+{
+ Q_D(QDeclarativeState);
+ d->operations.append(QDeclarativeStatePrivate::OperationGuard(op, &d->operations));
+ return *this;
+}
+
+void QDeclarativeStatePrivate::complete()
+{
+ Q_Q(QDeclarativeState);
+
+ for (int ii = 0; ii < reverting.count(); ++ii) {
+ for (int jj = 0; jj < revertList.count(); ++jj) {
+ if (revertList.at(jj).property() == reverting.at(ii)) {
+ revertList.removeAt(jj);
+ break;
+ }
+ }
+ }
+ reverting.clear();
+
+ emit q->completed();
+}
+
+// Generate a list of actions for this state. This includes coelescing state
+// actions that this state "extends"
+QDeclarativeStateOperation::ActionList
+QDeclarativeStatePrivate::generateActionList(QDeclarativeStateGroup *group) const
+{
+ QDeclarativeStateOperation::ActionList applyList;
+ if (inState)
+ return applyList;
+
+ // Prevent "extends" recursion
+ inState = true;
+
+ if (!extends.isEmpty()) {
+ QList<QDeclarativeState *> states = group->states();
+ for (int ii = 0; ii < states.count(); ++ii)
+ if (states.at(ii)->name() == extends) {
+ qmlExecuteDeferred(states.at(ii));
+ applyList = static_cast<QDeclarativeStatePrivate*>(states.at(ii)->d_func())->generateActionList(group);
+ }
+ }
+
+ foreach(QDeclarativeStateOperation *op, operations)
+ applyList << op->actions();
+
+ inState = false;
+ return applyList;
+}
+
+QDeclarativeStateGroup *QDeclarativeState::stateGroup() const
+{
+ Q_D(const QDeclarativeState);
+ return d->group;
+}
+
+void QDeclarativeState::setStateGroup(QDeclarativeStateGroup *group)
+{
+ Q_D(QDeclarativeState);
+ d->group = group;
+}
+
+void QDeclarativeState::cancel()
+{
+ Q_D(QDeclarativeState);
+ d->transitionManager.cancel();
+}
+
+void QDeclarativeAction::deleteFromBinding()
+{
+ if (fromBinding) {
+ QDeclarativePropertyPrivate::setBinding(property, 0);
+ fromBinding->destroy();
+ fromBinding = 0;
+ }
+}
+
+bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
+ simpleAction.setValue(revertValue);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
+ if (simpleAction.binding())
+ simpleAction.binding()->destroy();
+
+ simpleAction.setBinding(binding);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QString &name)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target && simpleAction.property().name() == name) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void QDeclarativeState::addEntryToRevertList(const QDeclarativeAction &action)
+{
+ Q_D(QDeclarativeState);
+
+ QDeclarativeSimpleAction simpleAction(action);
+
+ d->revertList.append(simpleAction);
+}
+
+void QDeclarativeState::removeAllEntriesFromRevertList(QObject *target)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ }
+ }
+ }
+}
+
+void QDeclarativeState::addEntriesToRevertList(const QList<QDeclarativeAction> &actionList)
+{
+ Q_D(QDeclarativeState);
+ if (isStateActive()) {
+ QList<QDeclarativeSimpleAction> simpleActionList;
+
+ QListIterator<QDeclarativeAction> actionListIterator(actionList);
+ while(actionListIterator.hasNext()) {
+ const QDeclarativeAction &action = actionListIterator.next();
+ QDeclarativeSimpleAction simpleAction(action);
+ action.property.write(action.toValue);
+ if (!action.toBinding.isNull()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding)
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), action.toBinding.data(), QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+
+ simpleActionList.append(simpleAction);
+ }
+
+ d->revertList.append(simpleActionList);
+ }
+}
+
+QVariant QDeclarativeState::valueInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return simpleAction.value();
+ }
+ }
+
+ return QVariant();
+}
+
+QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return simpleAction.binding();
+ }
+ }
+
+ return 0;
+}
+
+bool QDeclarativeState::isStateActive() const
+{
+ return stateGroup() && stateGroup()->state() == name();
+}
+
+void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransition *trans, QDeclarativeState *revert)
+{
+ Q_D(QDeclarativeState);
+
+ qmlExecuteDeferred(this);
+
+ cancel();
+ if (revert)
+ revert->cancel();
+ d->revertList.clear();
+ d->reverting.clear();
+
+ if (revert) {
+ QDeclarativeStatePrivate *revertPrivate =
+ static_cast<QDeclarativeStatePrivate*>(revert->d_func());
+ d->revertList = revertPrivate->revertList;
+ revertPrivate->revertList.clear();
+ }
+
+ // List of actions caused by this state
+ QDeclarativeStateOperation::ActionList applyList = d->generateActionList(group);
+
+ // List of actions that need to be reverted to roll back (just) this state
+ QDeclarativeStatePrivate::SimpleActionList additionalReverts;
+ // First add the reverse of all the applyList actions
+ for (int ii = 0; ii < applyList.count(); ++ii) {
+ QDeclarativeAction &action = applyList[ii];
+
+ if (action.event) {
+ if (!action.event->isReversable())
+ continue;
+ bool found = false;
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
+ QDeclarativeActionEvent *event = d->revertList.at(jj).event();
+ if (event && event->typeName() == action.event->typeName()) {
+ if (action.event->override(event)) {
+ found = true;
+
+ if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) {
+ action.event->copyOriginals(d->revertList.at(jj).event());
+
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ d->revertList.removeAt(jj);
+ --jj;
+ } else if (action.event->isRewindable()) //###why needed?
+ action.event->saveCurrentValues();
+
+ break;
+ }
+ }
+ }
+ if (!found) {
+ action.event->saveOriginals();
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
+ } else {
+ bool found = false;
+ action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
+
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
+ if (d->revertList.at(jj).property() == action.property) {
+ found = true;
+ if (d->revertList.at(jj).binding() != action.fromBinding) {
+ action.deleteFromBinding();
+ }
+ break;
+ }
+ }
+
+ if (!found) {
+ if (!action.restore) {
+ action.deleteFromBinding();;
+ } else {
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
+ }
+ }
+ }
+
+ // Any reverts from a previous state that aren't carried forth
+ // into this state need to be translated into apply actions
+ for (int ii = 0; ii < d->revertList.count(); ++ii) {
+ bool found = false;
+ if (d->revertList.at(ii).event()) {
+ QDeclarativeActionEvent *event = d->revertList.at(ii).event();
+ if (!event->isReversable())
+ continue;
+ for (int jj = 0; !found && jj < applyList.count(); ++jj) {
+ const QDeclarativeAction &action = applyList.at(jj);
+ if (action.event && action.event->typeName() == event->typeName()) {
+ if (action.event->override(event))
+ found = true;
+ }
+ }
+ } else {
+ for (int jj = 0; !found && jj < applyList.count(); ++jj) {
+ const QDeclarativeAction &action = applyList.at(jj);
+ if (action.property == d->revertList.at(ii).property())
+ found = true;
+ }
+ }
+ if (!found) {
+ QVariant cur = d->revertList.at(ii).property().read();
+ QDeclarativeAbstractBinding *delBinding =
+ QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0);
+ if (delBinding)
+ delBinding->destroy();
+
+ QDeclarativeAction a;
+ a.property = d->revertList.at(ii).property();
+ a.fromValue = cur;
+ a.toValue = d->revertList.at(ii).value();
+ a.toBinding = QDeclarativeAbstractBinding::getPointer(d->revertList.at(ii).binding());
+ a.specifiedObject = d->revertList.at(ii).specifiedObject();
+ a.specifiedProperty = d->revertList.at(ii).specifiedProperty();
+ a.event = d->revertList.at(ii).event();
+ a.reverseEvent = d->revertList.at(ii).reverseEvent();
+ if (a.event && a.event->isRewindable())
+ a.event->saveCurrentValues();
+ applyList << a;
+ // Store these special reverts in the reverting list
+ d->reverting << d->revertList.at(ii).property();
+ }
+ }
+ // All the local reverts now become part of the ongoing revertList
+ d->revertList << additionalReverts;
+
+#ifndef QT_NO_DEBUG_STREAM
+ // Output for debugging
+ if (stateChangeDebug()) {
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event)
+ qWarning() << " QDeclarativeAction event:" << action.event->typeName();
+ else
+ qWarning() << " QDeclarativeAction:" << action.property.object()
+ << action.property.name() << "From:" << action.fromValue
+ << "To:" << action.toValue;
+ }
+ }
+#endif
+
+ d->transitionManager.transition(applyList, trans);
+}
+
+QDeclarativeStateOperation::ActionList QDeclarativeStateOperation::actions()
+{
+ return ActionList();
+}
+
+QDeclarativeState *QDeclarativeStateOperation::state() const
+{
+ Q_D(const QDeclarativeStateOperation);
+ return d->m_state;
+}
+
+void QDeclarativeStateOperation::setState(QDeclarativeState *state)
+{
+ Q_D(QDeclarativeStateOperation);
+ d->m_state = state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativestate_p.h b/src/declarative/util/qdeclarativestate_p.h
new file mode 100644
index 0000000000..60d0e0b046
--- /dev/null
+++ b/src/declarative/util/qdeclarativestate_p.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESTATE_H
+#define QDECLARATIVESTATE_H
+
+#include <qdeclarative.h>
+#include <qdeclarativeproperty.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsharedpointer.h>
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeActionEvent;
+class QDeclarativeAbstractBinding;
+class QDeclarativeBinding;
+class QDeclarativeExpression;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAction
+{
+public:
+ QDeclarativeAction();
+ QDeclarativeAction(QObject *, const QString &, const QVariant &);
+ QDeclarativeAction(QObject *, const QString &,
+ QDeclarativeContext *, const QVariant &);
+
+ bool restore:1;
+ bool actionDone:1;
+ bool reverseEvent:1;
+ bool deletableToBinding:1;
+
+ QDeclarativeProperty property;
+ QVariant fromValue;
+ QVariant toValue;
+
+ QDeclarativeAbstractBinding *fromBinding;
+ QWeakPointer<QDeclarativeAbstractBinding> toBinding;
+ QDeclarativeActionEvent *event;
+
+ //strictly for matching
+ QObject *specifiedObject;
+ QString specifiedProperty;
+
+ void deleteFromBinding();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeActionEvent
+{
+public:
+ virtual ~QDeclarativeActionEvent();
+ virtual QString typeName() const;
+
+ enum Reason { ActualChange, FastForward };
+
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual void saveOriginals() {}
+ virtual bool needsCopy() { return false; }
+ virtual void copyOriginals(QDeclarativeActionEvent *) {}
+
+ virtual bool isRewindable() { return isReversable(); }
+ virtual void rewind() {}
+ virtual void saveCurrentValues() {}
+ virtual void saveTargetValues() {}
+
+ virtual bool changesBindings();
+ virtual void clearBindings();
+ virtual bool override(QDeclarativeActionEvent*other);
+};
+
+//### rename to QDeclarativeStateChange?
+class QDeclarativeStateGroup;
+class QDeclarativeState;
+class QDeclarativeStateOperationPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeStateOperation : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeStateOperation(QObject *parent = 0)
+ : QObject(parent) {}
+ typedef QList<QDeclarativeAction> ActionList;
+
+ virtual ActionList actions();
+
+ QDeclarativeState *state() const;
+ void setState(QDeclarativeState *state);
+
+protected:
+ QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeStateOperation)
+ Q_DISABLE_COPY(QDeclarativeStateOperation)
+};
+
+typedef QDeclarativeStateOperation::ActionList QDeclarativeStateActions;
+
+class QDeclarativeTransition;
+class QDeclarativeStatePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeState : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QDeclarativeBinding *when READ when WRITE setWhen)
+ Q_PROPERTY(QString extend READ extends WRITE setExtends)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeStateOperation> changes READ changes)
+ Q_CLASSINFO("DefaultProperty", "changes")
+ Q_CLASSINFO("DeferredPropertyNames", "changes")
+
+public:
+ QDeclarativeState(QObject *parent=0);
+ virtual ~QDeclarativeState();
+
+ QString name() const;
+ void setName(const QString &);
+ bool isNamed() const;
+
+ /*'when' is a QDeclarativeBinding to limit state changes oscillation
+ due to the unpredictable order of evaluation of bound expressions*/
+ bool isWhenKnown() const;
+ QDeclarativeBinding *when() const;
+ void setWhen(QDeclarativeBinding *);
+
+ QString extends() const;
+ void setExtends(const QString &);
+
+ QDeclarativeListProperty<QDeclarativeStateOperation> changes();
+ int operationCount() const;
+ QDeclarativeStateOperation *operationAt(int) const;
+
+ QDeclarativeState &operator<<(QDeclarativeStateOperation *);
+
+ void apply(QDeclarativeStateGroup *, QDeclarativeTransition *, QDeclarativeState *revert);
+ void cancel();
+
+ QDeclarativeStateGroup *stateGroup() const;
+ void setStateGroup(QDeclarativeStateGroup *);
+
+ bool containsPropertyInRevertList(QObject *target, const QString &name) const;
+ bool changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue);
+ bool changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding);
+ bool removeEntryFromRevertList(QObject *target, const QString &name);
+ void addEntryToRevertList(const QDeclarativeAction &action);
+ void removeAllEntriesFromRevertList(QObject *target);
+ void addEntriesToRevertList(const QList<QDeclarativeAction> &actions);
+ QVariant valueInRevertList(QObject *target, const QString &name) const;
+ QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QString &name) const;
+
+ bool isStateActive() const;
+
+Q_SIGNALS:
+ void completed();
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeState)
+ Q_DISABLE_COPY(QDeclarativeState)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeStateOperation)
+QML_DECLARE_TYPE(QDeclarativeState)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATE_H
diff --git a/src/declarative/util/qdeclarativestate_p_p.h b/src/declarative/util/qdeclarativestate_p_p.h
new file mode 100644
index 0000000000..888159ea44
--- /dev/null
+++ b/src/declarative/util/qdeclarativestate_p_p.h
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESTATE_P_H
+#define QDECLARATIVESTATE_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/qdeclarativestate_p.h"
+
+#include "private/qdeclarativeanimation_p_p.h"
+#include "private/qdeclarativetransitionmanager_p_p.h"
+
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+#include <private/qdeclarativebinding_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSimpleAction
+{
+public:
+ enum State { StartState, EndState };
+ QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState)
+ {
+ m_property = a.property;
+ m_specifiedObject = a.specifiedObject;
+ m_specifiedProperty = a.specifiedProperty;
+ m_event = a.event;
+ if (state == StartState) {
+ m_value = a.fromValue;
+ if (QDeclarativePropertyPrivate::binding(m_property)) {
+ m_binding = QDeclarativeAbstractBinding::getPointer(QDeclarativePropertyPrivate::binding(m_property));
+ }
+ m_reverseEvent = true;
+ } else {
+ m_value = a.toValue;
+ m_binding = a.toBinding;
+ m_reverseEvent = false;
+ }
+ }
+
+ ~QDeclarativeSimpleAction()
+ {
+ }
+
+ QDeclarativeSimpleAction(const QDeclarativeSimpleAction &other)
+ : m_property(other.m_property),
+ m_value(other.m_value),
+ m_binding(QDeclarativeAbstractBinding::getPointer(other.binding())),
+ m_specifiedObject(other.m_specifiedObject),
+ m_specifiedProperty(other.m_specifiedProperty),
+ m_event(other.m_event),
+ m_reverseEvent(other.m_reverseEvent)
+ {
+ }
+
+ QDeclarativeSimpleAction &operator =(const QDeclarativeSimpleAction &other)
+ {
+ m_property = other.m_property;
+ m_value = other.m_value;
+ m_binding = QDeclarativeAbstractBinding::getPointer(other.binding());
+ m_specifiedObject = other.m_specifiedObject;
+ m_specifiedProperty = other.m_specifiedProperty;
+ m_event = other.m_event;
+ m_reverseEvent = other.m_reverseEvent;
+
+ return *this;
+ }
+
+ void setProperty(const QDeclarativeProperty &property)
+ {
+ m_property = property;
+ }
+
+ const QDeclarativeProperty &property() const
+ {
+ return m_property;
+ }
+
+ void setValue(const QVariant &value)
+ {
+ m_value = value;
+ }
+
+ const QVariant &value() const
+ {
+ return m_value;
+ }
+
+ void setBinding(QDeclarativeAbstractBinding *binding)
+ {
+ m_binding = QDeclarativeAbstractBinding::getPointer(binding);
+ }
+
+ QDeclarativeAbstractBinding *binding() const
+ {
+ return m_binding.data();
+ }
+
+ QObject *specifiedObject() const
+ {
+ return m_specifiedObject;
+ }
+
+ const QString &specifiedProperty() const
+ {
+ return m_specifiedProperty;
+ }
+
+ QDeclarativeActionEvent *event() const
+ {
+ return m_event;
+ }
+
+ bool reverseEvent() const
+ {
+ return m_reverseEvent;
+ }
+
+private:
+ QDeclarativeProperty m_property;
+ QVariant m_value;
+ QDeclarativeAbstractBinding::Pointer m_binding;
+ QObject *m_specifiedObject;
+ QString m_specifiedProperty;
+ QDeclarativeActionEvent *m_event;
+ bool m_reverseEvent;
+};
+
+class QDeclarativeStateOperationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeStateOperation)
+
+public:
+
+ QDeclarativeStateOperationPrivate()
+ : m_state(0) {}
+
+ QDeclarativeState *m_state;
+};
+
+class QDeclarativeStatePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeState)
+
+public:
+ QDeclarativeStatePrivate()
+ : when(0), named(false), inState(false), group(0) {}
+
+ typedef QList<QDeclarativeSimpleAction> SimpleActionList;
+
+ QString name;
+ QDeclarativeBinding *when;
+ bool named;
+
+ struct OperationGuard : public QDeclarativeGuard<QDeclarativeStateOperation>
+ {
+ OperationGuard(QObject *obj, QList<OperationGuard> *l) : list(l) { (QDeclarativeGuard<QObject>&)*this = obj; }
+ QList<OperationGuard> *list;
+ void objectDestroyed(QDeclarativeStateOperation *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+ QList<OperationGuard> operations;
+
+ static void operations_append(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, QDeclarativeStateOperation *op) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ op->setState(qobject_cast<QDeclarativeState*>(prop->object));
+ list->append(OperationGuard(op, list));
+ }
+ static void operations_clear(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ QMutableListIterator<OperationGuard> listIterator(*list);
+ while(listIterator.hasNext())
+ listIterator.next()->setState(0);
+ list->clear();
+ }
+ static int operations_count(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ return list->count();
+ }
+ static QDeclarativeStateOperation *operations_at(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, int index) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ return list->at(index);
+ }
+
+ QDeclarativeTransitionManager transitionManager;
+
+ SimpleActionList revertList;
+ QList<QDeclarativeProperty> reverting;
+ QString extends;
+ mutable bool inState;
+ QDeclarativeStateGroup *group;
+
+ QDeclarativeStateOperation::ActionList generateActionList(QDeclarativeStateGroup *) const;
+ void complete();
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESTATE_P_H
diff --git a/src/declarative/util/qdeclarativestategroup.cpp b/src/declarative/util/qdeclarativestategroup.cpp
new file mode 100644
index 0000000000..6459bf9ae3
--- /dev/null
+++ b/src/declarative/util/qdeclarativestategroup.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativestategroup_p.h"
+
+#include "private/qdeclarativetransition_p.h"
+#include "private/qdeclarativestate_p_p.h"
+
+#include <qdeclarativebinding_p.h>
+#include <qdeclarativeglobal_p.h>
+
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+class QDeclarativeStateGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeStateGroup)
+public:
+ QDeclarativeStateGroupPrivate()
+ : nullState(0), componentComplete(true),
+ ignoreTrans(false), applyingState(false), unnamedCount(0) {}
+
+ QString currentState;
+ QDeclarativeState *nullState;
+
+ static void append_state(QDeclarativeListProperty<QDeclarativeState> *list, QDeclarativeState *state);
+ static int count_state(QDeclarativeListProperty<QDeclarativeState> *list);
+ static QDeclarativeState *at_state(QDeclarativeListProperty<QDeclarativeState> *list, int index);
+ static void clear_states(QDeclarativeListProperty<QDeclarativeState> *list);
+
+ QList<QDeclarativeState *> states;
+ QList<QDeclarativeTransition *> transitions;
+
+ bool componentComplete;
+ bool ignoreTrans;
+ bool applyingState;
+ int unnamedCount;
+
+ QDeclarativeTransition *findTransition(const QString &from, const QString &to);
+ void setCurrentStateInternal(const QString &state, bool = false);
+ bool updateAutoState();
+};
+
+/*!
+ \qmlclass StateGroup QDeclarativeStateGroup
+ \ingroup qml-state-elements
+ \since 4.7
+ \brief The StateGroup element provides state support for non-Item elements.
+
+ Item (and all derived elements) provides built in support for states and transitions
+ via its \l{Item::state}{state}, \l{Item::states}{states} and \l{Item::transitions}{transitions} properties. StateGroup provides an easy way to
+ use this support in other (non-Item-derived) elements.
+
+ \qml
+ MyCustomObject {
+ StateGroup {
+ id: myStateGroup
+ states: State {
+ name: "state1"
+ // ...
+ }
+ transitions: Transition {
+ // ...
+ }
+ }
+
+ onSomethingHappened: myStateGroup.state = "state1";
+ }
+ \endqml
+
+ \sa {qmlstate}{States} {QML Animation and Transitions}{Transitions}, {QtDeclarative}
+*/
+
+QDeclarativeStateGroup::QDeclarativeStateGroup(QObject *parent)
+ : QObject(*(new QDeclarativeStateGroupPrivate), parent)
+{
+}
+
+QDeclarativeStateGroup::~QDeclarativeStateGroup()
+{
+ Q_D(const QDeclarativeStateGroup);
+ for (int i = 0; i < d->states.count(); ++i)
+ d->states.at(i)->setStateGroup(0);
+}
+
+QList<QDeclarativeState *> QDeclarativeStateGroup::states() const
+{
+ Q_D(const QDeclarativeStateGroup);
+ return d->states;
+}
+
+/*!
+ \qmlproperty list<State> StateGroup::states
+ This property holds a list of states defined by the state group.
+
+ \qml
+ StateGroup {
+ states: [
+ State {
+ // State definition...
+ },
+ State {
+ // ...
+ }
+ // Other states...
+ ]
+ }
+ \endqml
+
+ \sa {qmlstate}{States}
+*/
+QDeclarativeListProperty<QDeclarativeState> QDeclarativeStateGroup::statesProperty()
+{
+ Q_D(QDeclarativeStateGroup);
+ return QDeclarativeListProperty<QDeclarativeState>(this, &d->states, &QDeclarativeStateGroupPrivate::append_state,
+ &QDeclarativeStateGroupPrivate::count_state,
+ &QDeclarativeStateGroupPrivate::at_state,
+ &QDeclarativeStateGroupPrivate::clear_states);
+}
+
+void QDeclarativeStateGroupPrivate::append_state(QDeclarativeListProperty<QDeclarativeState> *list, QDeclarativeState *state)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ if (state) {
+ _this->d_func()->states.append(state);
+ state->setStateGroup(_this);
+ }
+
+}
+
+int QDeclarativeStateGroupPrivate::count_state(QDeclarativeListProperty<QDeclarativeState> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->states.count();
+}
+
+QDeclarativeState *QDeclarativeStateGroupPrivate::at_state(QDeclarativeListProperty<QDeclarativeState> *list, int index)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->states.at(index);
+}
+
+void QDeclarativeStateGroupPrivate::clear_states(QDeclarativeListProperty<QDeclarativeState> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ _this->d_func()->setCurrentStateInternal(QString(), true);
+ for (int i = 0; i < _this->d_func()->states.count(); ++i) {
+ _this->d_func()->states.at(i)->setStateGroup(0);
+ }
+ _this->d_func()->states.clear();
+}
+
+/*!
+ \qmlproperty list<Transition> StateGroup::transitions
+ This property holds a list of transitions defined by the state group.
+
+ \qml
+ StateGroup {
+ transitions: [
+ Transition {
+ // ...
+ },
+ Transition {
+ // ...
+ }
+ // ...
+ ]
+ }
+ \endqml
+
+ \sa {QML Animation and Transitions}{Transitions}
+*/
+QDeclarativeListProperty<QDeclarativeTransition> QDeclarativeStateGroup::transitionsProperty()
+{
+ Q_D(QDeclarativeStateGroup);
+ return QDeclarativeListProperty<QDeclarativeTransition>(this, d->transitions);
+}
+
+/*!
+ \qmlproperty string StateGroup::state
+
+ This property holds the name of the current state of the state group.
+
+ This property is often used in scripts to change between states. For
+ example:
+
+ \js
+ function toggle() {
+ if (button.state == 'On')
+ button.state = 'Off';
+ else
+ button.state = 'On';
+ }
+ \endjs
+
+ If the state group is in its base state (i.e. no explicit state has been
+ set), \c state will be a blank string. Likewise, you can return a
+ state group to its base state by setting its current state to \c ''.
+
+ \sa {qmlstates}{States}
+*/
+QString QDeclarativeStateGroup::state() const
+{
+ Q_D(const QDeclarativeStateGroup);
+ return d->currentState;
+}
+
+void QDeclarativeStateGroup::setState(const QString &state)
+{
+ Q_D(QDeclarativeStateGroup);
+ if (d->currentState == state)
+ return;
+
+ d->setCurrentStateInternal(state);
+}
+
+void QDeclarativeStateGroup::classBegin()
+{
+ Q_D(QDeclarativeStateGroup);
+ d->componentComplete = false;
+}
+
+void QDeclarativeStateGroup::componentComplete()
+{
+ Q_D(QDeclarativeStateGroup);
+ d->componentComplete = true;
+
+ for (int ii = 0; ii < d->states.count(); ++ii) {
+ QDeclarativeState *state = d->states.at(ii);
+ if (!state->isNamed())
+ state->setName(QLatin1String("anonymousState") % QString::number(++d->unnamedCount));
+ }
+
+ if (d->updateAutoState()) {
+ return;
+ } else if (!d->currentState.isEmpty()) {
+ QString cs = d->currentState;
+ d->currentState.clear();
+ d->setCurrentStateInternal(cs, true);
+ }
+}
+
+/*!
+ Returns true if the state was changed, otherwise false.
+*/
+bool QDeclarativeStateGroup::updateAutoState()
+{
+ Q_D(QDeclarativeStateGroup);
+ return d->updateAutoState();
+}
+
+bool QDeclarativeStateGroupPrivate::updateAutoState()
+{
+ Q_Q(QDeclarativeStateGroup);
+ if (!componentComplete)
+ return false;
+
+ bool revert = false;
+ for (int ii = 0; ii < states.count(); ++ii) {
+ QDeclarativeState *state = states.at(ii);
+ if (state->isWhenKnown()) {
+ if (state->isNamed()) {
+ if (state->when() && state->when()->evaluate().toBool()) {
+ if (stateChangeDebug())
+ qWarning() << "Setting auto state due to:"
+ << state->when()->expression();
+ if (currentState != state->name()) {
+ q->setState(state->name());
+ return true;
+ } else {
+ return false;
+ }
+ } else if (state->name() == currentState) {
+ revert = true;
+ }
+ }
+ }
+ }
+ if (revert) {
+ bool rv = !currentState.isEmpty();
+ q->setState(QString());
+ return rv;
+ } else {
+ return false;
+ }
+}
+
+QDeclarativeTransition *QDeclarativeStateGroupPrivate::findTransition(const QString &from, const QString &to)
+{
+ QDeclarativeTransition *highest = 0;
+ int score = 0;
+ bool reversed = false;
+ bool done = false;
+
+ for (int ii = 0; !done && ii < transitions.count(); ++ii) {
+ QDeclarativeTransition *t = transitions.at(ii);
+ for (int ii = 0; ii < 2; ++ii)
+ {
+ if (ii && (!t->reversible() ||
+ (t->fromState() == QLatin1String("*") &&
+ t->toState() == QLatin1String("*"))))
+ break;
+ QStringList fromState;
+ QStringList toState;
+
+ fromState = t->fromState().split(QLatin1Char(','));
+ toState = t->toState().split(QLatin1Char(','));
+ if (ii == 1)
+ qSwap(fromState, toState);
+ int tScore = 0;
+ if (fromState.contains(from))
+ tScore += 2;
+ else if (fromState.contains(QLatin1String("*")))
+ tScore += 1;
+ else
+ continue;
+
+ if (toState.contains(to))
+ tScore += 2;
+ else if (toState.contains(QLatin1String("*")))
+ tScore += 1;
+ else
+ continue;
+
+ if (ii == 1)
+ reversed = true;
+ else
+ reversed = false;
+
+ if (tScore == 4) {
+ highest = t;
+ done = true;
+ break;
+ } else if (tScore > score) {
+ score = tScore;
+ highest = t;
+ }
+ }
+ }
+
+ if (highest)
+ highest->setReversed(reversed);
+
+ return highest;
+}
+
+void QDeclarativeStateGroupPrivate::setCurrentStateInternal(const QString &state,
+ bool ignoreTrans)
+{
+ Q_Q(QDeclarativeStateGroup);
+ if (!componentComplete) {
+ currentState = state;
+ return;
+ }
+
+ if (applyingState) {
+ qmlInfo(q) << "Can't apply a state change as part of a state definition.";
+ return;
+ }
+
+ applyingState = true;
+
+ QDeclarativeTransition *transition = (ignoreTrans || ignoreTrans) ? 0 : findTransition(currentState, state);
+ if (stateChangeDebug()) {
+ qWarning() << this << "Changing state. From" << currentState << ". To" << state;
+ if (transition)
+ qWarning() << " using transition" << transition->fromState()
+ << transition->toState();
+ }
+
+ QDeclarativeState *oldState = 0;
+ if (!currentState.isEmpty()) {
+ for (int ii = 0; ii < states.count(); ++ii) {
+ if (states.at(ii)->name() == currentState) {
+ oldState = states.at(ii);
+ break;
+ }
+ }
+ }
+
+ currentState = state;
+ emit q->stateChanged(currentState);
+
+ QDeclarativeState *newState = 0;
+ for (int ii = 0; ii < states.count(); ++ii) {
+ if (states.at(ii)->name() == currentState) {
+ newState = states.at(ii);
+ break;
+ }
+ }
+
+ if (oldState == 0 || newState == 0) {
+ if (!nullState) { nullState = new QDeclarativeState; QDeclarative_setParent_noEvent(nullState, q); }
+ if (!oldState) oldState = nullState;
+ if (!newState) newState = nullState;
+ }
+
+ newState->apply(q, transition, oldState);
+ applyingState = false;
+ if (!transition)
+ static_cast<QDeclarativeStatePrivate*>(QObjectPrivate::get(newState))->complete();
+}
+
+QDeclarativeState *QDeclarativeStateGroup::findState(const QString &name) const
+{
+ Q_D(const QDeclarativeStateGroup);
+ for (int i = 0; i < d->states.count(); ++i) {
+ QDeclarativeState *state = d->states.at(i);
+ if (state->name() == name)
+ return state;
+ }
+
+ return 0;
+}
+
+void QDeclarativeStateGroup::removeState(QDeclarativeState *state)
+{
+ Q_D(QDeclarativeStateGroup);
+ d->states.removeOne(state);
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/declarative/util/qdeclarativestategroup_p.h b/src/declarative/util/qdeclarativestategroup_p.h
new file mode 100644
index 0000000000..ddf4e0aead
--- /dev/null
+++ b/src/declarative/util/qdeclarativestategroup_p.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 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 QDECLARATIVESTATEGROUP_H
+#define QDECLARATIVESTATEGROUP_H
+
+#include "private/qdeclarativestate_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeStateGroupPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeStateGroup : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_DECLARE_PRIVATE(QDeclarativeStateGroup)
+
+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeState> states READ statesProperty DESIGNABLE false)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeTransition> transitions READ transitionsProperty DESIGNABLE false)
+
+public:
+ QDeclarativeStateGroup(QObject * = 0);
+ virtual ~QDeclarativeStateGroup();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QDeclarativeListProperty<QDeclarativeState> statesProperty();
+ QList<QDeclarativeState *> states() const;
+
+ QDeclarativeListProperty<QDeclarativeTransition> transitionsProperty();
+
+ QDeclarativeState *findState(const QString &name) const;
+
+ virtual void classBegin();
+ virtual void componentComplete();
+Q_SIGNALS:
+ void stateChanged(const QString &);
+
+private:
+ friend class QDeclarativeState;
+ bool updateAutoState();
+ void removeState(QDeclarativeState *state);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeStateGroup)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATEGROUP_H
diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp
new file mode 100644
index 0000000000..9aca71fec2
--- /dev/null
+++ b/src/declarative/util/qdeclarativestateoperations.cpp
@@ -0,0 +1,1587 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativestateoperations_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeexpression.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativeanchors_p_p.h>
+#include <qdeclarativeitem_p.h>
+#include <qdeclarativeguard_p.h>
+#include <qdeclarativenullablevalue_p_p.h>
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativestate_p_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtCore/qmath.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeParentChangePrivate : public QDeclarativeStateOperationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeParentChange)
+public:
+ QDeclarativeParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
+ rewindParent(0), rewindStackBefore(0) {}
+
+ QDeclarativeItem *target;
+ QDeclarativeGuard<QDeclarativeItem> parent;
+ QDeclarativeGuard<QDeclarativeItem> origParent;
+ QDeclarativeGuard<QDeclarativeItem> origStackBefore;
+ QDeclarativeItem *rewindParent;
+ QDeclarativeItem *rewindStackBefore;
+
+ QDeclarativeNullableValue<QDeclarativeScriptString> xString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> yString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> widthString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> heightString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> scaleString;
+ QDeclarativeNullableValue<QDeclarativeScriptString> rotationString;
+
+ QDeclarativeNullableValue<qreal> x;
+ QDeclarativeNullableValue<qreal> y;
+ QDeclarativeNullableValue<qreal> width;
+ QDeclarativeNullableValue<qreal> height;
+ QDeclarativeNullableValue<qreal> scale;
+ QDeclarativeNullableValue<qreal> rotation;
+
+ void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0);
+};
+
+void QDeclarativeParentChangePrivate::doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore)
+{
+ if (targetParent && target && target->parentItem()) {
+ Q_Q(QDeclarativeParentChange);
+ bool ok;
+ const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(q) << QDeclarativeParentChange::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) << QDeclarativeParentChange::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) << QDeclarativeParentChange::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) << QDeclarativeParentChange::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() != QDeclarativeItem::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);
+}
+
+/*!
+ \preliminary
+ \qmlclass ParentChange QDeclarativeParentChange
+ \ingroup qml-state-elements
+ \brief The ParentChange element allows you to reparent an Item in a state change.
+
+ ParentChange reparents an item while preserving its visual appearance (position, size,
+ rotation, and scale) on screen. You can then specify a transition to move/resize/rotate/scale
+ the item to its final intended appearance.
+
+ ParentChange can only preserve visual appearance if no complex transforms are involved.
+ More specifically, it will not work if the transform property has been set for any
+ items involved in the reparenting (i.e. items in the common ancestor tree
+ for the original and new parent).
+
+ The example below displays a large red rectangle and a small blue rectangle, side by side.
+ When the \c blueRect is clicked, it changes to the "reparented" state: its parent is changed to \c redRect and it is
+ positioned at (10, 10) within the red rectangle, as specified in the ParentChange.
+
+ \snippet doc/src/snippets/declarative/parentchange.qml 0
+
+ \image parentchange.png
+
+ You can specify at which point in a transition you want a ParentChange to occur by
+ using a ParentAnimation.
+*/
+
+
+QDeclarativeParentChange::QDeclarativeParentChange(QObject *parent)
+ : QDeclarativeStateOperation(*(new QDeclarativeParentChangePrivate), parent)
+{
+}
+
+QDeclarativeParentChange::~QDeclarativeParentChange()
+{
+}
+
+/*!
+ \qmlproperty real ParentChange::x
+ \qmlproperty real ParentChange::y
+ \qmlproperty real ParentChange::width
+ \qmlproperty real ParentChange::height
+ \qmlproperty real ParentChange::scale
+ \qmlproperty real ParentChange::rotation
+ These properties hold the new position, size, scale, and rotation
+ for the item in this state.
+*/
+QDeclarativeScriptString QDeclarativeParentChange::x() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->xString.value;
+}
+
+void tryReal(QDeclarativeNullableValue<qreal> &value, const QString &string)
+{
+ bool ok = false;
+ qreal realValue = string.toFloat(&ok);
+ if (ok)
+ value = realValue;
+ else
+ value.invalidate();
+}
+
+void QDeclarativeParentChange::setX(QDeclarativeScriptString x)
+{
+ Q_D(QDeclarativeParentChange);
+ d->xString = x;
+ tryReal(d->x, x.script());
+}
+
+bool QDeclarativeParentChange::xIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->xString.isValid();
+}
+
+QDeclarativeScriptString QDeclarativeParentChange::y() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->yString.value;
+}
+
+void QDeclarativeParentChange::setY(QDeclarativeScriptString y)
+{
+ Q_D(QDeclarativeParentChange);
+ d->yString = y;
+ tryReal(d->y, y.script());
+}
+
+bool QDeclarativeParentChange::yIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->yString.isValid();
+}
+
+QDeclarativeScriptString QDeclarativeParentChange::width() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->widthString.value;
+}
+
+void QDeclarativeParentChange::setWidth(QDeclarativeScriptString width)
+{
+ Q_D(QDeclarativeParentChange);
+ d->widthString = width;
+ tryReal(d->width, width.script());
+}
+
+bool QDeclarativeParentChange::widthIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->widthString.isValid();
+}
+
+QDeclarativeScriptString QDeclarativeParentChange::height() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->heightString.value;
+}
+
+void QDeclarativeParentChange::setHeight(QDeclarativeScriptString height)
+{
+ Q_D(QDeclarativeParentChange);
+ d->heightString = height;
+ tryReal(d->height, height.script());
+}
+
+bool QDeclarativeParentChange::heightIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->heightString.isValid();
+}
+
+QDeclarativeScriptString QDeclarativeParentChange::scale() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->scaleString.value;
+}
+
+void QDeclarativeParentChange::setScale(QDeclarativeScriptString scale)
+{
+ Q_D(QDeclarativeParentChange);
+ d->scaleString = scale;
+ tryReal(d->scale, scale.script());
+}
+
+bool QDeclarativeParentChange::scaleIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->scaleString.isValid();
+}
+
+QDeclarativeScriptString QDeclarativeParentChange::rotation() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->rotationString.value;
+}
+
+void QDeclarativeParentChange::setRotation(QDeclarativeScriptString rotation)
+{
+ Q_D(QDeclarativeParentChange);
+ d->rotationString = rotation;
+ tryReal(d->rotation, rotation.script());
+}
+
+bool QDeclarativeParentChange::rotationIsSet() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->rotationString.isValid();
+}
+
+QDeclarativeItem *QDeclarativeParentChange::originalParent() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->origParent;
+}
+
+/*!
+ \qmlproperty Item ParentChange::target
+ This property holds the item to be reparented
+*/
+
+QDeclarativeItem *QDeclarativeParentChange::object() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->target;
+}
+
+void QDeclarativeParentChange::setObject(QDeclarativeItem *target)
+{
+ Q_D(QDeclarativeParentChange);
+ d->target = target;
+}
+
+/*!
+ \qmlproperty Item ParentChange::parent
+ This property holds the new parent for the item in this state.
+*/
+
+QDeclarativeItem *QDeclarativeParentChange::parent() const
+{
+ Q_D(const QDeclarativeParentChange);
+ return d->parent;
+}
+
+void QDeclarativeParentChange::setParent(QDeclarativeItem *parent)
+{
+ Q_D(QDeclarativeParentChange);
+ d->parent = parent;
+}
+
+QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions()
+{
+ Q_D(QDeclarativeParentChange);
+ if (!d->target || !d->parent)
+ return ActionList();
+
+ ActionList actions;
+
+ QDeclarativeAction a;
+ a.event = this;
+ actions << a;
+
+ QDeclarativeContext *ctxt = qmlContext(this);
+
+ if (d->xString.isValid()) {
+ if (d->x.isValid()) {
+ QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, d->x.value);
+ actions << xa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->xString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"), ctxt));
+ QDeclarativeAction xa;
+ xa.property = newBinding->property();
+ xa.toBinding = newBinding;
+ xa.fromValue = xa.property.read();
+ xa.deletableToBinding = true;
+ actions << xa;
+ }
+ }
+
+ if (d->yString.isValid()) {
+ if (d->y.isValid()) {
+ QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, d->y.value);
+ actions << ya;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->yString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"), ctxt));
+ QDeclarativeAction ya;
+ ya.property = newBinding->property();
+ ya.toBinding = newBinding;
+ ya.fromValue = ya.property.read();
+ ya.deletableToBinding = true;
+ actions << ya;
+ }
+ }
+
+ if (d->scaleString.isValid()) {
+ if (d->scale.isValid()) {
+ QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, d->scale.value);
+ actions << sa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->scaleString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"), ctxt));
+ QDeclarativeAction sa;
+ sa.property = newBinding->property();
+ sa.toBinding = newBinding;
+ sa.fromValue = sa.property.read();
+ sa.deletableToBinding = true;
+ actions << sa;
+ }
+ }
+
+ if (d->rotationString.isValid()) {
+ if (d->rotation.isValid()) {
+ QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, d->rotation.value);
+ actions << ra;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->rotationString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"), ctxt));
+ QDeclarativeAction ra;
+ ra.property = newBinding->property();
+ ra.toBinding = newBinding;
+ ra.fromValue = ra.property.read();
+ ra.deletableToBinding = true;
+ actions << ra;
+ }
+ }
+
+ if (d->widthString.isValid()) {
+ if (d->width.isValid()) {
+ QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, d->width.value);
+ actions << wa;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->widthString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"), ctxt));
+ QDeclarativeAction wa;
+ wa.property = newBinding->property();
+ wa.toBinding = newBinding;
+ wa.fromValue = wa.property.read();
+ wa.deletableToBinding = true;
+ actions << wa;
+ }
+ }
+
+ if (d->heightString.isValid()) {
+ if (d->height.isValid()) {
+ QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, d->height.value);
+ actions << ha;
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->heightString.value.script(), d->target, ctxt);
+ newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"), ctxt));
+ QDeclarativeAction ha;
+ ha.property = newBinding->property();
+ ha.toBinding = newBinding;
+ ha.fromValue = ha.property.read();
+ ha.deletableToBinding = true;
+ actions << ha;
+ }
+ }
+
+ return actions;
+}
+
+class AccessibleFxItem : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
+public:
+ int siblingIndex() {
+ Q_D(QDeclarativeItem);
+ return d->siblingIndex;
+ }
+};
+
+void QDeclarativeParentChange::saveOriginals()
+{
+ Q_D(QDeclarativeParentChange);
+ saveCurrentValues();
+ d->origParent = d->rewindParent;
+ d->origStackBefore = d->rewindStackBefore;
+}
+
+/*void QDeclarativeParentChange::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QDeclarativeParentChange);
+ QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(other);
+
+ d->origParent = pc->d_func()->rewindParent;
+ d->origStackBefore = pc->d_func()->rewindStackBefore;
+
+ saveCurrentValues();
+}*/
+
+void QDeclarativeParentChange::execute(Reason)
+{
+ Q_D(QDeclarativeParentChange);
+ d->doChange(d->parent);
+}
+
+bool QDeclarativeParentChange::isReversable()
+{
+ return true;
+}
+
+void QDeclarativeParentChange::reverse(Reason)
+{
+ Q_D(QDeclarativeParentChange);
+ d->doChange(d->origParent, d->origStackBefore);
+}
+
+QString QDeclarativeParentChange::typeName() const
+{
+ return QLatin1String("ParentChange");
+}
+
+bool QDeclarativeParentChange::override(QDeclarativeActionEvent*other)
+{
+ Q_D(QDeclarativeParentChange);
+ if (other->typeName() != QLatin1String("ParentChange"))
+ return false;
+ if (QDeclarativeParentChange *otherPC = static_cast<QDeclarativeParentChange*>(other))
+ return (d->target == otherPC->object());
+ return false;
+}
+
+void QDeclarativeParentChange::saveCurrentValues()
+{
+ Q_D(QDeclarativeParentChange);
+ if (!d->target) {
+ d->rewindParent = 0;
+ d->rewindStackBefore = 0;
+ return;
+ }
+
+ d->rewindParent = d->target->parentItem();
+ d->rewindStackBefore = 0;
+
+ if (!d->rewindParent)
+ return;
+
+ //try to determine the item's original stack position so we can restore it
+ int siblingIndex = ((AccessibleFxItem*)d->target)->siblingIndex() + 1;
+ QList<QGraphicsItem*> children = d->rewindParent->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QDeclarativeItem *child = qobject_cast<QDeclarativeItem*>(children.at(i));
+ if (!child)
+ continue;
+ if (((AccessibleFxItem*)child)->siblingIndex() == siblingIndex) {
+ d->rewindStackBefore = child;
+ break;
+ }
+ }
+}
+
+void QDeclarativeParentChange::rewind()
+{
+ Q_D(QDeclarativeParentChange);
+ d->doChange(d->rewindParent, d->rewindStackBefore);
+}
+
+class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate
+{
+public:
+ QDeclarativeStateChangeScriptPrivate() {}
+
+ QDeclarativeScriptString script;
+ QString name;
+};
+
+/*!
+ \qmlclass StateChangeScript QDeclarativeStateChangeScript
+ \ingroup qml-state-elements
+ \brief The StateChangeScript element allows you to run a script in a state.
+
+ A StateChangeScript is run upon entering a state. You can optionally use
+ ScriptAction to specify the point in the transition at which
+ the StateChangeScript should to be run.
+
+ \snippet snippets/declarative/states/statechangescript.qml state and transition
+
+ \sa ScriptAction
+*/
+
+QDeclarativeStateChangeScript::QDeclarativeStateChangeScript(QObject *parent)
+: QDeclarativeStateOperation(*(new QDeclarativeStateChangeScriptPrivate), parent)
+{
+}
+
+QDeclarativeStateChangeScript::~QDeclarativeStateChangeScript()
+{
+}
+
+/*!
+ \qmlproperty script StateChangeScript::script
+ This property holds the script to run when the state is current.
+*/
+QDeclarativeScriptString QDeclarativeStateChangeScript::script() const
+{
+ Q_D(const QDeclarativeStateChangeScript);
+ return d->script;
+}
+
+void QDeclarativeStateChangeScript::setScript(const QDeclarativeScriptString &s)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ d->script = s;
+}
+
+/*!
+ \qmlproperty string StateChangeScript::name
+ This property holds the name of the script. This name can be used by a
+ ScriptAction to target a specific script.
+
+ \sa ScriptAction::scriptName
+*/
+QString QDeclarativeStateChangeScript::name() const
+{
+ Q_D(const QDeclarativeStateChangeScript);
+ return d->name;
+}
+
+void QDeclarativeStateChangeScript::setName(const QString &n)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ d->name = n;
+}
+
+void QDeclarativeStateChangeScript::execute(Reason)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ const QString &script = d->script.script();
+ if (!script.isEmpty()) {
+ QDeclarativeExpression expr(d->script.context(), d->script.scopeObject(), script);
+ QDeclarativeData *ddata = QDeclarativeData::get(this);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expr.setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ expr.evaluate();
+ if (expr.hasError())
+ qmlInfo(this, expr.error());
+ }
+}
+
+QDeclarativeStateChangeScript::ActionList QDeclarativeStateChangeScript::actions()
+{
+ ActionList rv;
+ QDeclarativeAction a;
+ a.event = this;
+ rv << a;
+ return rv;
+}
+
+QString QDeclarativeStateChangeScript::typeName() const
+{
+ return QLatin1String("StateChangeScript");
+}
+
+/*!
+ \qmlclass AnchorChanges QDeclarativeAnchorChanges
+ \ingroup qml-state-elements
+ \brief The AnchorChanges element allows you to change the anchors of an item in a state.
+
+ The AnchorChanges element is used to modify the anchors of an item in a \l State.
+
+ AnchorChanges cannot be used to modify the margins on an item. For this, use
+ PropertyChanges intead.
+
+ In the following example we change the top and bottom anchors of an item
+ using AnchorChanges, and the top and bottom anchor margins using
+ PropertyChanges:
+
+ \snippet doc/src/snippets/declarative/anchorchanges.qml 0
+
+ \image anchorchanges.png
+
+ AnchorChanges can be animated using AnchorAnimation.
+ \qml
+ //animate our anchor changes
+ Transition {
+ AnchorAnimation {}
+ }
+ \endqml
+
+ Margin animations can be animated using NumberAnimation.
+
+ For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+class QDeclarativeAnchorSetPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnchorSet)
+public:
+ QDeclarativeAnchorSetPrivate()
+ : usedAnchors(0), resetAnchors(0), fill(0),
+ centerIn(0)/*, leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
+ margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)*/
+ {
+ }
+
+ QDeclarativeAnchors::Anchors usedAnchors;
+ QDeclarativeAnchors::Anchors resetAnchors;
+
+ QDeclarativeItem *fill;
+ QDeclarativeItem *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;*/
+};
+
+QDeclarativeAnchorSet::QDeclarativeAnchorSet(QObject *parent)
+ : QObject(*new QDeclarativeAnchorSetPrivate, parent)
+{
+}
+
+QDeclarativeAnchorSet::~QDeclarativeAnchorSet()
+{
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::top() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->topScript;
+}
+
+void QDeclarativeAnchorSet::setTop(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::TopAnchor;
+ d->topScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetTop();
+}
+
+void QDeclarativeAnchorSet::resetTop()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::TopAnchor;
+ d->topScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::TopAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::bottom() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->bottomScript;
+}
+
+void QDeclarativeAnchorSet::setBottom(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::BottomAnchor;
+ d->bottomScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBottom();
+}
+
+void QDeclarativeAnchorSet::resetBottom()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::BottomAnchor;
+ d->bottomScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::BottomAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::verticalCenter() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->vCenterScript;
+}
+
+void QDeclarativeAnchorSet::setVerticalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::VCenterAnchor;
+ d->vCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetVerticalCenter();
+}
+
+void QDeclarativeAnchorSet::resetVerticalCenter()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::VCenterAnchor;
+ d->vCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::VCenterAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::baseline() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->baselineScript;
+}
+
+void QDeclarativeAnchorSet::setBaseline(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::BaselineAnchor;
+ d->baselineScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetBaseline();
+}
+
+void QDeclarativeAnchorSet::resetBaseline()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::BaselineAnchor;
+ d->baselineScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::BaselineAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::left() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->leftScript;
+}
+
+void QDeclarativeAnchorSet::setLeft(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::LeftAnchor;
+ d->leftScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetLeft();
+}
+
+void QDeclarativeAnchorSet::resetLeft()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::LeftAnchor;
+ d->leftScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::LeftAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::right() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->rightScript;
+}
+
+void QDeclarativeAnchorSet::setRight(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::RightAnchor;
+ d->rightScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetRight();
+}
+
+void QDeclarativeAnchorSet::resetRight()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::RightAnchor;
+ d->rightScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::RightAnchor;
+}
+
+QDeclarativeScriptString QDeclarativeAnchorSet::horizontalCenter() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->hCenterScript;
+}
+
+void QDeclarativeAnchorSet::setHorizontalCenter(const QDeclarativeScriptString &edge)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors |= QDeclarativeAnchors::HCenterAnchor;
+ d->hCenterScript = edge;
+ if (edge.script() == QLatin1String("undefined"))
+ resetHorizontalCenter();
+}
+
+void QDeclarativeAnchorSet::resetHorizontalCenter()
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->usedAnchors &= ~QDeclarativeAnchors::HCenterAnchor;
+ d->hCenterScript = QDeclarativeScriptString();
+ d->resetAnchors |= QDeclarativeAnchors::HCenterAnchor;
+}
+
+QDeclarativeItem *QDeclarativeAnchorSet::fill() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->fill;
+}
+
+void QDeclarativeAnchorSet::setFill(QDeclarativeItem *f)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->fill = f;
+}
+
+void QDeclarativeAnchorSet::resetFill()
+{
+ setFill(0);
+}
+
+QDeclarativeItem *QDeclarativeAnchorSet::centerIn() const
+{
+ Q_D(const QDeclarativeAnchorSet);
+ return d->centerIn;
+}
+
+void QDeclarativeAnchorSet::setCenterIn(QDeclarativeItem* c)
+{
+ Q_D(QDeclarativeAnchorSet);
+ d->centerIn = c;
+}
+
+void QDeclarativeAnchorSet::resetCenterIn()
+{
+ setCenterIn(0);
+}
+
+
+class QDeclarativeAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
+{
+public:
+ QDeclarativeAnchorChangesPrivate()
+ : target(0), anchorSet(new QDeclarativeAnchorSet),
+ 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)
+ {
+
+ }
+ ~QDeclarativeAnchorChangesPrivate() { delete anchorSet; }
+
+ QDeclarativeItem *target;
+ QDeclarativeAnchorSet *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;
+
+ QDeclarativeAnchorLine rewindLeft;
+ QDeclarativeAnchorLine rewindRight;
+ QDeclarativeAnchorLine rewindHCenter;
+ QDeclarativeAnchorLine rewindTop;
+ QDeclarativeAnchorLine rewindBottom;
+ QDeclarativeAnchorLine rewindVCenter;
+ QDeclarativeAnchorLine 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;
+};
+
+/*!
+ \qmlproperty Item AnchorChanges::target
+ This property holds the \l Item for which the anchor changes will be applied.
+*/
+
+QDeclarativeAnchorChanges::QDeclarativeAnchorChanges(QObject *parent)
+ : QDeclarativeStateOperation(*(new QDeclarativeAnchorChangesPrivate), parent)
+{
+}
+
+QDeclarativeAnchorChanges::~QDeclarativeAnchorChanges()
+{
+}
+
+QDeclarativeAnchorChanges::ActionList QDeclarativeAnchorChanges::actions()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ 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"));
+
+ QDeclarativeContext *ctxt = qmlContext(this);
+
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::LeftAnchor) {
+ d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, ctxt);
+ d->leftBinding->setTarget(d->leftProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::RightAnchor) {
+ d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, ctxt);
+ d->rightBinding->setTarget(d->rightProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
+ d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, ctxt);
+ d->hCenterBinding->setTarget(d->hCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::TopAnchor) {
+ d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, ctxt);
+ d->topBinding->setTarget(d->topProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BottomAnchor) {
+ d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, ctxt);
+ d->bottomBinding->setTarget(d->bottomProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
+ d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, ctxt);
+ d->vCenterBinding->setTarget(d->vCenterProp);
+ }
+ if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BaselineAnchor) {
+ d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, ctxt);
+ d->baselineBinding->setTarget(d->baselineProp);
+ }
+
+ QDeclarativeAction a;
+ a.event = this;
+ return ActionList() << a;
+}
+
+QDeclarativeAnchorSet *QDeclarativeAnchorChanges::anchors()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ return d->anchorSet;
+}
+
+QDeclarativeItem *QDeclarativeAnchorChanges::object() const
+{
+ Q_D(const QDeclarativeAnchorChanges);
+ return d->target;
+}
+
+void QDeclarativeAnchorChanges::setObject(QDeclarativeItem *target)
+{
+ Q_D(QDeclarativeAnchorChanges);
+ d->target = target;
+}
+
+/*!
+ \qmlproperty AnchorLine AnchorChanges::anchors.left
+ \qmlproperty AnchorLine AnchorChanges::anchors.right
+ \qmlproperty AnchorLine AnchorChanges::anchors.horizontalCenter
+ \qmlproperty AnchorLine AnchorChanges::anchors.top
+ \qmlproperty AnchorLine AnchorChanges::anchors.bottom
+ \qmlproperty AnchorLine AnchorChanges::anchors.verticalCenter
+ \qmlproperty AnchorLine AnchorChanges::anchors.baseline
+
+ These properties change the respective anchors of the item.
+
+ To reset an anchor you can assign \c undefined:
+ \qml
+ AnchorChanges {
+ target: myItem
+ anchors.left: undefined //remove myItem's left anchor
+ anchors.right: otherItem.right
+ }
+ \endqml
+*/
+
+void QDeclarativeAnchorChanges::execute(Reason reason)
+{
+ Q_D(QDeclarativeAnchorChanges);
+ if (!d->target)
+ return;
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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 & QDeclarativeAnchors::LeftAnchor) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::RightAnchor) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::HCenterAnchor) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::TopAnchor) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::BottomAnchor) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::VCenterAnchor) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::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 QDeclarativeAnchorChanges::isReversable()
+{
+ return true;
+}
+
+void QDeclarativeAnchorChanges::reverse(Reason reason)
+{
+ Q_D(QDeclarativeAnchorChanges);
+ if (!d->target)
+ return;
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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
+ QDeclarativeAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Vertical_Mask;
+ QDeclarativeAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Vertical_Mask;
+ QDeclarativeAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Horizontal_Mask;
+ QDeclarativeAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Horizontal_Mask;
+
+ bool stateSetWidth = (stateHAnchors &&
+ stateHAnchors != QDeclarativeAnchors::LeftAnchor &&
+ stateHAnchors != QDeclarativeAnchors::RightAnchor &&
+ stateHAnchors != QDeclarativeAnchors::HCenterAnchor);
+ bool origSetWidth = (origHAnchors &&
+ origHAnchors != QDeclarativeAnchors::LeftAnchor &&
+ origHAnchors != QDeclarativeAnchors::RightAnchor &&
+ origHAnchors != QDeclarativeAnchors::HCenterAnchor);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
+ d->target->setWidth(d->origWidth.value);
+
+ bool stateSetHeight = (stateVAnchors &&
+ stateVAnchors != QDeclarativeAnchors::TopAnchor &&
+ stateVAnchors != QDeclarativeAnchors::BottomAnchor &&
+ stateVAnchors != QDeclarativeAnchors::VCenterAnchor &&
+ stateVAnchors != QDeclarativeAnchors::BaselineAnchor);
+ bool origSetHeight = (origVAnchors &&
+ origVAnchors != QDeclarativeAnchors::TopAnchor &&
+ origVAnchors != QDeclarativeAnchors::BottomAnchor &&
+ origVAnchors != QDeclarativeAnchors::VCenterAnchor &&
+ origVAnchors != QDeclarativeAnchors::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 QDeclarativeAnchorChanges::typeName() const
+{
+ return QLatin1String("AnchorChanges");
+}
+
+QList<QDeclarativeAction> QDeclarativeAnchorChanges::additionalActions()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ QList<QDeclarativeAction> extra;
+
+ QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
+ bool hChange = combined & QDeclarativeAnchors::Horizontal_Mask;
+ bool vChange = combined & QDeclarativeAnchors::Vertical_Mask;
+
+ if (d->target) {
+ QDeclarativeContext *ctxt = qmlContext(this);
+ QDeclarativeAction a;
+ if (hChange && d->fromX != d->toX) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("x"), ctxt);
+ a.toValue = d->toX;
+ extra << a;
+ }
+ if (vChange && d->fromY != d->toY) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("y"), ctxt);
+ a.toValue = d->toY;
+ extra << a;
+ }
+ if (hChange && d->fromWidth != d->toWidth) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("width"), ctxt);
+ a.toValue = d->toWidth;
+ extra << a;
+ }
+ if (vChange && d->fromHeight != d->toHeight) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("height"), ctxt);
+ a.toValue = d->toHeight;
+ extra << a;
+ }
+ }
+
+ return extra;
+}
+
+bool QDeclarativeAnchorChanges::changesBindings()
+{
+ return true;
+}
+
+void QDeclarativeAnchorChanges::saveOriginals()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ 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);
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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 QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QDeclarativeAnchorChanges);
+ QDeclarativeAnchorChanges *ac = static_cast<QDeclarativeAnchorChanges*>(other);
+ QDeclarativeAnchorChangesPrivate *acp = ac->d_func();
+
+ QDeclarativeAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
+ acp->anchorSet->d_func()->resetAnchors;
+
+ //probably also need to revert some things
+ d->applyOrigLeft = (combined & QDeclarativeAnchors::LeftAnchor);
+ d->applyOrigRight = (combined & QDeclarativeAnchors::RightAnchor);
+ d->applyOrigHCenter = (combined & QDeclarativeAnchors::HCenterAnchor);
+ d->applyOrigTop = (combined & QDeclarativeAnchors::TopAnchor);
+ d->applyOrigBottom = (combined & QDeclarativeAnchors::BottomAnchor);
+ d->applyOrigVCenter = (combined & QDeclarativeAnchors::VCenterAnchor);
+ d->applyOrigBaseline = (combined & QDeclarativeAnchors::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 QDeclarativeAnchorChanges::clearBindings()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ 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();
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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
+ QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
+ d->anchorSet->d_func()->usedAnchors;
+ if (d->applyOrigLeft || (combined & QDeclarativeAnchors::LeftAnchor)) {
+ targetPrivate->anchors()->resetLeft();
+ QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
+ }
+ if (d->applyOrigRight || (combined & QDeclarativeAnchors::RightAnchor)) {
+ targetPrivate->anchors()->resetRight();
+ QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
+ }
+ if (d->applyOrigHCenter || (combined & QDeclarativeAnchors::HCenterAnchor)) {
+ targetPrivate->anchors()->resetHorizontalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
+ }
+ if (d->applyOrigTop || (combined & QDeclarativeAnchors::TopAnchor)) {
+ targetPrivate->anchors()->resetTop();
+ QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
+ }
+ if (d->applyOrigBottom || (combined & QDeclarativeAnchors::BottomAnchor)) {
+ targetPrivate->anchors()->resetBottom();
+ QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
+ }
+ if (d->applyOrigVCenter || (combined & QDeclarativeAnchors::VCenterAnchor)) {
+ targetPrivate->anchors()->resetVerticalCenter();
+ QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
+ }
+ if (d->applyOrigBaseline || (combined & QDeclarativeAnchors::BaselineAnchor)) {
+ targetPrivate->anchors()->resetBaseline();
+ QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
+ }
+}
+
+bool QDeclarativeAnchorChanges::override(QDeclarativeActionEvent*other)
+{
+ if (other->typeName() != QLatin1String("AnchorChanges"))
+ return false;
+ if (static_cast<QDeclarativeActionEvent*>(this) == other)
+ return true;
+ if (static_cast<QDeclarativeAnchorChanges*>(other)->object() == object())
+ return true;
+ return false;
+}
+
+void QDeclarativeAnchorChanges::rewind()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ if (!d->target)
+ return;
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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 QDeclarativeAnchorChanges::saveCurrentValues()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ if (!d->target)
+ return;
+
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::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 QDeclarativeAnchorChanges::saveTargetValues()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ 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 <qdeclarativestateoperations.moc>
+#include <moc_qdeclarativestateoperations_p.cpp>
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/util/qdeclarativestateoperations_p.h b/src/declarative/util/qdeclarativestateoperations_p.h
new file mode 100644
index 0000000000..594e3c54d1
--- /dev/null
+++ b/src/declarative/util/qdeclarativestateoperations_p.h
@@ -0,0 +1,299 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESTATEOPERATIONS_H
+#define QDECLARATIVESTATEOPERATIONS_H
+
+#include "private/qdeclarativestate_p.h"
+
+#include <qdeclarativeitem.h>
+#include <private/qdeclarativeanchors_p.h>
+#include <qdeclarativescriptstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeParentChangePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeParentChange : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeParentChange)
+
+ Q_PROPERTY(QDeclarativeItem *target READ object WRITE setObject)
+ Q_PROPERTY(QDeclarativeItem *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:
+ QDeclarativeParentChange(QObject *parent=0);
+ ~QDeclarativeParentChange();
+
+ QDeclarativeItem *object() const;
+ void setObject(QDeclarativeItem *);
+
+ QDeclarativeItem *parent() const;
+ void setParent(QDeclarativeItem *);
+
+ QDeclarativeItem *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 QDeclarativeStateChangeScriptPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeStateChangeScript : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeStateChangeScript)
+
+ Q_PROPERTY(QDeclarativeScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString name READ name WRITE setName)
+
+public:
+ QDeclarativeStateChangeScript(QObject *parent=0);
+ ~QDeclarativeStateChangeScript();
+
+ virtual ActionList actions();
+
+ virtual QString typeName() const;
+
+ QDeclarativeScriptString script() const;
+ void setScript(const QDeclarativeScriptString &);
+
+ QString name() const;
+ void setName(const QString &);
+
+ virtual void execute(Reason reason = ActualChange);
+};
+
+class QDeclarativeAnchorChanges;
+class QDeclarativeAnchorSetPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeAnchorSet : 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(QDeclarativeItem *fill READ fill WRITE setFill RESET resetFill)
+ //Q_PROPERTY(QDeclarativeItem *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:
+ QDeclarativeAnchorSet(QObject *parent=0);
+ virtual ~QDeclarativeAnchorSet();
+
+ 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();
+
+ QDeclarativeItem *fill() const;
+ void setFill(QDeclarativeItem *);
+ void resetFill();
+
+ QDeclarativeItem *centerIn() const;
+ void setCenterIn(QDeclarativeItem *);
+ 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);*/
+
+ QDeclarativeAnchors::Anchors usedAnchors() const;
+
+/*Q_SIGNALS:
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void marginsChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+ void baselineOffsetChanged();*/
+
+private:
+ friend class QDeclarativeAnchorChanges;
+ Q_DISABLE_COPY(QDeclarativeAnchorSet)
+ Q_DECLARE_PRIVATE(QDeclarativeAnchorSet)
+};
+
+class QDeclarativeAnchorChangesPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeAnchorChanges : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnchorChanges)
+
+ Q_PROPERTY(QDeclarativeItem *target READ object WRITE setObject)
+ Q_PROPERTY(QDeclarativeAnchorSet *anchors READ anchors CONSTANT)
+
+public:
+ QDeclarativeAnchorChanges(QObject *parent=0);
+ ~QDeclarativeAnchorChanges();
+
+ virtual ActionList actions();
+
+ QDeclarativeAnchorSet *anchors();
+
+ QDeclarativeItem *object() const;
+ void setObject(QDeclarativeItem *);
+
+ 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(QDeclarativeParentChange)
+QML_DECLARE_TYPE(QDeclarativeStateChangeScript)
+QML_DECLARE_TYPE(QDeclarativeAnchorSet)
+QML_DECLARE_TYPE(QDeclarativeAnchorChanges)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATEOPERATIONS_H
diff --git a/src/declarative/util/qdeclarativestyledtext.cpp b/src/declarative/util/qdeclarativestyledtext.cpp
new file mode 100644
index 0000000000..a99d27eb3f
--- /dev/null
+++ b/src/declarative/util/qdeclarativestyledtext.cpp
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 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 <QStack>
+#include <QVector>
+#include <QPainter>
+#include <QTextLayout>
+#include <QDebug>
+#include <qmath.h>
+#include "private/qdeclarativestyledtext_p.h"
+
+/*
+ QDeclarativeStyledText supports few tags:
+
+ <b></b> - bold
+ <i></i> - italic
+ <br> - new line
+ <font color="color_name" size="1-7"></font>
+
+ The opening and closing tags must be correctly nested.
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStyledTextPrivate
+{
+public:
+ QDeclarativeStyledTextPrivate(const QString &t, QTextLayout &l) : text(t), layout(l), baseFont(layout.font()) {}
+
+ void parse();
+ bool parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format);
+ bool parseCloseTag(const QChar *&ch, const QString &textIn);
+ void parseEntity(const QChar *&ch, const QString &textIn, QString &textOut);
+ bool parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format);
+ QPair<QStringRef,QStringRef> parseAttribute(const QChar *&ch, const QString &textIn);
+ QStringRef parseValue(const QChar *&ch, const QString &textIn);
+
+ inline void skipSpace(const QChar *&ch) {
+ while (ch->isSpace() && !ch->isNull())
+ ++ch;
+ }
+
+ QString text;
+ QTextLayout &layout;
+ QFont baseFont;
+
+ static const QChar lessThan;
+ static const QChar greaterThan;
+ static const QChar equals;
+ static const QChar singleQuote;
+ static const QChar doubleQuote;
+ static const QChar slash;
+ static const QChar ampersand;
+};
+
+const QChar QDeclarativeStyledTextPrivate::lessThan(QLatin1Char('<'));
+const QChar QDeclarativeStyledTextPrivate::greaterThan(QLatin1Char('>'));
+const QChar QDeclarativeStyledTextPrivate::equals(QLatin1Char('='));
+const QChar QDeclarativeStyledTextPrivate::singleQuote(QLatin1Char('\''));
+const QChar QDeclarativeStyledTextPrivate::doubleQuote(QLatin1Char('\"'));
+const QChar QDeclarativeStyledTextPrivate::slash(QLatin1Char('/'));
+const QChar QDeclarativeStyledTextPrivate::ampersand(QLatin1Char('&'));
+
+QDeclarativeStyledText::QDeclarativeStyledText(const QString &string, QTextLayout &layout)
+: d(new QDeclarativeStyledTextPrivate(string, layout))
+{
+}
+
+QDeclarativeStyledText::~QDeclarativeStyledText()
+{
+ delete d;
+}
+
+void QDeclarativeStyledText::parse(const QString &string, QTextLayout &layout)
+{
+ if (string.isEmpty())
+ return;
+ QDeclarativeStyledText styledText(string, layout);
+ styledText.d->parse();
+}
+
+void QDeclarativeStyledTextPrivate::parse()
+{
+ QList<QTextLayout::FormatRange> ranges;
+ QStack<QTextCharFormat> formatStack;
+
+ QString drawText;
+ drawText.reserve(text.count());
+
+ int textStart = 0;
+ int textLength = 0;
+ int rangeStart = 0;
+ const QChar *ch = text.constData();
+ while (!ch->isNull()) {
+ if (*ch == lessThan) {
+ if (textLength)
+ drawText.append(QStringRef(&text, textStart, textLength));
+ if (rangeStart != drawText.length() && formatStack.count()) {
+ QTextLayout::FormatRange formatRange;
+ formatRange.format = formatStack.top();
+ formatRange.start = rangeStart;
+ formatRange.length = drawText.length() - rangeStart;
+ ranges.append(formatRange);
+ }
+ rangeStart = drawText.length();
+ ++ch;
+ if (*ch == slash) {
+ ++ch;
+ if (parseCloseTag(ch, text)) {
+ if (formatStack.count())
+ formatStack.pop();
+ }
+ } else {
+ QTextCharFormat format;
+ if (formatStack.count())
+ format = formatStack.top();
+ if (parseTag(ch, text, drawText, format))
+ formatStack.push(format);
+ }
+ textStart = ch - text.constData() + 1;
+ textLength = 0;
+ } else if (*ch == ampersand) {
+ ++ch;
+ drawText.append(QStringRef(&text, textStart, textLength));
+ parseEntity(ch, text, drawText);
+ textStart = ch - text.constData() + 1;
+ textLength = 0;
+ } else {
+ ++textLength;
+ }
+ if (!ch->isNull())
+ ++ch;
+ }
+ if (textLength)
+ drawText.append(QStringRef(&text, textStart, textLength));
+ if (rangeStart != drawText.length() && formatStack.count()) {
+ QTextLayout::FormatRange formatRange;
+ formatRange.format = formatStack.top();
+ formatRange.start = rangeStart;
+ formatRange.length = drawText.length() - rangeStart;
+ ranges.append(formatRange);
+ }
+
+ layout.setText(drawText);
+ layout.setAdditionalFormats(ranges);
+}
+
+bool QDeclarativeStyledTextPrivate::parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format)
+{
+ skipSpace(ch);
+
+ int tagStart = ch - textIn.constData();
+ int tagLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ if (char0 == QLatin1Char('b')) {
+ if (tagLength == 1)
+ format.setFontWeight(QFont::Bold);
+ else if (tagLength == 2 && tag.at(1) == QLatin1Char('r')) {
+ textOut.append(QChar(QChar::LineSeparator));
+ return false;
+ }
+ } else if (char0 == QLatin1Char('i')) {
+ if (tagLength == 1)
+ format.setFontItalic(true);
+ }
+ return true;
+ } else if (ch->isSpace()) {
+ // may have params.
+ QStringRef tag(&textIn, tagStart, tagLength);
+ if (tag == QLatin1String("font"))
+ return parseFontAttributes(ch, textIn, format);
+ if (*ch == greaterThan || ch->isNull())
+ continue;
+ } else if (*ch != slash){
+ tagLength++;
+ }
+ ++ch;
+ }
+
+ return false;
+}
+
+bool QDeclarativeStyledTextPrivate::parseCloseTag(const QChar *&ch, const QString &textIn)
+{
+ skipSpace(ch);
+
+ int tagStart = ch - textIn.constData();
+ int tagLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ if (char0 == QLatin1Char('b')) {
+ if (tagLength == 1)
+ return true;
+ else if (tag.at(1) == QLatin1Char('r') && tagLength == 2)
+ return true;
+ } else if (char0 == QLatin1Char('i')) {
+ if (tagLength == 1)
+ return true;
+ } else if (tag == QLatin1String("font")) {
+ return true;
+ }
+ return false;
+ } else if (!ch->isSpace()){
+ tagLength++;
+ }
+ ++ch;
+ }
+
+ return false;
+}
+
+void QDeclarativeStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textIn, QString &textOut)
+{
+ int entityStart = ch - textIn.constData();
+ int entityLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == QLatin1Char(';')) {
+ QStringRef entity(&textIn, entityStart, entityLength);
+ if (entity == QLatin1String("gt"))
+ textOut += QChar(62);
+ else if (entity == QLatin1String("lt"))
+ textOut += QChar(60);
+ else if (entity == QLatin1String("amp"))
+ textOut += QChar(38);
+ return;
+ }
+ ++entityLength;
+ ++ch;
+ }
+}
+
+bool QDeclarativeStyledTextPrivate::parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
+{
+ bool valid = false;
+ QPair<QStringRef,QStringRef> attr;
+ do {
+ attr = parseAttribute(ch, textIn);
+ if (attr.first == QLatin1String("color")) {
+ valid = true;
+ format.setForeground(QColor(attr.second.toString()));
+ } else if (attr.first == QLatin1String("size")) {
+ valid = true;
+ int size = attr.second.toString().toInt();
+ if (attr.second.at(0) == QLatin1Char('-') || attr.second.at(0) == QLatin1Char('+'))
+ size += 3;
+ if (size >= 1 && size <= 7) {
+ static const qreal scaling[] = { 0.7, 0.8, 1.0, 1.2, 1.5, 2.0, 2.4 };
+ format.setFontPointSize(baseFont.pointSize() * scaling[size-1]);
+ }
+ }
+ } while (!ch->isNull() && !attr.first.isEmpty());
+
+ return valid;
+}
+
+QPair<QStringRef,QStringRef> QDeclarativeStyledTextPrivate::parseAttribute(const QChar *&ch, const QString &textIn)
+{
+ skipSpace(ch);
+
+ int attrStart = ch - textIn.constData();
+ int attrLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ break;
+ } else if (*ch == equals) {
+ ++ch;
+ if (*ch != singleQuote && *ch != doubleQuote) {
+ while (*ch != greaterThan && !ch->isNull())
+ ++ch;
+ break;
+ }
+ ++ch;
+ if (!attrLength)
+ break;
+ QStringRef attr(&textIn, attrStart, attrLength);
+ QStringRef val = parseValue(ch, textIn);
+ if (!val.isEmpty())
+ return QPair<QStringRef,QStringRef>(attr,val);
+ break;
+ } else {
+ ++attrLength;
+ }
+ ++ch;
+ }
+
+ return QPair<QStringRef,QStringRef>();
+}
+
+QStringRef QDeclarativeStyledTextPrivate::parseValue(const QChar *&ch, const QString &textIn)
+{
+ int valStart = ch - textIn.constData();
+ int valLength = 0;
+ while (*ch != singleQuote && *ch != doubleQuote && !ch->isNull()) {
+ ++valLength;
+ ++ch;
+ }
+ if (ch->isNull())
+ return QStringRef();
+ ++ch; // skip quote
+
+ return QStringRef(&textIn, valStart, valLength);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativestyledtext_p.h b/src/declarative/util/qdeclarativestyledtext_p.h
new file mode 100644
index 0000000000..ecb43c15a2
--- /dev/null
+++ b/src/declarative/util/qdeclarativestyledtext_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVESTYLEDTEXT_H
+#define QDECLARATIVESTYLEDTEXT_H
+
+#include <QSizeF>
+
+QT_BEGIN_NAMESPACE
+
+class QPainter;
+class QPointF;
+class QString;
+class QDeclarativeStyledTextPrivate;
+class QTextLayout;
+
+class Q_AUTOTEST_EXPORT QDeclarativeStyledText
+{
+public:
+ static void parse(const QString &string, QTextLayout &layout);
+
+private:
+ QDeclarativeStyledText(const QString &string, QTextLayout &layout);
+ ~QDeclarativeStyledText();
+
+ QDeclarativeStyledTextPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/util/qdeclarativesystempalette.cpp b/src/declarative/util/qdeclarativesystempalette.cpp
new file mode 100644
index 0000000000..a340fd807f
--- /dev/null
+++ b/src/declarative/util/qdeclarativesystempalette.cpp
@@ -0,0 +1,312 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativesystempalette_p.h"
+
+#include <QApplication>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSystemPalettePrivate : public QObjectPrivate
+{
+public:
+ QPalette palette;
+ QPalette::ColorGroup group;
+};
+
+
+
+/*!
+ \qmlclass SystemPalette QDeclarativeSystemPalette
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The SystemPalette element provides access to the Qt palettes.
+
+ The SystemPalette element provides access to the Qt application
+ palettes. This provides information about the standard colors used
+ for application windows, buttons and other features. These colors
+ are grouped into three \e {color groups}: \c Active, \c Inactive,
+ and \c Disabled. See the QPalette documentation for details about
+ color groups and the properties provided by SystemPalette.
+
+ This can be used to color items in a way that provides a more
+ native look and feel.
+
+ The following example creates a palette from the \c Active color
+ group and uses this to color the window and text items
+ appropriately:
+
+ \snippet doc/src/snippets/declarative/systempalette.qml 0
+
+ \sa QPalette
+*/
+QDeclarativeSystemPalette::QDeclarativeSystemPalette(QObject *parent)
+ : QObject(*(new QDeclarativeSystemPalettePrivate), parent)
+{
+ Q_D(QDeclarativeSystemPalette);
+ d->palette = QApplication::palette();
+ d->group = QPalette::Active;
+ qApp->installEventFilter(this);
+}
+
+QDeclarativeSystemPalette::~QDeclarativeSystemPalette()
+{
+}
+
+/*!
+ \qmlproperty color SystemPalette::window
+ The window (general background) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::window() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Window);
+}
+
+/*!
+ \qmlproperty color SystemPalette::windowText
+ The window text (general foreground) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::windowText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::WindowText);
+}
+
+/*!
+ \qmlproperty color SystemPalette::base
+ The base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::base() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Base);
+}
+
+/*!
+ \qmlproperty color SystemPalette::text
+ The text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::text() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Text);
+}
+
+/*!
+ \qmlproperty color SystemPalette::alternateBase
+ The alternate base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::alternateBase() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::AlternateBase);
+}
+
+/*!
+ \qmlproperty color SystemPalette::button
+ The button color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::button() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Button);
+}
+
+/*!
+ \qmlproperty color SystemPalette::buttonText
+ The button text foreground color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::buttonText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::ButtonText);
+}
+
+/*!
+ \qmlproperty color SystemPalette::light
+ The light color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::light() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Light);
+}
+
+/*!
+ \qmlproperty color SystemPalette::midlight
+ The midlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::midlight() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Midlight);
+}
+
+/*!
+ \qmlproperty color SystemPalette::dark
+ The dark color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::dark() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Dark);
+}
+
+/*!
+ \qmlproperty color SystemPalette::mid
+ The mid color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::mid() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Mid);
+}
+
+/*!
+ \qmlproperty color SystemPalette::shadow
+ The shadow color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::shadow() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Shadow);
+}
+
+/*!
+ \qmlproperty color SystemPalette::highlight
+ The highlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::highlight() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Highlight);
+}
+
+/*!
+ \qmlproperty color SystemPalette::highlightedText
+ The highlighted text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::highlightedText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::HighlightedText);
+}
+
+/*!
+ \qmlproperty enumeration SystemPalette::colorGroup
+
+ The color group of the palette. This can be one of:
+
+ \list
+ \o SystemPalette.Active (default)
+ \o SystemPalette.Inactive
+ \o SystemPalette.Disabled
+ \endlist
+
+ \sa QPalette::ColorGroup
+*/
+QDeclarativeSystemPalette::ColorGroup QDeclarativeSystemPalette::colorGroup() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return (QDeclarativeSystemPalette::ColorGroup)d->group;
+}
+
+void QDeclarativeSystemPalette::setColorGroup(QDeclarativeSystemPalette::ColorGroup colorGroup)
+{
+ Q_D(QDeclarativeSystemPalette);
+ d->group = (QPalette::ColorGroup)colorGroup;
+ emit paletteChanged();
+}
+
+bool QDeclarativeSystemPalette::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched == qApp) {
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
+ return false;
+ }
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+bool QDeclarativeSystemPalette::event(QEvent *event)
+{
+ Q_D(QDeclarativeSystemPalette);
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ d->palette = QApplication::palette();
+ emit paletteChanged();
+ return true;
+ }
+ return QObject::event(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativesystempalette_p.h b/src/declarative/util/qdeclarativesystempalette_p.h
new file mode 100644
index 0000000000..609d6d4ffb
--- /dev/null
+++ b/src/declarative/util/qdeclarativesystempalette_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 QDECLARATIVESYSTEMPALETTE_H
+#define QDECLARATIVESYSTEMPALETTE_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QPalette>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeSystemPalettePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSystemPalette : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ColorGroup)
+ Q_DECLARE_PRIVATE(QDeclarativeSystemPalette)
+
+ Q_PROPERTY(QDeclarativeSystemPalette::ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY paletteChanged)
+ Q_PROPERTY(QColor window READ window NOTIFY paletteChanged)
+ Q_PROPERTY(QColor windowText READ windowText NOTIFY paletteChanged)
+ Q_PROPERTY(QColor base READ base NOTIFY paletteChanged)
+ Q_PROPERTY(QColor text READ text NOTIFY paletteChanged)
+ Q_PROPERTY(QColor alternateBase READ alternateBase NOTIFY paletteChanged)
+ Q_PROPERTY(QColor button READ button NOTIFY paletteChanged)
+ Q_PROPERTY(QColor buttonText READ buttonText NOTIFY paletteChanged)
+ Q_PROPERTY(QColor light READ light NOTIFY paletteChanged)
+ Q_PROPERTY(QColor midlight READ midlight NOTIFY paletteChanged)
+ Q_PROPERTY(QColor dark READ dark NOTIFY paletteChanged)
+ Q_PROPERTY(QColor mid READ mid NOTIFY paletteChanged)
+ Q_PROPERTY(QColor shadow READ shadow NOTIFY paletteChanged)
+ Q_PROPERTY(QColor highlight READ highlight NOTIFY paletteChanged)
+ Q_PROPERTY(QColor highlightedText READ highlightedText NOTIFY paletteChanged)
+
+public:
+ QDeclarativeSystemPalette(QObject *parent=0);
+ ~QDeclarativeSystemPalette();
+
+ enum ColorGroup { Active = QPalette::Active, Inactive = QPalette::Inactive, Disabled = QPalette::Disabled };
+
+ QColor window() const;
+ QColor windowText() const;
+
+ QColor base() const;
+ QColor text() const;
+ QColor alternateBase() const;
+
+ QColor button() const;
+ QColor buttonText() const;
+
+ QColor light() const;
+ QColor midlight() const;
+ QColor dark() const;
+ QColor mid() const;
+ QColor shadow() const;
+
+ QColor highlight() const;
+ QColor highlightedText() const;
+
+ QDeclarativeSystemPalette::ColorGroup colorGroup() const;
+ void setColorGroup(QDeclarativeSystemPalette::ColorGroup);
+
+Q_SIGNALS:
+ void paletteChanged();
+
+private:
+ bool eventFilter(QObject *watched, QEvent *event);
+ bool event(QEvent *event);
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSystemPalette)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESYSTEMPALETTE_H
diff --git a/src/declarative/util/qdeclarativetimeline.cpp b/src/declarative/util/qdeclarativetimeline.cpp
new file mode 100644
index 0000000000..7ed3b6a9de
--- /dev/null
+++ b/src/declarative/util/qdeclarativetimeline.cpp
@@ -0,0 +1,947 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetimeline_p_p.h"
+
+#include <QDebug>
+#include <QMutex>
+#include <QThread>
+#include <QWaitCondition>
+#include <QEvent>
+#include <QCoreApplication>
+#include <QEasingCurve>
+#include <QTime>
+
+QT_BEGIN_NAMESPACE
+
+struct Update {
+ Update(QDeclarativeTimeLineValue *_g, qreal _v)
+ : g(_g), v(_v) {}
+ Update(const QDeclarativeTimeLineCallback &_e)
+ : g(0), v(0), e(_e) {}
+
+ QDeclarativeTimeLineValue *g;
+ qreal v;
+ QDeclarativeTimeLineCallback e;
+};
+
+struct QDeclarativeTimeLinePrivate
+{
+ QDeclarativeTimeLinePrivate(QDeclarativeTimeLine *);
+
+ struct Op {
+ enum Type {
+ Pause,
+ Set,
+ Move,
+ MoveBy,
+ Accel,
+ AccelDistance,
+ Execute
+ };
+ Op() {}
+ Op(Type t, int l, qreal v, qreal v2, int o,
+ const QDeclarativeTimeLineCallback &ev = QDeclarativeTimeLineCallback(), const QEasingCurve &es = QEasingCurve())
+ : type(t), length(l), value(v), value2(v2), order(o), event(ev),
+ easing(es) {}
+ Op(const Op &o)
+ : type(o.type), length(o.length), value(o.value), value2(o.value2),
+ order(o.order), event(o.event), easing(o.easing) {}
+ Op &operator=(const Op &o) {
+ type = o.type; length = o.length; value = o.value;
+ value2 = o.value2; order = o.order; event = o.event;
+ easing = o.easing;
+ return *this;
+ }
+
+ Type type;
+ int length;
+ qreal value;
+ qreal value2;
+
+ int order;
+ QDeclarativeTimeLineCallback event;
+ QEasingCurve easing;
+ };
+ struct TimeLine
+ {
+ TimeLine() : length(0), consumedOpLength(0), base(0.) {}
+ QList<Op> ops;
+ int length;
+ int consumedOpLength;
+ qreal base;
+ };
+
+ int length;
+ int syncPoint;
+ typedef QHash<QDeclarativeTimeLineObject *, TimeLine> Ops;
+ Ops ops;
+ QDeclarativeTimeLine *q;
+
+ void add(QDeclarativeTimeLineObject &, const Op &);
+ qreal value(const Op &op, int time, qreal base, bool *) const;
+
+ int advance(int);
+
+ bool clockRunning;
+ int prevTime;
+
+ int order;
+
+ QDeclarativeTimeLine::SyncMode syncMode;
+ int syncAdj;
+ QList<QPair<int, Update> > *updateQueue;
+};
+
+QDeclarativeTimeLinePrivate::QDeclarativeTimeLinePrivate(QDeclarativeTimeLine *parent)
+: length(0), syncPoint(0), q(parent), clockRunning(false), prevTime(0), order(0), syncMode(QDeclarativeTimeLine::LocalSync), syncAdj(0), updateQueue(0)
+{
+}
+
+void QDeclarativeTimeLinePrivate::add(QDeclarativeTimeLineObject &g, const Op &o)
+{
+ if (g._t && g._t != q) {
+ qWarning() << "QDeclarativeTimeLine: Cannot modify a QDeclarativeTimeLineValue owned by"
+ << "another timeline.";
+ return;
+ }
+ g._t = q;
+
+ Ops::Iterator iter = ops.find(&g);
+ if (iter == ops.end()) {
+ iter = ops.insert(&g, TimeLine());
+ if (syncPoint > 0)
+ q->pause(g, syncPoint);
+ }
+ if (!iter->ops.isEmpty() &&
+ o.type == Op::Pause &&
+ iter->ops.last().type == Op::Pause) {
+ iter->ops.last().length += o.length;
+ iter->length += o.length;
+ } else {
+ iter->ops.append(o);
+ iter->length += o.length;
+ }
+
+ if (iter->length > length)
+ length = iter->length;
+
+ if (!clockRunning) {
+ q->stop();
+ prevTime = 0;
+ clockRunning = true;
+
+ if (syncMode == QDeclarativeTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ q->start();
+/* q->tick(0);
+ if (syncMode == QDeclarativeTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ */
+ }
+}
+
+qreal QDeclarativeTimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const
+{
+ Q_ASSERT(time >= 0);
+ Q_ASSERT(time <= op.length);
+ *changed = true;
+
+ switch(op.type) {
+ case Op::Pause:
+ *changed = false;
+ return base;
+ case Op::Set:
+ return op.value;
+ case Op::Move:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return op.value;
+ } else {
+ qreal delta = op.value - base;
+ qreal pTime = (qreal)(time) / (qreal)op.length;
+ if (op.easing.type() == QEasingCurve::Linear)
+ return base + delta * pTime;
+ else
+ return base + delta * op.easing.valueForProgress(pTime);
+ }
+ case Op::MoveBy:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return base + op.value;
+ } else {
+ qreal delta = op.value;
+ qreal pTime = (qreal)(time) / (qreal)op.length;
+ if (op.easing.type() == QEasingCurve::Linear)
+ return base + delta * pTime;
+ else
+ return base + delta * op.easing.valueForProgress(pTime);
+ }
+ case Op::Accel:
+ if (time == 0) {
+ return base;
+ } else {
+ qreal t = (qreal)(time) / 1000.0f;
+ qreal delta = op.value * t + 0.5f * op.value2 * t * t;
+ return base + delta;
+ }
+ case Op::AccelDistance:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return base + op.value2;
+ } else {
+ qreal t = (qreal)(time) / 1000.0f;
+ qreal accel = -1.0f * 1000.0f * op.value / (qreal)op.length;
+ qreal delta = op.value * t + 0.5f * accel * t * t;
+ return base + delta;
+
+ }
+ case Op::Execute:
+ op.event.d0(op.event.d1);
+ *changed = false;
+ return -1;
+ }
+
+ return base;
+}
+
+/*!
+ \internal
+ \class QDeclarativeTimeLine
+ \brief The QDeclarativeTimeLine class provides a timeline for controlling animations.
+
+ QDeclarativeTimeLine is similar to QTimeLine except:
+ \list
+ \i It updates QDeclarativeTimeLineValue instances directly, rather than maintaining a single
+ current value.
+
+ For example, the following animates a simple value over 200 milliseconds:
+ \code
+ QDeclarativeTimeLineValue v(<starting value>);
+ QDeclarativeTimeLine tl;
+ tl.move(v, 100., 200);
+ tl.start()
+ \endcode
+
+ If your program needs to know when values are changed, it can either
+ connect to the QDeclarativeTimeLine's updated() signal, or inherit from QDeclarativeTimeLineValue
+ and reimplement the QDeclarativeTimeLineValue::setValue() method.
+
+ \i Supports multiple QDeclarativeTimeLineValue, arbitrary start and end values and allows
+ animations to be strung together for more complex effects.
+
+ For example, the following animation moves the x and y coordinates of
+ an object from wherever they are to the position (100, 100) in 50
+ milliseconds and then further animates them to (100, 200) in 50
+ milliseconds:
+
+ \code
+ QDeclarativeTimeLineValue x(<starting value>);
+ QDeclarativeTimeLineValue y(<starting value>);
+
+ QDeclarativeTimeLine tl;
+ tl.start();
+
+ tl.move(x, 100., 50);
+ tl.move(y, 100., 50);
+ tl.move(y, 200., 50);
+ \endcode
+
+ \i All QDeclarativeTimeLine instances share a single, synchronized clock.
+
+ Actions scheduled within the same event loop tick are scheduled
+ synchronously against each other, regardless of the wall time between the
+ scheduling. Synchronized scheduling applies both to within the same
+ QDeclarativeTimeLine and across separate QDeclarativeTimeLine's within the same process.
+
+ \endlist
+
+ Currently easing functions are not supported.
+*/
+
+
+/*!
+ Construct a new QDeclarativeTimeLine with the specified \a parent.
+*/
+QDeclarativeTimeLine::QDeclarativeTimeLine(QObject *parent)
+: QAbstractAnimation(parent)
+{
+ d = new QDeclarativeTimeLinePrivate(this);
+}
+
+/*!
+ Destroys the time line. Any inprogress animations are canceled, but not
+ completed.
+*/
+QDeclarativeTimeLine::~QDeclarativeTimeLine()
+{
+ for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter)
+ iter.key()->_t = 0;
+
+ delete d; d = 0;
+}
+
+/*!
+ \enum QDeclarativeTimeLine::SyncMode
+ */
+
+/*!
+ Return the timeline's synchronization mode.
+ */
+QDeclarativeTimeLine::SyncMode QDeclarativeTimeLine::syncMode() const
+{
+ return d->syncMode;
+}
+
+/*!
+ Set the timeline's synchronization mode to \a syncMode.
+ */
+void QDeclarativeTimeLine::setSyncMode(SyncMode syncMode)
+{
+ d->syncMode = syncMode;
+}
+
+/*!
+ Pause \a obj for \a time milliseconds.
+*/
+void QDeclarativeTimeLine::pause(QDeclarativeTimeLineObject &obj, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
+ d->add(obj, op);
+}
+
+/*!
+ Execute the \a event.
+ */
+void QDeclarativeTimeLine::callback(const QDeclarativeTimeLineCallback &callback)
+{
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, callback);
+ d->add(*callback.callbackObject(), op);
+}
+
+/*!
+ Set the \a value of \a timeLineValue.
+*/
+void QDeclarativeTimeLine::set(QDeclarativeTimeLineValue &timeLineValue, qreal value)
+{
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Set, 0, value, 0., d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Decelerate \a timeLineValue from the starting \a velocity to zero at the
+ given \a acceleration rate. Although the \a acceleration is technically
+ a deceleration, it should always be positive. The QDeclarativeTimeLine will ensure
+ that the deceleration is in the opposite direction to the initial velocity.
+*/
+int QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
+{
+ if (acceleration == 0.0f)
+ return -1;
+
+ if ((velocity > 0.0f) == (acceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+
+ int time = static_cast<int>(-1000 * velocity / acceleration);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ \overload
+
+ Decelerate \a timeLineValue from the starting \a velocity to zero at the
+ given \a acceleration rate over a maximum distance of maxDistance.
+
+ If necessary, QDeclarativeTimeLine will reduce the acceleration to ensure that the
+ entire operation does not require a move of more than \a maxDistance.
+ \a maxDistance should always be positive.
+*/
+int QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
+{
+ if (maxDistance == 0.0f || acceleration == 0.0f)
+ return -1;
+
+ Q_ASSERT(acceleration > 0.0f && maxDistance > 0.0f);
+
+ qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance);
+ if (maxAccel > acceleration)
+ acceleration = maxAccel;
+
+ if ((velocity > 0.0f) == (acceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+
+ int time = static_cast<int>(-1000 * velocity / acceleration);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ Decelerate \a timeLineValue from the starting \a velocity to zero over the given
+ \a distance. This is like accel(), but the QDeclarativeTimeLine calculates the exact
+ deceleration to use.
+
+ \a distance should be positive.
+*/
+int QDeclarativeTimeLine::accelDistance(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal distance)
+{
+ if (distance == 0.0f || velocity == 0.0f)
+ return -1;
+
+ Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f));
+
+ int time = static_cast<int>(1000 * (2.0f * distance) / velocity);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ Linearly change the \a timeLineValue from its current value to the given
+ \a destination value over \a time milliseconds.
+*/
+void QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Change the \a timeLineValue from its current value to the given \a destination
+ value over \a time milliseconds using the \a easing curve.
+ */
+void QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QDeclarativeTimeLineCallback(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Linearly change the \a timeLineValue from its current value by the \a change amount
+ over \a time milliseconds.
+*/
+void QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Change the \a timeLineValue from its current value by the \a change amount over
+ \a time milliseconds using the \a easing curve.
+ */
+void QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QDeclarativeTimeLineCallback(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Cancel (but don't complete) all scheduled actions for \a timeLineValue.
+*/
+void QDeclarativeTimeLine::reset(QDeclarativeTimeLineValue &timeLineValue)
+{
+ if (!timeLineValue._t)
+ return;
+ if (timeLineValue._t != this) {
+ qWarning() << "QDeclarativeTimeLine: Cannot reset a QDeclarativeTimeLineValue owned by another timeline.";
+ return;
+ }
+ remove(&timeLineValue);
+ timeLineValue._t = 0;
+}
+
+int QDeclarativeTimeLine::duration() const
+{
+ return -1;
+}
+
+/*!
+ Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo
+ within this timeline.
+
+ Following operations on \a timeLineValue in this timeline will be scheduled after
+ all the currently scheduled actions on \a syncTo are complete. In
+ pseudo-code this is equivalent to:
+ \code
+ QDeclarativeTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
+ \endcode
+*/
+void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue, QDeclarativeTimeLineValue &syncTo)
+{
+ QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo);
+ if (iter == d->ops.end())
+ return;
+ int length = iter->length;
+
+ iter = d->ops.find(&timeLineValue);
+ if (iter == d->ops.end()) {
+ pause(timeLineValue, length);
+ } else {
+ int glength = iter->length;
+ pause(timeLineValue, length - glength);
+ }
+}
+
+/*!
+ Synchronize the end point of \a timeLineValue to the endpoint of the longest
+ action cursrently scheduled in the timeline.
+
+ In pseudo-code, this is equivalent to:
+ \code
+ QDeclarativeTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
+ \endcode
+*/
+void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue)
+{
+ QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue);
+ if (iter == d->ops.end()) {
+ pause(timeLineValue, d->length);
+ } else {
+ pause(timeLineValue, d->length - iter->length);
+ }
+}
+
+/*
+ Synchronize all currently and future scheduled values in this timeline to
+ the longest action currently scheduled.
+
+ For example:
+ \code
+ value1->setValue(0.);
+ value2->setValue(0.);
+ value3->setValue(0.);
+ QDeclarativeTimeLine tl;
+ ...
+ tl.move(value1, 10, 200);
+ tl.move(value2, 10, 100);
+ tl.sync();
+ tl.move(value2, 20, 100);
+ tl.move(value3, 20, 100);
+ \endcode
+
+ will result in:
+
+ \table
+ \header \o \o 0ms \o 50ms \o 100ms \o 150ms \o 200ms \o 250ms \o 300ms
+ \row \o value1 \o 0 \o 2.5 \o 5.0 \o 7.5 \o 10 \o 10 \o 10
+ \row \o value2 \o 0 \o 5.0 \o 10.0 \o 10.0 \o 10.0 \o 15.0 \o 20.0
+ \row \o value2 \o 0 \o 0 \o 0 \o 0 \o 0 \o 10.0 \o 20.0
+ \endtable
+*/
+
+/*void QDeclarativeTimeLine::sync()
+{
+ for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter)
+ pause(*iter.key(), d->length - iter->length);
+ d->syncPoint = d->length;
+}*/
+
+/*!
+ \internal
+
+ Temporary hack.
+ */
+void QDeclarativeTimeLine::setSyncPoint(int sp)
+{
+ d->syncPoint = sp;
+}
+
+/*!
+ \internal
+
+ Temporary hack.
+ */
+int QDeclarativeTimeLine::syncPoint() const
+{
+ return d->syncPoint;
+}
+
+/*!
+ Returns true if the timeline is active. An active timeline is one where
+ QDeclarativeTimeLineValue actions are still pending.
+*/
+bool QDeclarativeTimeLine::isActive() const
+{
+ return !d->ops.isEmpty();
+}
+
+/*!
+ Completes the timeline. All queued actions are played to completion, and then discarded. For example,
+ \code
+ QDeclarativeTimeLineValue v(0.);
+ QDeclarativeTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.complete();
+ // v.value() == 100.
+ \endcode
+*/
+void QDeclarativeTimeLine::complete()
+{
+ d->advance(d->length);
+}
+
+/*!
+ Resets the timeline. All queued actions are discarded and QDeclarativeTimeLineValue's retain their current value. For example,
+ \code
+ QDeclarativeTimeLineValue v(0.);
+ QDeclarativeTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.clear();
+ // v.value() == 50.
+ \endcode
+*/
+void QDeclarativeTimeLine::clear()
+{
+ for (QDeclarativeTimeLinePrivate::Ops::ConstIterator iter = d->ops.begin(); iter != d->ops.end(); ++iter)
+ iter.key()->_t = 0;
+ d->ops.clear();
+ d->length = 0;
+ d->syncPoint = 0;
+ //XXX need stop here?
+}
+
+int QDeclarativeTimeLine::time() const
+{
+ return d->prevTime;
+}
+
+/*!
+ \fn void QDeclarativeTimeLine::updated()
+
+ Emitted each time the timeline modifies QDeclarativeTimeLineValues. Even if multiple
+ QDeclarativeTimeLineValues are changed, this signal is only emitted once for each clock tick.
+*/
+
+void QDeclarativeTimeLine::updateCurrentTime(int v)
+{
+ if (d->syncAdj == -1)
+ d->syncAdj = v;
+ v -= d->syncAdj;
+
+ int timeChanged = v - d->prevTime;
+#if 0
+ if (!timeChanged)
+ return;
+#endif
+ d->prevTime = v;
+ d->advance(timeChanged);
+ emit updated();
+
+ // Do we need to stop the clock?
+ if (d->ops.isEmpty()) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = false;
+ emit completed();
+ } /*else if (pauseTime > 0) {
+ GfxClock::cancelClock();
+ d->prevTime = 0;
+ GfxClock::pauseFor(pauseTime);
+ d->syncAdj = 0;
+ d->clockRunning = false;
+ }*/ else if (/*!GfxClock::isActive()*/ state() != Running) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = true;
+ d->syncAdj = 0;
+ start();
+ }
+}
+
+bool operator<(const QPair<int, Update> &lhs,
+ const QPair<int, Update> &rhs)
+{
+ return lhs.first < rhs.first;
+}
+
+int QDeclarativeTimeLinePrivate::advance(int t)
+{
+ int pauseTime = -1;
+
+ // XXX - surely there is a more efficient way?
+ do {
+ pauseTime = -1;
+ // Minimal advance time
+ int advanceTime = t;
+ for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ++iter) {
+ TimeLine &tl = *iter;
+ Op &op = tl.ops.first();
+ int length = op.length - tl.consumedOpLength;
+
+ if (length < advanceTime) {
+ advanceTime = length;
+ if (advanceTime == 0)
+ break;
+ }
+ }
+ t -= advanceTime;
+
+ // Process until then. A zero length advance time will only process
+ // sets.
+ QList<QPair<int, Update> > updates;
+
+ for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ) {
+ QDeclarativeTimeLineValue *v = static_cast<QDeclarativeTimeLineValue *>(iter.key());
+ TimeLine &tl = *iter;
+ Q_ASSERT(!tl.ops.isEmpty());
+
+ do {
+ Op &op = tl.ops.first();
+ if (advanceTime == 0 && op.length != 0)
+ continue;
+
+ if (tl.consumedOpLength == 0 &&
+ op.type != Op::Pause &&
+ op.type != Op::Execute)
+ tl.base = v->value();
+
+ if ((tl.consumedOpLength + advanceTime) == op.length) {
+ if (op.type == Op::Execute) {
+ updates << qMakePair(op.order, Update(op.event));
+ } else {
+ bool changed = false;
+ qreal val = value(op, op.length, tl.base, &changed);
+ if (changed)
+ updates << qMakePair(op.order, Update(v, val));
+ }
+ tl.length -= qMin(advanceTime, tl.length);
+ tl.consumedOpLength = 0;
+ tl.ops.removeFirst();
+ } else {
+ tl.consumedOpLength += advanceTime;
+ bool changed = false;
+ qreal val = value(op, tl.consumedOpLength, tl.base, &changed);
+ if (changed)
+ updates << qMakePair(op.order, Update(v, val));
+ tl.length -= qMin(advanceTime, tl.length);
+ break;
+ }
+
+ } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0);
+
+
+ if (tl.ops.isEmpty()) {
+ iter = ops.erase(iter);
+ v->_t = 0;
+ } else {
+ if (tl.ops.first().type == Op::Pause && pauseTime != 0) {
+ int opPauseTime = tl.ops.first().length - tl.consumedOpLength;
+ if (pauseTime == -1 || opPauseTime < pauseTime)
+ pauseTime = opPauseTime;
+ } else {
+ pauseTime = 0;
+ }
+ ++iter;
+ }
+ }
+
+ length -= qMin(length, advanceTime);
+ syncPoint -= advanceTime;
+
+ qSort(updates.begin(), updates.end());
+ updateQueue = &updates;
+ for (int ii = 0; ii < updates.count(); ++ii) {
+ const Update &v = updates.at(ii).second;
+ if (v.g) {
+ v.g->setValue(v.v);
+ } else {
+ v.e.d0(v.e.d1);
+ }
+ }
+ updateQueue = 0;
+ } while(t);
+
+ return pauseTime;
+}
+
+void QDeclarativeTimeLine::remove(QDeclarativeTimeLineObject *v)
+{
+ QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(v);
+ Q_ASSERT(iter != d->ops.end());
+
+ int len = iter->length;
+ d->ops.erase(iter);
+ if (len == d->length) {
+ // We need to recalculate the length
+ d->length = 0;
+ for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter) {
+
+ if (iter->length > d->length)
+ d->length = iter->length;
+
+ }
+ }
+ if (d->ops.isEmpty()) {
+ stop();
+ d->clockRunning = false;
+ } else if (/*!GfxClock::isActive()*/ state() != Running) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = true;
+
+ if (d->syncMode == QDeclarativeTimeLine::LocalSync) {
+ d->syncAdj = -1;
+ } else {
+ d->syncAdj = 0;
+ }
+ start();
+ }
+
+ if (d->updateQueue) {
+ for (int ii = 0; ii < d->updateQueue->count(); ++ii) {
+ if (d->updateQueue->at(ii).second.g == v ||
+ d->updateQueue->at(ii).second.e.callbackObject() == v) {
+ d->updateQueue->removeAt(ii);
+ --ii;
+ }
+ }
+ }
+
+
+}
+
+/*!
+ \internal
+ \class QDeclarativeTimeLineValue
+ \brief The QDeclarativeTimeLineValue class provides a value that can be modified by QDeclarativeTimeLine.
+*/
+
+/*!
+ \fn QDeclarativeTimeLineValue::QDeclarativeTimeLineValue(qreal value = 0)
+
+ Construct a new QDeclarativeTimeLineValue with an initial \a value.
+*/
+
+/*!
+ \fn qreal QDeclarativeTimeLineValue::value() const
+
+ Return the current value.
+*/
+
+/*!
+ \fn void QDeclarativeTimeLineValue::setValue(qreal value)
+
+ Set the current \a value.
+*/
+
+/*!
+ \fn QDeclarativeTimeLine *QDeclarativeTimeLineValue::timeLine() const
+
+ If a QDeclarativeTimeLine is operating on this value, return a pointer to it,
+ otherwise return null.
+*/
+
+
+QDeclarativeTimeLineObject::QDeclarativeTimeLineObject()
+: _t(0)
+{
+}
+
+QDeclarativeTimeLineObject::~QDeclarativeTimeLineObject()
+{
+ if (_t) {
+ _t->remove(this);
+ _t = 0;
+ }
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback()
+: d0(0), d1(0), d2(0)
+{
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback f, void *d)
+: d0(f), d1(d), d2(b)
+{
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o)
+: d0(o.d0), d1(o.d1), d2(o.d2)
+{
+}
+
+QDeclarativeTimeLineCallback &QDeclarativeTimeLineCallback::operator=(const QDeclarativeTimeLineCallback &o)
+{
+ d0 = o.d0;
+ d1 = o.d1;
+ d2 = o.d2;
+ return *this;
+}
+
+QDeclarativeTimeLineObject *QDeclarativeTimeLineCallback::callbackObject() const
+{
+ return d2;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativetimeline_p_p.h b/src/declarative/util/qdeclarativetimeline_p_p.h
new file mode 100644
index 0000000000..87362fae53
--- /dev/null
+++ b/src/declarative/util/qdeclarativetimeline_p_p.h
@@ -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 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 QDECLARATIVETIMELINE_H
+#define QDECLARATIVETIMELINE_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/QObject>
+#include <QtCore/QAbstractAnimation>
+
+QT_BEGIN_NAMESPACE
+
+class QEasingCurve;
+class QDeclarativeTimeLineValue;
+class QDeclarativeTimeLineCallback;
+struct QDeclarativeTimeLinePrivate;
+class QDeclarativeTimeLineObject;
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLine : public QAbstractAnimation
+{
+Q_OBJECT
+public:
+ QDeclarativeTimeLine(QObject *parent = 0);
+ ~QDeclarativeTimeLine();
+
+ enum SyncMode { LocalSync, GlobalSync };
+ SyncMode syncMode() const;
+ void setSyncMode(SyncMode);
+
+ void pause(QDeclarativeTimeLineObject &, int);
+ void callback(const QDeclarativeTimeLineCallback &);
+ void set(QDeclarativeTimeLineValue &, qreal);
+
+ int accel(QDeclarativeTimeLineValue &, qreal velocity, qreal accel);
+ int accel(QDeclarativeTimeLineValue &, qreal velocity, qreal accel, qreal maxDistance);
+ int accelDistance(QDeclarativeTimeLineValue &, qreal velocity, qreal distance);
+
+ void move(QDeclarativeTimeLineValue &, qreal destination, int time = 500);
+ void move(QDeclarativeTimeLineValue &, qreal destination, const QEasingCurve &, int time = 500);
+ void moveBy(QDeclarativeTimeLineValue &, qreal change, int time = 500);
+ void moveBy(QDeclarativeTimeLineValue &, qreal change, const QEasingCurve &, int time = 500);
+
+ void sync();
+ void setSyncPoint(int);
+ int syncPoint() const;
+
+ void sync(QDeclarativeTimeLineValue &);
+ void sync(QDeclarativeTimeLineValue &, QDeclarativeTimeLineValue &);
+
+ void reset(QDeclarativeTimeLineValue &);
+
+ void complete();
+ void clear();
+ bool isActive() const;
+
+ int time() const;
+
+ virtual int duration() const;
+Q_SIGNALS:
+ void updated();
+ void completed();
+
+protected:
+ virtual void updateCurrentTime(int);
+
+private:
+ void remove(QDeclarativeTimeLineObject *);
+ friend class QDeclarativeTimeLineObject;
+ friend struct QDeclarativeTimeLinePrivate;
+ QDeclarativeTimeLinePrivate *d;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineObject
+{
+public:
+ QDeclarativeTimeLineObject();
+ virtual ~QDeclarativeTimeLineObject();
+
+protected:
+ friend class QDeclarativeTimeLine;
+ friend struct QDeclarativeTimeLinePrivate;
+ QDeclarativeTimeLine *_t;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineValue : public QDeclarativeTimeLineObject
+{
+public:
+ QDeclarativeTimeLineValue(qreal v = 0.) : _v(v) {}
+
+ virtual qreal value() const { return _v; }
+ virtual void setValue(qreal v) { _v = v; }
+
+ QDeclarativeTimeLine *timeLine() const { return _t; }
+
+ operator qreal() const { return _v; }
+ QDeclarativeTimeLineValue &operator=(qreal v) { setValue(v); return *this; }
+private:
+ friend class QDeclarativeTimeLine;
+ friend struct QDeclarativeTimeLinePrivate;
+ qreal _v;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineCallback
+{
+public:
+ typedef void (*Callback)(void *);
+
+ QDeclarativeTimeLineCallback();
+ QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback, void * = 0);
+ QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o);
+
+ QDeclarativeTimeLineCallback &operator=(const QDeclarativeTimeLineCallback &o);
+ QDeclarativeTimeLineObject *callbackObject() const;
+
+private:
+ friend struct QDeclarativeTimeLinePrivate;
+ Callback d0;
+ void *d1;
+ QDeclarativeTimeLineObject *d2;
+};
+
+template<class T>
+class QDeclarativeTimeLineValueProxy : public QDeclarativeTimeLineValue
+{
+public:
+ QDeclarativeTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.)
+ : QDeclarativeTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0)
+ {
+ Q_ASSERT(_class);
+ }
+
+ QDeclarativeTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.)
+ : QDeclarativeTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func)
+ {
+ Q_ASSERT(_class);
+ }
+
+ virtual void setValue(qreal v)
+ {
+ QDeclarativeTimeLineValue::setValue(v);
+ if (_setFunctionReal) (_class->*_setFunctionReal)(v);
+ else if (_setFunctionInt) (_class->*_setFunctionInt)((int)v);
+ }
+
+private:
+ T *_class;
+ void (T::*_setFunctionReal)(qreal);
+ void (T::*_setFunctionInt)(int);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/util/qdeclarativetimer.cpp b/src/declarative/util/qdeclarativetimer.cpp
new file mode 100644
index 0000000000..14daf5d991
--- /dev/null
+++ b/src/declarative/util/qdeclarativetimer.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetimer_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpauseanimation.h>
+#include <qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+
+class QDeclarativeTimerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTimer)
+public:
+ QDeclarativeTimerPrivate()
+ : interval(1000), running(false), repeating(false), triggeredOnStart(false)
+ , classBegun(false), componentComplete(false), firstTick(true) {}
+ int interval;
+ QPauseAnimation pause;
+ bool running : 1;
+ bool repeating : 1;
+ bool triggeredOnStart : 1;
+ bool classBegun : 1;
+ bool componentComplete : 1;
+ bool firstTick : 1;
+};
+
+/*!
+ \qmlclass Timer QDeclarativeTimer
+ \ingroup qml-utility-elements
+ \since 4.7
+ \brief The Timer item triggers a handler at a specified interval.
+
+ A Timer can be used to trigger an action either once, or repeatedly
+ at a given interval.
+
+ Here is a Timer that shows the current date and time, and updates
+ the text every 500 milliseconds. It uses the JavaScript \c Date
+ object to access the current time.
+
+ \qml
+ import QtQuick 1.0
+
+ Item {
+ Timer {
+ interval: 500; running: true; repeat: true
+ onTriggered: time.text = Date().toString()
+ }
+
+ Text { id: time }
+ }
+ \endqml
+
+ The Timer element is synchronized with the animation timer. Since the animation
+ timer is usually set to 60fps, the resolution of Timer will be
+ at best 16ms.
+
+ If the Timer is running and one of its properties is changed, the
+ elapsed time will be reset. For example, if a Timer with interval of
+ 1000ms has its \e repeat property changed 500ms after starting, the
+ elapsed time will be reset to 0, and the Timer will be triggered
+ 1000ms later.
+
+ \sa {declarative/toys/clocks}{Clocks example}
+*/
+
+QDeclarativeTimer::QDeclarativeTimer(QObject *parent)
+ : QObject(*(new QDeclarativeTimerPrivate), parent)
+{
+ Q_D(QDeclarativeTimer);
+ connect(&d->pause, SIGNAL(currentLoopChanged(int)), this, SLOT(ticked()));
+ connect(&d->pause, SIGNAL(finished()), this, SLOT(finished()));
+ d->pause.setLoopCount(1);
+ d->pause.setDuration(d->interval);
+}
+
+/*!
+ \qmlproperty int Timer::interval
+
+ Sets the \a interval between triggers, in milliseconds.
+
+ The default interval is 1000 milliseconds.
+*/
+void QDeclarativeTimer::setInterval(int interval)
+{
+ Q_D(QDeclarativeTimer);
+ if (interval != d->interval) {
+ d->interval = interval;
+ update();
+ emit intervalChanged();
+ }
+}
+
+int QDeclarativeTimer::interval() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->interval;
+}
+
+/*!
+ \qmlproperty bool Timer::running
+
+ If set to true, starts the timer; otherwise stops the timer.
+ For a non-repeating timer, \a running is set to false after the
+ timer has been triggered.
+
+ \a running defaults to false.
+
+ \sa repeat
+*/
+bool QDeclarativeTimer::isRunning() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->running;
+}
+
+void QDeclarativeTimer::setRunning(bool running)
+{
+ Q_D(QDeclarativeTimer);
+ if (d->running != running) {
+ d->running = running;
+ d->firstTick = true;
+ emit runningChanged();
+ update();
+ }
+}
+
+/*!
+ \qmlproperty bool Timer::repeat
+
+ If \a repeat is true the timer is triggered repeatedly at the
+ specified interval; otherwise, the timer will trigger once at the
+ specified interval and then stop (i.e. running will be set to false).
+
+ \a repeat defaults to false.
+
+ \sa running
+*/
+bool QDeclarativeTimer::isRepeating() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->repeating;
+}
+
+void QDeclarativeTimer::setRepeating(bool repeating)
+{
+ Q_D(QDeclarativeTimer);
+ if (repeating != d->repeating) {
+ d->repeating = repeating;
+ update();
+ emit repeatChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool Timer::triggeredOnStart
+
+ When a timer is started, the first trigger is usually after the specified
+ interval has elapsed. It is sometimes desirable to trigger immediately
+ when the timer is started; for example, to establish an initial
+ state.
+
+ If \a triggeredOnStart is true, the timer is triggered immediately
+ when started, and subsequently at the specified interval. Note that if
+ \e repeat is set to false, the timer is triggered twice; once on start,
+ and again at the interval.
+
+ \a triggeredOnStart defaults to false.
+
+ \sa running
+*/
+bool QDeclarativeTimer::triggeredOnStart() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->triggeredOnStart;
+}
+
+void QDeclarativeTimer::setTriggeredOnStart(bool triggeredOnStart)
+{
+ Q_D(QDeclarativeTimer);
+ if (d->triggeredOnStart != triggeredOnStart) {
+ d->triggeredOnStart = triggeredOnStart;
+ update();
+ emit triggeredOnStartChanged();
+ }
+}
+
+/*!
+ \qmlmethod Timer::start()
+ \brief Starts the timer.
+
+ If the timer is already running, calling this method has no effect. The
+ \c running property will be true following a call to \c start().
+*/
+void QDeclarativeTimer::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod Timer::stop()
+ \brief Stops the timer.
+
+ If the timer is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c stop().
+*/
+void QDeclarativeTimer::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod Timer::restart()
+ \brief Restarts the timer.
+
+ If the Timer is not running it will be started, otherwise it will be
+ stopped, reset to initial state and started. The \c running property
+ will be true following a call to \c restart().
+*/
+void QDeclarativeTimer::restart()
+{
+ setRunning(false);
+ setRunning(true);
+}
+
+void QDeclarativeTimer::update()
+{
+ Q_D(QDeclarativeTimer);
+ if (d->classBegun && !d->componentComplete)
+ return;
+ d->pause.stop();
+ if (d->running) {
+ d->pause.setCurrentTime(0);
+ d->pause.setLoopCount(d->repeating ? -1 : 1);
+ d->pause.setDuration(d->interval);
+ d->pause.start();
+ if (d->triggeredOnStart && d->firstTick) {
+ QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
+ QMetaObject::invokeMethod(this, "ticked", Qt::QueuedConnection);
+ }
+ }
+}
+
+void QDeclarativeTimer::classBegin()
+{
+ Q_D(QDeclarativeTimer);
+ d->classBegun = true;
+}
+
+void QDeclarativeTimer::componentComplete()
+{
+ Q_D(QDeclarativeTimer);
+ d->componentComplete = true;
+ update();
+}
+
+/*!
+ \qmlsignal Timer::onTriggered()
+
+ This handler is called when the Timer is triggered.
+*/
+void QDeclarativeTimer::ticked()
+{
+ Q_D(QDeclarativeTimer);
+ if (d->running && (d->pause.currentTime() > 0 || (d->triggeredOnStart && d->firstTick)))
+ emit triggered();
+ d->firstTick = false;
+}
+
+void QDeclarativeTimer::finished()
+{
+ Q_D(QDeclarativeTimer);
+ if (d->repeating || !d->running)
+ return;
+ emit triggered();
+ d->running = false;
+ d->firstTick = false;
+ emit runningChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativetimer_p.h b/src/declarative/util/qdeclarativetimer_p.h
new file mode 100644
index 0000000000..ec06eb5d0b
--- /dev/null
+++ b/src/declarative/util/qdeclarativetimer_p.h
@@ -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 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 QDECLARATIVETIMER_H
+#define QDECLARATIVETIMER_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractanimation.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeTimerPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeTimer : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeTimer)
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating NOTIFY repeatChanged)
+ Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart NOTIFY triggeredOnStartChanged)
+ Q_PROPERTY(QObject *parent READ parent CONSTANT)
+
+public:
+ QDeclarativeTimer(QObject *parent=0);
+
+ void setInterval(int interval);
+ int interval() const;
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+ bool isRepeating() const;
+ void setRepeating(bool repeating);
+
+ bool triggeredOnStart() const;
+ void setTriggeredOnStart(bool triggeredOnStart);
+
+protected:
+ void classBegin();
+ void componentComplete();
+
+public Q_SLOTS:
+ void start();
+ void stop();
+ void restart();
+
+Q_SIGNALS:
+ void triggered();
+ void runningChanged();
+ void intervalChanged();
+ void repeatChanged();
+ void triggeredOnStartChanged();
+
+private:
+ void update();
+
+private Q_SLOTS:
+ void ticked();
+ void finished();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTimer)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qdeclarativetransition.cpp b/src/declarative/util/qdeclarativetransition.cpp
new file mode 100644
index 0000000000..1a574b8960
--- /dev/null
+++ b/src/declarative/util/qdeclarativetransition.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativestate_p.h"
+#include "private/qdeclarativestategroup_p.h"
+#include "private/qdeclarativestate_p_p.h"
+#include "private/qdeclarativestateoperations_p.h"
+#include "private/qdeclarativeanimation_p.h"
+#include "private/qdeclarativeanimation_p_p.h"
+#include "private/qdeclarativetransitionmanager_p_p.h"
+
+#include <QParallelAnimationGroup>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Transition QDeclarativeTransition
+ \ingroup qml-animation-transition
+ \since 4.7
+ \brief The Transition element defines animated transitions that occur on state changes.
+
+ A Transition defines the animations to be applied when a \l State change occurs.
+
+ For example, the following \l Rectangle has two states: the default state, and
+ an added "moved" state. In the "moved state, the rectangle's position changes
+ to (50, 50). The added Transition specifies that when the rectangle
+ changes between the default and the "moved" state, any changes
+ to the \c x and \c y properties should be animated, using an \c Easing.InOutQuad.
+
+ \snippet doc/src/snippets/declarative/transition.qml 0
+
+ Notice the example does not require \l{PropertyAnimation::}{to} and
+ \l{PropertyAnimation::}{from} values for the NumberAnimation. As a convenience,
+ these properties are automatically set to the values of \c x and \c y before
+ and after the state change; the \c from values are provided by
+ the current values of \c x and \c y, and the \c to values are provided by
+ the PropertyChanges object. If you wish, you can provide \l{PropertyAnimation::}{to} and
+ \l{PropertyAnimation::}{from} values anyway to override the default values.
+
+ By default, a Transition's animations are applied for any state change in the
+ parent item. The Transition \l {Transition::}{from} and \l {Transition::}{to}
+ values can be set to restrict the animations to only be applied when changing
+ from one particular state to another.
+
+ To define multiple transitions, specify \l Item::transitions as a list:
+
+ \snippet doc/src/snippets/declarative/transitions-list.qml list of transitions
+
+ If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular
+ state change. In the example above, when changing to \c state1, the first transition will be used, rather
+ than the more generic second transition.
+
+ If a state change has a Transition that matches the same property as a
+ \l Behavior, the Transition animation overrides the \l Behavior for that
+ state change.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtDeclarative}
+*/
+
+//ParallelAnimationWrapper allows us to do a "callback" when the animation finishes, rather than connecting
+//and disconnecting signals and slots frequently
+class ParallelAnimationWrapper : public QParallelAnimationGroup
+{
+ Q_OBJECT
+public:
+ ParallelAnimationWrapper(QObject *parent = 0) : QParallelAnimationGroup(parent) {}
+ QDeclarativeTransitionPrivate *trans;
+protected:
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState);
+};
+
+class QDeclarativeTransitionPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTransition)
+public:
+ QDeclarativeTransitionPrivate()
+ : fromState(QLatin1String("*")), toState(QLatin1String("*")),
+ reversed(false), reversible(false), endState(0)
+ {
+ group.trans = this;
+ }
+
+ QString fromState;
+ QString toState;
+ bool reversed;
+ bool reversible;
+ ParallelAnimationWrapper group;
+ QDeclarativeTransitionManager *endState;
+
+ void complete()
+ {
+ endState->complete();
+ }
+ static void append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a);
+ QList<QDeclarativeAbstractAnimation *> animations;
+};
+
+void QDeclarativeTransitionPrivate::append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a)
+{
+ QDeclarativeTransition *q = static_cast<QDeclarativeTransition *>(list->object);
+ q->d_func()->animations.append(a);
+ q->d_func()->group.addAnimation(a->qtAnimation());
+ a->setDisableUserControl();
+}
+
+void ParallelAnimationWrapper::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+{
+ QParallelAnimationGroup::updateState(newState, oldState);
+ if (newState == Stopped && (duration() == -1
+ || (direction() == QAbstractAnimation::Forward && currentLoopTime() == duration())
+ || (direction() == QAbstractAnimation::Backward && currentLoopTime() == 0)))
+ {
+ trans->complete();
+ }
+}
+
+
+
+QDeclarativeTransition::QDeclarativeTransition(QObject *parent)
+ : QObject(*(new QDeclarativeTransitionPrivate), parent)
+{
+}
+
+QDeclarativeTransition::~QDeclarativeTransition()
+{
+}
+
+void QDeclarativeTransition::stop()
+{
+ Q_D(QDeclarativeTransition);
+ d->group.stop();
+}
+
+void QDeclarativeTransition::setReversed(bool r)
+{
+ Q_D(QDeclarativeTransition);
+ d->reversed = r;
+}
+
+void QDeclarativeTransition::prepare(QDeclarativeStateOperation::ActionList &actions,
+ QList<QDeclarativeProperty> &after,
+ QDeclarativeTransitionManager *endState)
+{
+ Q_D(QDeclarativeTransition);
+
+ qmlExecuteDeferred(this);
+
+ if (d->reversed) {
+ for (int ii = d->animations.count() - 1; ii >= 0; --ii) {
+ d->animations.at(ii)->transition(actions, after, QDeclarativeAbstractAnimation::Backward);
+ }
+ } else {
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ d->animations.at(ii)->transition(actions, after, QDeclarativeAbstractAnimation::Forward);
+ }
+ }
+
+ d->endState = endState;
+ d->group.setDirection(d->reversed ? QAbstractAnimation::Backward : QAbstractAnimation::Forward);
+ d->group.start();
+}
+
+/*!
+ \qmlproperty string Transition::from
+ \qmlproperty string Transition::to
+
+ These properties indicate the state changes that trigger the transition.
+
+ The default values for these properties is "*" (that is, any state).
+
+ For example, the following transition has not set the \c to and \c from
+ properties, so the animation is always applied when changing between
+ the two states (i.e. when the mouse is pressed and released).
+
+ \snippet doc/src/snippets/declarative/transition-from-to.qml 0
+
+ If the transition was changed to this:
+
+ \snippet doc/src/snippets/declarative/transition-from-to-modified.qml modified transition
+
+ The animation would only be applied when changing from the default state to
+ the "brighter" state (i.e. when the mouse is pressed, but not on release).
+
+ \sa reversible
+*/
+QString QDeclarativeTransition::fromState() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->fromState;
+}
+
+void QDeclarativeTransition::setFromState(const QString &f)
+{
+ Q_D(QDeclarativeTransition);
+ if (f == d->fromState)
+ return;
+
+ d->fromState = f;
+ emit fromChanged();
+}
+
+/*!
+ \qmlproperty bool Transition::reversible
+ This property holds whether the transition should be automatically reversed when the conditions that triggered this transition are reversed.
+
+ The default value is false.
+
+ By default, transitions run in parallel and are applied to all state
+ changes if the \l from and \l to states have not been set. In this
+ situation, the transition is automatically applied when a state change
+ is reversed, and it is not necessary to set this property to reverse
+ the transition.
+
+ However, if a SequentialAnimation is used, or if the \l from or \l to
+ properties have been set, this property will need to be set to reverse
+ a transition when a state change is reverted. For example, the following
+ transition applies a sequential animation when the mouse is pressed,
+ and reverses the sequence of the animation when the mouse is released:
+
+ \snippet doc/src/snippets/declarative/transition-reversible.qml 0
+
+ If the transition did not set the \c to and \c reversible values, then
+ on the mouse release, the transition would play the PropertyAnimation
+ before the ColorAnimation instead of reversing the sequence.
+*/
+bool QDeclarativeTransition::reversible() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->reversible;
+}
+
+void QDeclarativeTransition::setReversible(bool r)
+{
+ Q_D(QDeclarativeTransition);
+ if (r == d->reversible)
+ return;
+
+ d->reversible = r;
+ emit reversibleChanged();
+}
+
+QString QDeclarativeTransition::toState() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->toState;
+}
+
+void QDeclarativeTransition::setToState(const QString &t)
+{
+ Q_D(QDeclarativeTransition);
+ if (t == d->toState)
+ return;
+
+ d->toState = t;
+ emit toChanged();
+}
+
+/*!
+ \qmlproperty list<Animation> Transition::animations
+ \default
+
+ This property holds a list of the animations to be run for this transition.
+
+ \snippet examples/declarative/toys/dynamicscene/dynamicscene.qml top-level transitions
+
+ The top-level animations are run in parallel. To run them sequentially,
+ define them within a SequentialAnimation:
+
+ \snippet doc/src/snippets/declarative/transition-reversible.qml sequential animations
+*/
+QDeclarativeListProperty<QDeclarativeAbstractAnimation> QDeclarativeTransition::animations()
+{
+ Q_D(QDeclarativeTransition);
+ return QDeclarativeListProperty<QDeclarativeAbstractAnimation>(this, &d->animations, QDeclarativeTransitionPrivate::append_animation);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativetransition.moc>
diff --git a/src/declarative/util/qdeclarativetransition_p.h b/src/declarative/util/qdeclarativetransition_p.h
new file mode 100644
index 0000000000..501e5a8c4b
--- /dev/null
+++ b/src/declarative/util/qdeclarativetransition_p.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 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 QDECLARATIVETRANSITION_H
+#define QDECLARATIVETRANSITION_H
+
+#include "private/qdeclarativestate_p.h"
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeAbstractAnimation;
+class QDeclarativeTransitionPrivate;
+class QDeclarativeTransitionManager;
+class Q_DECLARATIVE_EXPORT QDeclarativeTransition : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeTransition)
+
+ Q_PROPERTY(QString from READ fromState WRITE setFromState NOTIFY fromChanged)
+ Q_PROPERTY(QString to READ toState WRITE setToState NOTIFY toChanged)
+ Q_PROPERTY(bool reversible READ reversible WRITE setReversible NOTIFY reversibleChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations READ animations)
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_CLASSINFO("DeferredPropertyNames", "animations")
+
+public:
+ QDeclarativeTransition(QObject *parent=0);
+ ~QDeclarativeTransition();
+
+ QString fromState() const;
+ void setFromState(const QString &);
+
+ QString toState() const;
+ void setToState(const QString &);
+
+ bool reversible() const;
+ void setReversible(bool);
+
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations();
+
+ void prepare(QDeclarativeStateOperation::ActionList &actions,
+ QList<QDeclarativeProperty> &after,
+ QDeclarativeTransitionManager *end);
+
+ void setReversed(bool r);
+ void stop();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void reversibleChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTransition)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVETRANSITION_H
diff --git a/src/declarative/util/qdeclarativetransitionmanager.cpp b/src/declarative/util/qdeclarativetransitionmanager.cpp
new file mode 100644
index 0000000000..b3196ee7a8
--- /dev/null
+++ b/src/declarative/util/qdeclarativetransitionmanager.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativetransitionmanager_p_p.h"
+
+#include "private/qdeclarativestate_p_p.h"
+#include "private/qdeclarativestate_p.h"
+
+#include <qdeclarativebinding_p.h>
+#include <qdeclarativeglobal_p.h>
+#include <qdeclarativeproperty_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+class QDeclarativeTransitionManagerPrivate
+{
+public:
+ QDeclarativeTransitionManagerPrivate()
+ : state(0), transition(0) {}
+
+ void applyBindings();
+ typedef QList<QDeclarativeSimpleAction> SimpleActionList;
+ QDeclarativeState *state;
+ QDeclarativeTransition *transition;
+ QDeclarativeStateOperation::ActionList bindingsList;
+ SimpleActionList completeList;
+};
+
+QDeclarativeTransitionManager::QDeclarativeTransitionManager()
+: d(new QDeclarativeTransitionManagerPrivate)
+{
+}
+
+void QDeclarativeTransitionManager::setState(QDeclarativeState *s)
+{
+ d->state = s;
+}
+
+QDeclarativeTransitionManager::~QDeclarativeTransitionManager()
+{
+ delete d; d = 0;
+}
+
+void QDeclarativeTransitionManager::complete()
+{
+ d->applyBindings();
+
+ for (int ii = 0; ii < d->completeList.count(); ++ii) {
+ const QDeclarativeProperty &prop = d->completeList.at(ii).property();
+ prop.write(d->completeList.at(ii).value());
+ }
+
+ d->completeList.clear();
+
+ if (d->state)
+ static_cast<QDeclarativeStatePrivate*>(QObjectPrivate::get(d->state))->complete();
+}
+
+void QDeclarativeTransitionManagerPrivate::applyBindings()
+{
+ foreach(const QDeclarativeAction &action, bindingsList) {
+ if (!action.toBinding.isNull()) {
+ QDeclarativePropertyPrivate::setBinding(action.property, action.toBinding.data());
+ } else if (action.event) {
+ if (action.reverseEvent)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+
+ }
+
+ bindingsList.clear();
+}
+
+void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &list,
+ QDeclarativeTransition *transition)
+{
+ cancel();
+
+ QDeclarativeStateOperation::ActionList applyList = list;
+ // Determine which actions are binding changes.
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.toBinding)
+ d->bindingsList << action;
+ if (action.fromBinding)
+ QDeclarativePropertyPrivate::setBinding(action.property, 0); // Disable current binding
+ if (action.event && action.event->changesBindings()) { //### assume isReversable()?
+ d->bindingsList << action;
+ action.event->clearBindings();
+ }
+ }
+
+ // Animated transitions need both the start and the end value for
+ // each property change. In the presence of bindings, the end values
+ // are non-trivial to calculate. As a "best effort" attempt, we first
+ // apply all the property and binding changes, then read all the actual
+ // final values, then roll back the changes and proceed as normal.
+ //
+ // This doesn't catch everything, and it might be a little fragile in
+ // some cases - but whatcha going to do?
+
+ if (!d->bindingsList.isEmpty()) {
+
+ // Apply all the property and binding changes
+ for (int ii = 0; ii < applyList.size(); ++ii) {
+ const QDeclarativeAction &action = applyList.at(ii);
+ if (!action.toBinding.isNull()) {
+ QDeclarativePropertyPrivate::setBinding(action.property, action.toBinding.data(), QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ } else if (!action.event) {
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ } else if (action.event->isReversable()) {
+ if (action.reverseEvent)
+ action.event->reverse(QDeclarativeActionEvent::FastForward);
+ else
+ action.event->execute(QDeclarativeActionEvent::FastForward);
+ }
+ }
+
+ // Read all the end values for binding changes
+ for (int ii = 0; ii < applyList.size(); ++ii) {
+ QDeclarativeAction *action = &applyList[ii];
+ if (action->event) {
+ action->event->saveTargetValues();
+ continue;
+ }
+ const QDeclarativeProperty &prop = action->property;
+ if (!action->toBinding.isNull() || !action->toValue.isValid()) {
+ action->toValue = prop.read();
+ }
+ }
+
+ // Revert back to the original values
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event) {
+ if (action.event->isReversable()) {
+ action.event->clearBindings();
+ action.event->rewind();
+ action.event->clearBindings(); //### shouldn't be needed
+ }
+ continue;
+ }
+
+ if (action.toBinding)
+ QDeclarativePropertyPrivate::setBinding(action.property, 0); // Make sure this is disabled during the transition
+
+ QDeclarativePropertyPrivate::write(action.property, action.fromValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+
+ if (transition) {
+ QList<QDeclarativeProperty> touched;
+ d->transition = transition;
+ d->transition->prepare(applyList, touched, this);
+
+ // Modify the action list to remove actions handled in the transition
+ for (int ii = 0; ii < applyList.count(); ++ii) {
+ const QDeclarativeAction &action = applyList.at(ii);
+
+ if (action.event) {
+
+ if (action.actionDone) {
+ applyList.removeAt(ii);
+ --ii;
+ }
+
+ } else {
+
+ if (touched.contains(action.property)) {
+ if (action.toValue != action.fromValue)
+ d->completeList <<
+ QDeclarativeSimpleAction(action, QDeclarativeSimpleAction::EndState);
+
+ applyList.removeAt(ii);
+ --ii;
+ }
+
+ }
+ }
+ }
+
+ // Any actions remaining have not been handled by the transition and should
+ // be applied immediately. We skip applying bindings, as they are all
+ // applied at the end in applyBindings() to avoid any nastiness mid
+ // transition
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event && !action.event->changesBindings()) {
+ if (action.event->isReversable() && action.reverseEvent)
+ action.event->reverse();
+ else
+ action.event->execute();
+ } else if (!action.event && !action.toBinding) {
+ action.property.write(action.toValue);
+ }
+ }
+#ifndef QT_NO_DEBUG_STREAM
+ if (stateChangeDebug()) {
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event)
+ qWarning() << " No transition for event:" << action.event->typeName();
+ else
+ qWarning() << " No transition for:" << action.property.object()
+ << action.property.name() << "From:" << action.fromValue
+ << "To:" << action.toValue;
+ }
+ }
+#endif
+ if (!transition)
+ d->applyBindings();
+}
+
+void QDeclarativeTransitionManager::cancel()
+{
+ if (d->transition) {
+ // ### this could potentially trigger a complete in rare circumstances
+ d->transition->stop();
+ d->transition = 0;
+ }
+
+ for(int i = 0; i < d->bindingsList.count(); ++i) {
+ QDeclarativeAction action = d->bindingsList[i];
+ if (!action.toBinding.isNull() && action.deletableToBinding) {
+ QDeclarativePropertyPrivate::setBinding(action.property, 0);
+ action.toBinding.data()->destroy();
+ action.toBinding.clear();
+ action.deletableToBinding = false;
+ } else if (action.event) {
+ //### what do we do here?
+ }
+
+ }
+ d->bindingsList.clear();
+ d->completeList.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativetransitionmanager_p_p.h b/src/declarative/util/qdeclarativetransitionmanager_p_p.h
new file mode 100644
index 0000000000..2dff3988bc
--- /dev/null
+++ b/src/declarative/util/qdeclarativetransitionmanager_p_p.h
@@ -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 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 QDECLARATIVETRANSITIONMANAGER_P_H
+#define QDECLARATIVETRANSITIONMANAGER_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/qdeclarativestateoperations_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStatePrivate;
+class QDeclarativeTransitionManagerPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeTransitionManager
+{
+public:
+ QDeclarativeTransitionManager();
+ ~QDeclarativeTransitionManager();
+
+ void transition(const QList<QDeclarativeAction> &, QDeclarativeTransition *transition);
+
+ void cancel();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeTransitionManager)
+ QDeclarativeTransitionManagerPrivate *d;
+
+ void complete();
+ void setState(QDeclarativeState *);
+
+ friend class QDeclarativeState;
+ friend class QDeclarativeTransitionPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETRANSITIONMANAGER_P_H
diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp
new file mode 100644
index 0000000000..f32f390530
--- /dev/null
+++ b/src/declarative/util/qdeclarativeutilmodule.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** 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 "private/qdeclarativeutilmodule_p.h"
+#include "private/qdeclarativeanimation_p.h"
+#include "private/qdeclarativeanimation_p_p.h"
+#include "private/qdeclarativebehavior_p.h"
+#include "private/qdeclarativebind_p.h"
+#include "private/qdeclarativeconnections_p.h"
+#include "private/qdeclarativesmoothedanimation_p.h"
+#include "private/qdeclarativefontloader_p.h"
+#include "private/qdeclarativelistaccessor_p.h"
+#include "private/qdeclarativelistmodel_p.h"
+#include "private/qdeclarativenullablevalue_p_p.h"
+#include "private/qdeclarativeopenmetaobject_p.h"
+#include "private/qdeclarativepackage_p.h"
+#include "private/qdeclarativepixmapcache_p.h"
+#include "private/qdeclarativepropertychanges_p.h"
+#include "qdeclarativepropertymap.h"
+#include "private/qdeclarativespringanimation_p.h"
+#include "private/qdeclarativestategroup_p.h"
+#include "private/qdeclarativestateoperations_p.h"
+#include "private/qdeclarativestate_p.h"
+#include "private/qdeclarativestate_p_p.h"
+#include "private/qdeclarativestyledtext_p.h"
+#include "private/qdeclarativesystempalette_p.h"
+#include "private/qdeclarativetimeline_p_p.h"
+#include "private/qdeclarativetimer_p.h"
+#include "private/qdeclarativetransitionmanager_p_p.h"
+#include "private/qdeclarativetransition_p.h"
+#include "private/qdeclarativeapplication_p.h"
+#include "qdeclarativeview.h"
+#include "qdeclarativeinfo.h"
+#include "private/qdeclarativetypenotavailable_p.h"
+#ifndef QT_NO_XMLPATTERNS
+#include "private/qdeclarativexmllistmodel_p.h"
+#endif
+
+void QDeclarativeUtilModule::defineModule()
+{
+ qmlRegisterUncreatableType<QDeclarativeApplication>("QtQuick",1,1,"Application", QDeclarativeApplication::tr("Application is an abstract class"));
+
+ qmlRegisterType<QDeclarativeAnchorAnimation>("QtQuick",1,0,"AnchorAnimation");
+ qmlRegisterType<QDeclarativeAnchorChanges>("QtQuick",1,0,"AnchorChanges");
+ qmlRegisterType<QDeclarativeBehavior>("QtQuick",1,0,"Behavior");
+ qmlRegisterType<QDeclarativeBind>("QtQuick",1,0,"Binding");
+ qmlRegisterType<QDeclarativeColorAnimation>("QtQuick",1,0,"ColorAnimation");
+ qmlRegisterType<QDeclarativeConnections>("QtQuick",1,0,"Connections");
+ qmlRegisterType<QDeclarativeSmoothedAnimation>("QtQuick",1,0,"SmoothedAnimation");
+ qmlRegisterType<QDeclarativeFontLoader>("QtQuick",1,0,"FontLoader");
+ qmlRegisterType<QDeclarativeListElement>("QtQuick",1,0,"ListElement");
+ qmlRegisterType<QDeclarativeNumberAnimation>("QtQuick",1,0,"NumberAnimation");
+ qmlRegisterType<QDeclarativePackage>("QtQuick",1,0,"Package");
+ qmlRegisterType<QDeclarativeParallelAnimation>("QtQuick",1,0,"ParallelAnimation");
+ qmlRegisterType<QDeclarativeParentAnimation>("QtQuick",1,0,"ParentAnimation");
+ qmlRegisterType<QDeclarativeParentChange>("QtQuick",1,0,"ParentChange");
+ qmlRegisterType<QDeclarativePauseAnimation>("QtQuick",1,0,"PauseAnimation");
+ qmlRegisterType<QDeclarativePropertyAction>("QtQuick",1,0,"PropertyAction");
+ qmlRegisterType<QDeclarativePropertyAnimation>("QtQuick",1,0,"PropertyAnimation");
+ qmlRegisterType<QDeclarativeRotationAnimation>("QtQuick",1,0,"RotationAnimation");
+ qmlRegisterType<QDeclarativeScriptAction>("QtQuick",1,0,"ScriptAction");
+ qmlRegisterType<QDeclarativeSequentialAnimation>("QtQuick",1,0,"SequentialAnimation");
+ qmlRegisterType<QDeclarativeSpringAnimation>("QtQuick",1,0,"SpringAnimation");
+ qmlRegisterType<QDeclarativeStateChangeScript>("QtQuick",1,0,"StateChangeScript");
+ qmlRegisterType<QDeclarativeStateGroup>("QtQuick",1,0,"StateGroup");
+ qmlRegisterType<QDeclarativeState>("QtQuick",1,0,"State");
+ qmlRegisterType<QDeclarativeSystemPalette>("QtQuick",1,0,"SystemPalette");
+ qmlRegisterType<QDeclarativeTimer>("QtQuick",1,0,"Timer");
+ qmlRegisterType<QDeclarativeTransition>("QtQuick",1,0,"Transition");
+ qmlRegisterType<QDeclarativeVector3dAnimation>("QtQuick",1,0,"Vector3dAnimation");
+#ifdef QT_NO_XMLPATTERNS
+ qmlRegisterTypeNotAvailable("QtQuick",1,0,"XmlListModel",
+ qApp->translate("QDeclarativeXmlListModel","Qt was built without support for xmlpatterns"));
+ qmlRegisterTypeNotAvailable("QtQuick",1,0,"XmlRole",
+ qApp->translate("QDeclarativeXmlListModel","Qt was built without support for xmlpatterns"));
+#else
+ qmlRegisterType<QDeclarativeXmlListModel>("QtQuick",1,0,"XmlListModel");
+ qmlRegisterType<QDeclarativeXmlListModelRole>("QtQuick",1,0,"XmlRole");
+#endif
+
+ qmlRegisterType<QDeclarativeAnchors>();
+ qmlRegisterType<QDeclarativeStateOperation>();
+ qmlRegisterType<QDeclarativeAnchorSet>();
+
+ qmlRegisterUncreatableType<QDeclarativeAbstractAnimation>("QtQuick",1,0,"Animation",QDeclarativeAbstractAnimation::tr("Animation is an abstract class"));
+
+ qmlRegisterCustomType<QDeclarativeListModel>("QtQuick",1,0,"ListModel", new QDeclarativeListModelParser);
+ qmlRegisterCustomType<QDeclarativePropertyChanges>("QtQuick",1,0,"PropertyChanges", new QDeclarativePropertyChangesParser);
+ qmlRegisterCustomType<QDeclarativeConnections>("QtQuick",1,0,"Connections", new QDeclarativeConnectionsParser);
+
+#ifndef QT_NO_IMPORT_QT47_QML
+ qmlRegisterType<QDeclarativeAnchorAnimation>("Qt",4,7,"AnchorAnimation");
+ qmlRegisterType<QDeclarativeAnchorChanges>("Qt",4,7,"AnchorChanges");
+ qmlRegisterType<QDeclarativeBehavior>("Qt",4,7,"Behavior");
+ qmlRegisterType<QDeclarativeBind>("Qt",4,7,"Binding");
+ qmlRegisterType<QDeclarativeColorAnimation>("Qt",4,7,"ColorAnimation");
+ qmlRegisterType<QDeclarativeConnections>("Qt",4,7,"Connections");
+ qmlRegisterType<QDeclarativeSmoothedAnimation>("Qt",4,7,"SmoothedAnimation");
+ qmlRegisterType<QDeclarativeFontLoader>("Qt",4,7,"FontLoader");
+ qmlRegisterType<QDeclarativeListElement>("Qt",4,7,"ListElement");
+ qmlRegisterType<QDeclarativeNumberAnimation>("Qt",4,7,"NumberAnimation");
+ qmlRegisterType<QDeclarativePackage>("Qt",4,7,"Package");
+ qmlRegisterType<QDeclarativeParallelAnimation>("Qt",4,7,"ParallelAnimation");
+ qmlRegisterType<QDeclarativeParentAnimation>("Qt",4,7,"ParentAnimation");
+ qmlRegisterType<QDeclarativeParentChange>("Qt",4,7,"ParentChange");
+ qmlRegisterType<QDeclarativePauseAnimation>("Qt",4,7,"PauseAnimation");
+ qmlRegisterType<QDeclarativePropertyAction>("Qt",4,7,"PropertyAction");
+ qmlRegisterType<QDeclarativePropertyAnimation>("Qt",4,7,"PropertyAnimation");
+ qmlRegisterType<QDeclarativeRotationAnimation>("Qt",4,7,"RotationAnimation");
+ qmlRegisterType<QDeclarativeScriptAction>("Qt",4,7,"ScriptAction");
+ qmlRegisterType<QDeclarativeSequentialAnimation>("Qt",4,7,"SequentialAnimation");
+ qmlRegisterType<QDeclarativeSpringAnimation>("Qt",4,7,"SpringAnimation");
+ qmlRegisterType<QDeclarativeStateChangeScript>("Qt",4,7,"StateChangeScript");
+ qmlRegisterType<QDeclarativeStateGroup>("Qt",4,7,"StateGroup");
+ qmlRegisterType<QDeclarativeState>("Qt",4,7,"State");
+ qmlRegisterType<QDeclarativeSystemPalette>("Qt",4,7,"SystemPalette");
+ qmlRegisterType<QDeclarativeTimer>("Qt",4,7,"Timer");
+ qmlRegisterType<QDeclarativeTransition>("Qt",4,7,"Transition");
+ qmlRegisterType<QDeclarativeVector3dAnimation>("Qt",4,7,"Vector3dAnimation");
+#ifdef QT_NO_XMLPATTERNS
+ qmlRegisterTypeNotAvailable("Qt",4,7,"XmlListModel",
+ qApp->translate("QDeclarativeXmlListModel","Qt was built without support for xmlpatterns"));
+ qmlRegisterTypeNotAvailable("Qt",4,7,"XmlRole",
+ qApp->translate("QDeclarativeXmlListModel","Qt was built without support for xmlpatterns"));
+#else
+ qmlRegisterType<QDeclarativeXmlListModel>("Qt",4,7,"XmlListModel");
+ qmlRegisterType<QDeclarativeXmlListModelRole>("Qt",4,7,"XmlRole");
+#endif
+
+ qmlRegisterUncreatableType<QDeclarativeAbstractAnimation>("Qt",4,7,"Animation",QDeclarativeAbstractAnimation::tr("Animation is an abstract class"));
+
+ qmlRegisterCustomType<QDeclarativeListModel>("Qt", 4,7, "ListModel", new QDeclarativeListModelParser);
+ qmlRegisterCustomType<QDeclarativePropertyChanges>("Qt", 4, 7, "PropertyChanges", new QDeclarativePropertyChangesParser);
+ qmlRegisterCustomType<QDeclarativeConnections>("Qt", 4, 7, "Connections", new QDeclarativeConnectionsParser);
+#endif
+}
diff --git a/src/declarative/util/qdeclarativeutilmodule_p.h b/src/declarative/util/qdeclarativeutilmodule_p.h
new file mode 100644
index 0000000000..dd5c730a64
--- /dev/null
+++ b/src/declarative/util/qdeclarativeutilmodule_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 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 QDECLARATIVEUTILMODULE_H
+#define QDECLARATIVEUTILMODULE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeUtilModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEUTILMODULE_H
diff --git a/src/declarative/util/qdeclarativeview.cpp b/src/declarative/util/qdeclarativeview.cpp
new file mode 100644
index 0000000000..e24f80f1d2
--- /dev/null
+++ b/src/declarative/util/qdeclarativeview.cpp
@@ -0,0 +1,734 @@
+/****************************************************************************
+**
+** Copyright (C) 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 "qdeclarativeview.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativeitem.h>
+#include <qdeclarativeengine.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeglobal_p.h>
+#include <qdeclarativeguard_p.h>
+
+#include <private/qdeclarativedebugtrace_p.h>
+
+#include <qscriptvalueiterator.h>
+#include <qdebug.h>
+#include <qtimer.h>
+#include <qevent.h>
+#include <qdir.h>
+#include <qcoreapplication.h>
+#include <qfontdatabase.h>
+#include <qicon.h>
+#include <qurl.h>
+#include <qlayout.h>
+#include <qwidget.h>
+#include <qgraphicswidget.h>
+#include <qbasictimer.h>
+#include <QtCore/qabstractanimation.h>
+#include <private/qgraphicsview_p.h>
+#include <private/qdeclarativeitem_p.h>
+#include <private/qabstractanimation_p.h>
+#include <private/qdeclarativeitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
+
+class QDeclarativeScene : public QGraphicsScene
+{
+public:
+ QDeclarativeScene(QObject *parent = 0);
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+};
+
+QDeclarativeScene::QDeclarativeScene(QObject *parent) : QGraphicsScene(parent)
+{
+}
+
+void QDeclarativeScene::keyPressEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QGraphicsScene::keyPressEvent(e);
+}
+
+void QDeclarativeScene::keyReleaseEvent(QKeyEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Key);
+
+ QGraphicsScene::keyReleaseEvent(e);
+}
+
+void QDeclarativeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QGraphicsScene::mouseMoveEvent(e);
+}
+
+void QDeclarativeScene::mousePressEvent(QGraphicsSceneMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QGraphicsScene::mousePressEvent(e);
+}
+
+void QDeclarativeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e)
+{
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::Mouse);
+
+ QGraphicsScene::mouseReleaseEvent(e);
+}
+
+class QDeclarativeViewPrivate : public QGraphicsViewPrivate, public QDeclarativeItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QDeclarativeView)
+public:
+ QDeclarativeViewPrivate()
+ : root(0), declarativeItemRoot(0), graphicsWidgetRoot(0), component(0),
+ resizeMode(QDeclarativeView::SizeViewToRootObject), initialSize(0,0) {}
+ ~QDeclarativeViewPrivate() { delete root; delete engine; }
+ void execute();
+ void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void initResize();
+ void updateSize();
+ inline QSize rootObjectSize() const;
+
+ QDeclarativeGuard<QGraphicsObject> root;
+ QDeclarativeGuard<QDeclarativeItem> declarativeItemRoot;
+ QDeclarativeGuard<QGraphicsWidget> graphicsWidgetRoot;
+
+ QUrl source;
+
+ QDeclarativeEngine* engine;
+ QDeclarativeComponent *component;
+ QBasicTimer resizetimer;
+
+ QDeclarativeView::ResizeMode resizeMode;
+ QSize initialSize;
+ QElapsedTimer frameTimer;
+
+ void init();
+};
+
+void QDeclarativeViewPrivate::execute()
+{
+ Q_Q(QDeclarativeView);
+ 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 QDeclarativeViewPrivate::itemGeometryChanged(QDeclarativeItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_Q(QDeclarativeView);
+ if (resizeItem == root && resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ // wait for both width and height to be changed
+ resizetimer.start(0,q);
+ }
+ QDeclarativeItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
+}
+
+/*!
+ \class QDeclarativeView
+ \since 4.7
+ \brief The QDeclarativeView class provides a widget for displaying a Qt Declarative user interface.
+
+ QDeclarativeItem objects can be placed on a standard QGraphicsScene and
+ displayed with QGraphicsView. QDeclarativeView is a QGraphicsView subclass
+ provided as a convenience for displaying QML files, and connecting between
+ QML and C++ Qt objects.
+
+ QDeclarativeView provides:
+
+ \list
+ \o Management of QDeclarativeComponent loading and object creation
+ \o Initialization of QGraphicsView for optimal performance with QML using these settings:
+ \list
+ \o QGraphicsView::setOptimizationFlags(QGraphicsView::DontSavePainterState)
+ \o QGraphicsView::setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate)
+ \o QGraphicsScene::setItemIndexMethod(QGraphicsScene::NoIndex)
+ \endlist
+ \o Initialization of QGraphicsView for QML key handling using these settings:
+ \list
+ \o QGraphicsView::viewport()->setFocusPolicy(Qt::NoFocus)
+ \o QGraphicsView::setFocusPolicy(Qt::StrongFocus)
+ \o QGraphicsScene::setStickyFocus(true)
+ \endlist
+ \endlist
+
+ Typical usage:
+
+ \code
+ QDeclarativeView *view = new QDeclarativeView;
+ view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
+ view->show();
+ \endcode
+
+ Since QDeclarativeView is a QWidget-based class, it can be used to
+ display QML interfaces within QWidget-based GUI applications that do not
+ use the Graphics View framework.
+
+ To receive errors related to loading and executing QML with QDeclarativeView,
+ you can connect to the statusChanged() signal and monitor for QDeclarativeView::Error.
+ The errors are available via QDeclarativeView::errors().
+
+ If you're using your own QGraphicsScene-based scene with QDeclarativeView, remember to
+ enable scene's sticky focus mode and to set itemIndexMethod to QGraphicsScene::NoIndex.
+
+ \sa {Integrating QML Code with Existing Qt UI Code}, {Using QML Bindings in C++ Applications}
+*/
+
+
+/*! \fn void QDeclarativeView::sceneResized(QSize size)
+ This signal is emitted when the view is resized to \a size.
+*/
+
+/*! \fn void QDeclarativeView::statusChanged(QDeclarativeView::Status status)
+ This signal is emitted when the component's current \a status changes.
+*/
+
+/*!
+ \fn QDeclarativeView::QDeclarativeView(QWidget *parent)
+
+ Constructs a QDeclarativeView with the given \a parent.
+*/
+QDeclarativeView::QDeclarativeView(QWidget *parent)
+ : QGraphicsView(*(new QDeclarativeViewPrivate), parent)
+{
+ Q_D(QDeclarativeView);
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ d->init();
+}
+
+/*!
+ \fn QDeclarativeView::QDeclarativeView(const QUrl &source, QWidget *parent)
+
+ Constructs a QDeclarativeView with the given QML \a source and \a parent.
+*/
+QDeclarativeView::QDeclarativeView(const QUrl &source, QWidget *parent)
+ : QGraphicsView(*(new QDeclarativeViewPrivate), parent)
+{
+ Q_D(QDeclarativeView);
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ d->init();
+ setSource(source);
+}
+
+void QDeclarativeViewPrivate::init()
+{
+ Q_Q(QDeclarativeView);
+ engine = new QDeclarativeEngine();
+ q->setScene(new QDeclarativeScene(q));
+
+ q->setOptimizationFlags(QGraphicsView::DontSavePainterState);
+ q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ q->setFrameStyle(0);
+
+ // These seem to give the best performance
+ q->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+ q->scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
+ q->viewport()->setFocusPolicy(Qt::NoFocus);
+ q->setFocusPolicy(Qt::StrongFocus);
+
+ q->scene()->setStickyFocus(true); //### needed for correct focus handling
+
+#ifdef QDECLARATIVEVIEW_NOBACKGROUND
+ q->setAttribute(Qt::WA_OpaquePaintEvent);
+ q->setAttribute(Qt::WA_NoSystemBackground);
+ q->viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
+ q->viewport()->setAttribute(Qt::WA_NoSystemBackground);
+#endif
+}
+
+/*!
+ Destroys the view.
+ */
+QDeclarativeView::~QDeclarativeView()
+{
+}
+
+/*! \property QDeclarativeView::source
+ \brief The URL of the source of the QML component.
+
+ Changing this property causes the QML component to be reloaded.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+ */
+
+/*!
+ Sets the source to the \a url, loads the QML component and instantiates it.
+
+ Ensure that the URL provided is full and correct, in particular, use
+ \l QUrl::fromLocalFile() when loading a file from the local filesystem.
+
+ Calling this methods multiple times with the same url will result
+ in the QML being reloaded.
+ */
+void QDeclarativeView::setSource(const QUrl& url)
+{
+ Q_D(QDeclarativeView);
+ d->source = url;
+ d->execute();
+}
+
+/*!
+ Returns the source URL, if set.
+
+ \sa setSource()
+ */
+QUrl QDeclarativeView::source() const
+{
+ Q_D(const QDeclarativeView);
+ return d->source;
+}
+
+/*!
+ Returns a pointer to the QDeclarativeEngine used for instantiating
+ QML Components.
+ */
+QDeclarativeEngine* QDeclarativeView::engine() const
+{
+ Q_D(const QDeclarativeView);
+ return d->engine;
+}
+
+/*!
+ This function returns the root of the context hierarchy. Each QML
+ component is instantiated in a QDeclarativeContext. QDeclarativeContext's are
+ essential for passing data to QML components. In QML, contexts are
+ arranged hierarchically and this hierarchy is managed by the
+ QDeclarativeEngine.
+ */
+QDeclarativeContext* QDeclarativeView::rootContext() const
+{
+ Q_D(const QDeclarativeView);
+ return d->engine->rootContext();
+}
+
+/*!
+ \enum QDeclarativeView::Status
+ Specifies the loading status of the QDeclarativeView.
+
+ \value Null This QDeclarativeView has no source set.
+ \value Ready This QDeclarativeView has loaded and created the QML component.
+ \value Loading This QDeclarativeView is loading network data.
+ \value Error One or more errors has occurred. Call errors() to retrieve a list
+ of errors.
+*/
+
+/*! \enum QDeclarativeView::ResizeMode
+
+ This enum specifies how to resize the view.
+
+ \value SizeViewToRootObject The view resizes with the root item in the QML.
+ \value SizeRootObjectToView The view will automatically resize the root item to the size of the view.
+*/
+
+/*!
+ \property QDeclarativeView::status
+ The component's current \l{QDeclarativeView::Status} {status}.
+*/
+
+QDeclarativeView::Status QDeclarativeView::status() const
+{
+ Q_D(const QDeclarativeView);
+ if (!d->component)
+ return QDeclarativeView::Null;
+
+ return QDeclarativeView::Status(d->component->status());
+}
+
+/*!
+ Return the list of errors that occurred during the last compile or create
+ operation. When the status is not Error, an empty list is returned.
+*/
+QList<QDeclarativeError> QDeclarativeView::errors() const
+{
+ Q_D(const QDeclarativeView);
+ if (d->component)
+ return d->component->errors();
+ return QList<QDeclarativeError>();
+}
+
+/*!
+ \property QDeclarativeView::resizeMode
+ \brief whether the view should resize the canvas contents
+
+ If this property is set to SizeViewToRootObject (the default), the view
+ resizes with the root item in the QML.
+
+ If this property is set to SizeRootObjectToView, the view will
+ automatically resize the root item.
+
+ Regardless of this property, the sizeHint of the view
+ is the initial size of the root item. Note though that
+ since QML may load dynamically, that size may change.
+*/
+
+void QDeclarativeView::setResizeMode(ResizeMode mode)
+{
+ Q_D(QDeclarativeView);
+ if (d->resizeMode == mode)
+ return;
+
+ if (d->declarativeItemRoot) {
+ if (d->resizeMode == SizeViewToRootObject) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(d->declarativeItemRoot));
+ p->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
+ }
+ } else if (d->graphicsWidgetRoot) {
+ if (d->resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ d->graphicsWidgetRoot->removeEventFilter(this);
+ }
+ }
+
+ d->resizeMode = mode;
+ if (d->root) {
+ d->initResize();
+ }
+}
+
+void QDeclarativeViewPrivate::initResize()
+{
+ Q_Q(QDeclarativeView);
+ if (declarativeItemRoot) {
+ if (resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ QDeclarativeItemPrivate *p =
+ static_cast<QDeclarativeItemPrivate *>(QGraphicsItemPrivate::get(declarativeItemRoot));
+ p->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
+ }
+ } else if (graphicsWidgetRoot) {
+ if (resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ graphicsWidgetRoot->installEventFilter(q);
+ }
+ }
+ updateSize();
+}
+
+void QDeclarativeViewPrivate::updateSize()
+{
+ Q_Q(QDeclarativeView);
+ if (!root)
+ return;
+ if (declarativeItemRoot) {
+ if (resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ QSize newSize = QSize(declarativeItemRoot->width(), declarativeItemRoot->height());
+ if (newSize.isValid() && newSize != q->size()) {
+ q->resize(newSize);
+ }
+ } else if (resizeMode == QDeclarativeView::SizeRootObjectToView) {
+ if (!qFuzzyCompare(q->width(), declarativeItemRoot->width()))
+ declarativeItemRoot->setWidth(q->width());
+ if (!qFuzzyCompare(q->height(), declarativeItemRoot->height()))
+ declarativeItemRoot->setHeight(q->height());
+ }
+ } else if (graphicsWidgetRoot) {
+ if (resizeMode == QDeclarativeView::SizeViewToRootObject) {
+ QSize newSize = QSize(graphicsWidgetRoot->size().width(), graphicsWidgetRoot->size().height());
+ if (newSize.isValid() && newSize != q->size()) {
+ q->resize(newSize);
+ }
+ } else if (resizeMode == QDeclarativeView::SizeRootObjectToView) {
+ QSizeF newSize = QSize(q->size().width(), q->size().height());
+ if (newSize.isValid() && newSize != graphicsWidgetRoot->size()) {
+ graphicsWidgetRoot->resize(newSize);
+ }
+ }
+ }
+ q->updateGeometry();
+}
+
+QSize QDeclarativeViewPrivate::rootObjectSize() const
+{
+ QSize rootObjectSize(0,0);
+ int widthCandidate = -1;
+ int heightCandidate = -1;
+ if (root) {
+ QSizeF size = root->boundingRect().size();
+ widthCandidate = size.width();
+ heightCandidate = size.height();
+ }
+ if (widthCandidate > 0) {
+ rootObjectSize.setWidth(widthCandidate);
+ }
+ if (heightCandidate > 0) {
+ rootObjectSize.setHeight(heightCandidate);
+ }
+ return rootObjectSize;
+}
+
+QDeclarativeView::ResizeMode QDeclarativeView::resizeMode() const
+{
+ Q_D(const QDeclarativeView);
+ return d->resizeMode;
+}
+
+/*!
+ \internal
+ */
+void QDeclarativeView::continueExecute()
+{
+ Q_D(QDeclarativeView);
+ 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;
+ }
+
+ setRootObject(obj);
+ emit statusChanged(status());
+}
+
+
+/*!
+ \internal
+*/
+void QDeclarativeView::setRootObject(QObject *obj)
+{
+ Q_D(QDeclarativeView);
+ if (d->root == obj || !scene())
+ return;
+ if (QDeclarativeItem *declarativeItem = qobject_cast<QDeclarativeItem *>(obj)) {
+ scene()->addItem(declarativeItem);
+ d->root = declarativeItem;
+ d->declarativeItemRoot = declarativeItem;
+ } else if (QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(obj)) {
+ scene()->addItem(graphicsObject);
+ d->root = graphicsObject;
+ if (graphicsObject->isWidget()) {
+ d->graphicsWidgetRoot = static_cast<QGraphicsWidget*>(graphicsObject);
+ } else {
+ qWarning() << "QDeclarativeView::resizeMode is not honored for components of type QGraphicsObject";
+ }
+ } else if (obj) {
+ qWarning() << "QDeclarativeView only supports loading of root objects that derive from QGraphicsObject";
+ if (QWidget* widget = qobject_cast<QWidget *>(obj)) {
+ window()->setAttribute(Qt::WA_OpaquePaintEvent, false);
+ window()->setAttribute(Qt::WA_NoSystemBackground, false);
+ if (layout() && layout()->count()) {
+ // Hide the QGraphicsView in GV mode.
+ QLayoutItem *item = layout()->itemAt(0);
+ if (item->widget())
+ item->widget()->hide();
+ }
+ widget->setParent(this);
+ if (isVisible()) {
+ widget->setVisible(true);
+ }
+ resize(widget->size());
+ }
+ }
+
+ if (d->root) {
+ d->initialSize = d->rootObjectSize();
+ if (d->initialSize != size()) {
+ if (!(parentWidget() && parentWidget()->layout())) {
+ resize(d->initialSize);
+ }
+ }
+ d->initResize();
+ }
+}
+
+/*!
+ \internal
+ If the \l {QTimerEvent} {timer event} \a e is this
+ view's resize timer, sceneResized() is emitted.
+ */
+void QDeclarativeView::timerEvent(QTimerEvent* e)
+{
+ Q_D(QDeclarativeView);
+ if (!e || e->timerId() == d->resizetimer.timerId()) {
+ d->updateSize();
+ d->resizetimer.stop();
+ }
+}
+
+/*! \internal */
+bool QDeclarativeView::eventFilter(QObject *watched, QEvent *e)
+{
+ Q_D(QDeclarativeView);
+ if (watched == d->root && d->resizeMode == SizeViewToRootObject) {
+ if (d->graphicsWidgetRoot) {
+ if (e->type() == QEvent::GraphicsSceneResize) {
+ d->updateSize();
+ }
+ }
+ }
+ return QGraphicsView::eventFilter(watched, e);
+}
+
+/*!
+ \internal
+ Preferred size follows the root object geometry.
+*/
+QSize QDeclarativeView::sizeHint() const
+{
+ Q_D(const QDeclarativeView);
+ QSize rootObjectSize = d->rootObjectSize();
+ if (rootObjectSize.isEmpty()) {
+ return size();
+ } else {
+ return rootObjectSize;
+ }
+}
+
+/*!
+ Returns the initial size of the root object
+*/
+QSize QDeclarativeView::initialSize() const
+{
+ Q_D(const QDeclarativeView);
+ return d->initialSize;
+}
+
+/*!
+ Returns the view's root \l {QGraphicsObject} {item}.
+ */
+QGraphicsObject *QDeclarativeView::rootObject() const
+{
+ Q_D(const QDeclarativeView);
+ return d->root;
+}
+
+/*!
+ \internal
+ This function handles the \l {QResizeEvent} {resize event}
+ \a e.
+ */
+void QDeclarativeView::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QDeclarativeView);
+ if (d->resizeMode == SizeRootObjectToView) {
+ d->updateSize();
+ }
+ if (d->declarativeItemRoot) {
+ setSceneRect(QRectF(0, 0, d->declarativeItemRoot->width(), d->declarativeItemRoot->height()));
+ } else if (d->root) {
+ setSceneRect(d->root->boundingRect());
+ } else {
+ setSceneRect(rect());
+ }
+ emit sceneResized(e->size());
+ QGraphicsView::resizeEvent(e);
+}
+
+/*!
+ \internal
+*/
+void QDeclarativeView::paintEvent(QPaintEvent *event)
+{
+ Q_D(QDeclarativeView);
+
+ QDeclarativeDebugTrace::addEvent(QDeclarativeDebugTrace::FramePaint);
+ QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Painting);
+
+ int time = 0;
+ if (frameRateDebug())
+ time = d->frameTimer.restart();
+
+ QGraphicsView::paintEvent(event);
+
+ QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Painting);
+
+ if (frameRateDebug())
+ qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
+
+#if QT_SHOW_DECLARATIVEVIEW_FPS
+ static QTime timer;
+ static int frames;
+
+ if (frames == 0) {
+ timer.start();
+ } else if (timer.elapsed() > 5000) {
+ qreal avgtime = timer.elapsed() / (qreal) frames;
+ qDebug("Average time per frame: %f ms (%i fps)", avgtime, int(1000 / avgtime));
+ timer.start();
+ frames = 0;
+ }
+ ++frames;
+ scene()->update();
+#endif
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeview.h b/src/declarative/util/qdeclarativeview.h
new file mode 100644
index 0000000000..530133ea96
--- /dev/null
+++ b/src/declarative/util/qdeclarativeview.h
@@ -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 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 QDECLARATIVEVIEW_H
+#define QDECLARATIVEVIEW_H
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qurl.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGraphicsObject;
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeError;
+
+class QDeclarativeViewPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeView : public QGraphicsView
+{
+ 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 QDeclarativeView(QWidget *parent = 0);
+ QDeclarativeView(const QUrl &source, QWidget *parent = 0);
+ virtual ~QDeclarativeView();
+
+ QUrl source() const;
+ void setSource(const QUrl&);
+
+ QDeclarativeEngine* engine() const;
+ QDeclarativeContext* rootContext() const;
+
+ QGraphicsObject *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 sceneResized(QSize size); // ???
+ void statusChanged(QDeclarativeView::Status);
+
+private Q_SLOTS:
+ void continueExecute();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void timerEvent(QTimerEvent*);
+ virtual void setRootObject(QObject *obj);
+ virtual bool eventFilter(QObject *watched, QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QDeclarativeView)
+ Q_DECLARE_PRIVATE(QDeclarativeView)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEVIEW_H
diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp
new file mode 100644
index 0000000000..0a39ca8dd0
--- /dev/null
+++ b/src/declarative/util/qdeclarativexmllistmodel.cpp
@@ -0,0 +1,1050 @@
+/****************************************************************************
+**
+** Copyright (C) 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/qdeclarativexmllistmodel_p.h"
+
+#include <qdeclarativecontext.h>
+#include <qdeclarativeengine_p.h>
+
+#include <QDebug>
+#include <QStringList>
+#include <QMap>
+#include <QApplication>
+#include <QThread>
+#include <QXmlQuery>
+#include <QXmlResultItems>
+#include <QXmlNodeModelIndex>
+#include <QBuffer>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QTimer>
+#include <QMutex>
+
+#include <private/qobject_p.h>
+
+Q_DECLARE_METATYPE(QDeclarativeXmlQueryResult)
+
+QT_BEGIN_NAMESPACE
+
+
+typedef QPair<int, int> QDeclarativeXmlListRange;
+
+#define XMLLISTMODEL_CLEAR_ID 0
+
+/*!
+ \qmlclass XmlRole QDeclarativeXmlListModelRole
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The XmlRole element allows you to specify a role for an XmlListModel.
+
+ \sa {QtDeclarative}
+*/
+
+/*!
+ \qmlproperty string XmlRole::name
+
+ The name for the role. This name is used to access the model data for this role.
+
+ For example, the following model has a role named "title", which can be accessed
+ from the view's delegate:
+
+ \qml
+ XmlListModel {
+ id: xmlModel
+ // ...
+ XmlRole {
+ name: "title"
+ query: "title/string()"
+ }
+ }
+ \endqml
+
+ \qml
+ ListView {
+ model: xmlModel
+ delegate: Text { text: title }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty string XmlRole::query
+ The relative XPath expression query for this role. The query must be relative; it cannot start
+ with a '/'.
+
+ For example, if there is an XML document like this:
+
+ \quotefile doc/src/snippets/declarative/xmlrole.xml
+
+ Here are some valid XPath expressions for XmlRole queries on this document:
+
+ \snippet doc/src/snippets/declarative/xmlrole.qml 0
+ \dots 4
+ \snippet doc/src/snippets/declarative/xmlrole.qml 1
+
+ See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information.
+*/
+
+/*!
+ \qmlproperty bool XmlRole::isKey
+ Defines whether this is a key role.
+
+ Key roles are used to to determine whether a set of values should
+ be updated or added to the XML list model when XmlListModel::reload()
+ is called.
+
+ \sa XmlListModel
+*/
+
+struct XmlQueryJob
+{
+ int queryId;
+ QByteArray data;
+ QString query;
+ QString namespaces;
+ QStringList roleQueries;
+ QList<void*> roleQueryErrorId; // the ptr to send back if there is an error
+ QStringList keyRoleQueries;
+ QStringList keyRoleResultsCache;
+ QString prefix;
+};
+
+class QDeclarativeXmlQuery : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeXmlQuery(QObject *parent=0)
+ : QObject(parent), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1) {
+ qRegisterMetaType<QDeclarativeXmlQueryResult>("QDeclarativeXmlQueryResult");
+ moveToThread(&m_thread);
+ m_thread.start(QThread::IdlePriority);
+ }
+
+ ~QDeclarativeXmlQuery() {
+ if(m_thread.isRunning()) {
+ m_thread.quit();
+ m_thread.wait();
+ }
+ }
+
+ void abort(int id) {
+ QMutexLocker ml(&m_mutex);
+ if (id != -1) {
+ m_jobs.remove(id);
+ }
+ }
+
+ int doQuery(QString query, QString namespaces, QByteArray data, QList<QDeclarativeXmlListModelRole *>* roleObjects, QStringList keyRoleResultsCache) {
+ {
+ QMutexLocker m1(&m_mutex);
+ m_queryIds.ref();
+ if (m_queryIds <= 0)
+ m_queryIds = 1;
+ }
+
+ XmlQueryJob job;
+ job.queryId = m_queryIds;
+ job.data = data;
+ job.query = QLatin1String("doc($src)") + query;
+ job.namespaces = namespaces;
+ job.keyRoleResultsCache = keyRoleResultsCache;
+
+ for (int i=0; i<roleObjects->count(); i++) {
+ if (!roleObjects->at(i)->isValid()) {
+ job.roleQueries << QString();
+ continue;
+ }
+ job.roleQueries << roleObjects->at(i)->query();
+ job.roleQueryErrorId << static_cast<void*>(roleObjects->at(i));
+ if (roleObjects->at(i)->isKey())
+ job.keyRoleQueries << job.roleQueries.last();
+ }
+
+ {
+ QMutexLocker ml(&m_mutex);
+ m_jobs.insert(m_queryIds, job);
+ }
+
+ QMetaObject::invokeMethod(this, "processQuery", Qt::QueuedConnection, Q_ARG(int, job.queryId));
+ return job.queryId;
+ }
+
+private slots:
+ void processQuery(int queryId) {
+ XmlQueryJob job;
+
+ {
+ QMutexLocker ml(&m_mutex);
+ if (!m_jobs.contains(queryId))
+ return;
+ job = m_jobs.value(queryId);
+ }
+
+ QDeclarativeXmlQueryResult result;
+ result.queryId = job.queryId;
+ doQueryJob(&job, &result);
+ doSubQueryJob(&job, &result);
+
+ {
+ QMutexLocker ml(&m_mutex);
+ if (m_jobs.contains(queryId)) {
+ emit queryCompleted(result);
+ m_jobs.remove(queryId);
+ }
+ }
+ }
+
+Q_SIGNALS:
+ void queryCompleted(const QDeclarativeXmlQueryResult &);
+ void error(void*, const QString&);
+
+protected:
+
+
+private:
+ void doQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult);
+ void doSubQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult);
+ void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const;
+ void addIndexToRangeList(QList<QDeclarativeXmlListRange> *ranges, int index) const;
+
+private:
+ QMutex m_mutex;
+ QThread m_thread;
+ QMap<int, XmlQueryJob> m_jobs;
+ QAtomicInt m_queryIds;
+};
+
+Q_GLOBAL_STATIC(QDeclarativeXmlQuery, globalXmlQuery)
+
+void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult)
+{
+ Q_ASSERT(currentJob->queryId != -1);
+
+ QString r;
+ QXmlQuery query;
+ QBuffer buffer(&currentJob->data);
+ buffer.open(QIODevice::ReadOnly);
+ query.bindVariable(QLatin1String("src"), &buffer);
+ query.setQuery(currentJob->namespaces + currentJob->query);
+ query.evaluateTo(&r);
+
+ //always need a single root element
+ QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>";
+ QBuffer b(&xml);
+ b.open(QIODevice::ReadOnly);
+
+ QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + currentJob->namespaces;
+ QString prefix = QLatin1String("doc($inputDocument)/dummy:items") +
+ currentJob->query.mid(currentJob->query.lastIndexOf(QLatin1Char('/')));
+
+ //figure out how many items we are dealing with
+ int count = -1;
+ {
+ QXmlResultItems result;
+ QXmlQuery countquery;
+ countquery.bindVariable(QLatin1String("inputDocument"), &b);
+ countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1Char(')'));
+ countquery.evaluateTo(&result);
+ QXmlItem item(result.next());
+ if (item.isAtomicValue())
+ count = item.toAtomicValue().toInt();
+ }
+
+ currentJob->data = xml;
+ currentJob->prefix = namespaces + prefix + QLatin1Char('/');
+ currentResult->size = (count > 0 ? count : 0);
+}
+
+void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const
+{
+ const QStringList &keysQueries = currentJob.keyRoleQueries;
+ QString keysQuery;
+ if (keysQueries.count() == 1)
+ keysQuery = currentJob.prefix + keysQueries[0];
+ else if (keysQueries.count() > 1)
+ keysQuery = currentJob.prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")");
+
+ if (!keysQuery.isEmpty()) {
+ query->setQuery(keysQuery);
+ QXmlResultItems resultItems;
+ query->evaluateTo(&resultItems);
+ QXmlItem item(resultItems.next());
+ while (!item.isNull()) {
+ values->append(item.toAtomicValue().toString());
+ item = resultItems.next();
+ }
+ }
+}
+
+void QDeclarativeXmlQuery::addIndexToRangeList(QList<QDeclarativeXmlListRange> *ranges, int index) const {
+ if (ranges->isEmpty())
+ ranges->append(qMakePair(index, 1));
+ else if (ranges->last().first + ranges->last().second == index)
+ ranges->last().second += 1;
+ else
+ ranges->append(qMakePair(index, 1));
+}
+
+void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult)
+{
+ Q_ASSERT(currentJob->queryId != -1);
+
+ QBuffer b(&currentJob->data);
+ b.open(QIODevice::ReadOnly);
+
+ QXmlQuery subquery;
+ subquery.bindVariable(QLatin1String("inputDocument"), &b);
+
+ QStringList keyRoleResults;
+ getValuesOfKeyRoles(*currentJob, &keyRoleResults, &subquery);
+
+ // See if any values of key roles have been inserted or removed.
+
+ if (currentJob->keyRoleResultsCache.isEmpty()) {
+ currentResult->inserted << qMakePair(0, currentResult->size);
+ } else {
+ if (keyRoleResults != currentJob->keyRoleResultsCache) {
+ QStringList temp;
+ for (int i=0; i<currentJob->keyRoleResultsCache.count(); i++) {
+ if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i]))
+ addIndexToRangeList(&currentResult->removed, i);
+ else
+ temp << currentJob->keyRoleResultsCache[i];
+ }
+
+ for (int i=0; i<keyRoleResults.count(); i++) {
+ if (temp.count() == i || keyRoleResults[i] != temp[i]) {
+ temp.insert(i, keyRoleResults[i]);
+ addIndexToRangeList(&currentResult->inserted, i);
+ }
+ }
+ }
+ }
+ currentResult->keyRoleResultsCache = keyRoleResults;
+
+ // Get the new values for each role.
+ //### we might be able to condense even further (query for everything in one go)
+ const QStringList &queries = currentJob->roleQueries;
+ for (int i = 0; i < queries.size(); ++i) {
+ QList<QVariant> resultList;
+ if (!queries[i].isEmpty()) {
+ subquery.setQuery(currentJob->prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")"));
+ if (subquery.isValid()) {
+ QXmlResultItems resultItems;
+ subquery.evaluateTo(&resultItems);
+ QXmlItem item(resultItems.next());
+ while (!item.isNull()) {
+ resultList << item.toAtomicValue(); //### we used to trim strings
+ item = resultItems.next();
+ }
+ } else {
+ emit error(currentJob->roleQueryErrorId.at(i), queries[i]);
+ }
+ }
+ //### should warn here if things have gone wrong.
+ while (resultList.count() < currentResult->size)
+ resultList << QVariant();
+ currentResult->data << resultList;
+ b.seek(0);
+ }
+
+ //this method is much slower, but works better for incremental loading
+ /*for (int j = 0; j < m_size; ++j) {
+ QList<QVariant> resultList;
+ for (int i = 0; i < m_roleObjects->size(); ++i) {
+ QDeclarativeXmlListModelRole *role = m_roleObjects->at(i);
+ subquery.setQuery(m_prefix.arg(j+1) + role->query());
+ if (role->isStringList()) {
+ QStringList data;
+ subquery.evaluateTo(&data);
+ resultList << QVariant(data);
+ //qDebug() << data;
+ } else {
+ QString s;
+ subquery.evaluateTo(&s);
+ if (role->isCData()) {
+ //un-escape
+ s.replace(QLatin1String("&lt;"), QLatin1String("<"));
+ s.replace(QLatin1String("&gt;"), QLatin1String(">"));
+ s.replace(QLatin1String("&amp;"), QLatin1String("&"));
+ }
+ resultList << s.trimmed();
+ //qDebug() << s;
+ }
+ b.seek(0);
+ }
+ m_modelData << resultList;
+ }*/
+}
+
+class QDeclarativeXmlListModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeXmlListModel)
+public:
+ QDeclarativeXmlListModelPrivate()
+ : isComponentComplete(true), size(-1), highestRole(Qt::UserRole)
+ , reply(0), status(QDeclarativeXmlListModel::Null), progress(0.0)
+ , queryId(-1), roleObjects(), redirectCount(0) {}
+
+
+ void notifyQueryStarted(bool remoteSource) {
+ Q_Q(QDeclarativeXmlListModel);
+ progress = remoteSource ? 0.0 : 1.0;
+ status = QDeclarativeXmlListModel::Loading;
+ errorString.clear();
+ emit q->progressChanged(progress);
+ emit q->statusChanged(status);
+ }
+
+ bool isComponentComplete;
+ QUrl src;
+ QString xml;
+ QString query;
+ QString namespaces;
+ int size;
+ QList<int> roles;
+ QStringList roleNames;
+ int highestRole;
+ QNetworkReply *reply;
+ QDeclarativeXmlListModel::Status status;
+ QString errorString;
+ qreal progress;
+ int queryId;
+ QStringList keyRoleResultsCache;
+ QList<QDeclarativeXmlListModelRole *> roleObjects;
+ static void append_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list, QDeclarativeXmlListModelRole *role);
+ static void clear_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list);
+ QList<QList<QVariant> > data;
+ int redirectCount;
+};
+
+
+void QDeclarativeXmlListModelPrivate::append_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list, QDeclarativeXmlListModelRole *role)
+{
+ QDeclarativeXmlListModel *_this = qobject_cast<QDeclarativeXmlListModel *>(list->object);
+ if (_this && role) {
+ int i = _this->d_func()->roleObjects.count();
+ _this->d_func()->roleObjects.append(role);
+ if (_this->d_func()->roleNames.contains(role->name())) {
+ qmlInfo(role) << QObject::tr("\"%1\" duplicates a previous role name and will be disabled.").arg(role->name());
+ return;
+ }
+ _this->d_func()->roles.insert(i, _this->d_func()->highestRole);
+ _this->d_func()->roleNames.insert(i, role->name());
+ ++_this->d_func()->highestRole;
+ }
+}
+
+//### clear needs to invalidate any cached data (in data table) as well
+// (and the model should emit the appropriate signals)
+void QDeclarativeXmlListModelPrivate::clear_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list)
+{
+ QDeclarativeXmlListModel *_this = static_cast<QDeclarativeXmlListModel *>(list->object);
+ _this->d_func()->roles.clear();
+ _this->d_func()->roleNames.clear();
+ _this->d_func()->roleObjects.clear();
+}
+
+/*!
+ \qmlclass XmlListModel QDeclarativeXmlListModel
+ \ingroup qml-working-with-data
+ \since 4.7
+ \brief The XmlListModel element is used to specify a read-only model using XPath expressions.
+
+ XmlListModel is used to create a read-only model from XML data. It can be used as a data source
+ for view elements (such as ListView, PathView, GridView) and other elements that interact with model
+ data (such as \l Repeater).
+
+ For example, if there is a XML document at http://www.mysite.com/feed.xml like this:
+
+ \code
+ <?xml version="1.0" encoding="utf-8"?>
+ <rss version="2.0">
+ ...
+ <channel>
+ <item>
+ <title>A blog post</title>
+ <pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
+ </item>
+ <item>
+ <title>Another blog post</title>
+ <pubDate>Sat, 07 Sep 2010 15:35:01 GMT</pubDate>
+ </item>
+ </channel>
+ </rss>
+ \endcode
+
+ A XmlListModel could create a model from this data, like this:
+
+ \qml
+ import QtQuick 1.0
+
+ XmlListModel {
+ id: xmlModel
+ source: "http://www.mysite.com/feed.xml"
+ query: "/rss/channel/item"
+
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "pubDate"; query: "pubDate/string()" }
+ }
+ \endqml
+
+ The \l {XmlListModel::query}{query} value of "/rss/channel/item" specifies that the XmlListModel should generate
+ a model item for each \c <item> in the XML document.
+
+ The XmlRole objects define the
+ model item attributes. Here, each model item will have \c title and \c pubDate
+ attributes that match the \c title and \c pubDate values of its corresponding \c <item>.
+ (See \l XmlRole::query for more examples of valid XPath expressions for XmlRole.)
+
+ The model could be used in a ListView, like this:
+
+ \qml
+ ListView {
+ width: 180; height: 300
+ model: xmlModel
+ delegate: Text { text: title + ": " + pubDate }
+ }
+ \endqml
+
+ \image qml-xmllistmodel-example.png
+
+ The XmlListModel data is loaded asynchronously, and \l status
+ is set to \c XmlListModel.Ready when loading is complete.
+ Note this means when XmlListModel is used for a view, the view is not
+ populated until the model is loaded.
+
+
+ \section2 Using key XML roles
+
+ You can define certain roles as "keys" so that when reload() is called,
+ the model will only add and refresh data that contains new values for
+ these keys.
+
+ For example, if above role for "pubDate" was defined like this instead:
+
+ \qml
+ XmlRole { name: "pubDate"; query: "pubDate/string()"; isKey: true }
+ \endqml
+
+ Then when reload() is called, the model will only add and reload
+ items with a "pubDate" value that is not already
+ present in the model.
+
+ This is useful when displaying the contents of XML documents that
+ are incrementally updated (such as RSS feeds) to avoid repainting the
+ entire contents of a model in a view.
+
+ If multiple key roles are specified, the model only adds and reload items
+ with a combined value of all key roles that is not already present in
+ the model.
+
+ \sa {RSS News}
+*/
+
+QDeclarativeXmlListModel::QDeclarativeXmlListModel(QObject *parent)
+ : QListModelInterface(*(new QDeclarativeXmlListModelPrivate), parent)
+{
+ connect(globalXmlQuery(), SIGNAL(queryCompleted(QDeclarativeXmlQueryResult)),
+ this, SLOT(queryCompleted(QDeclarativeXmlQueryResult)));
+ connect(globalXmlQuery(), SIGNAL(error(void*,QString)),
+ this, SLOT(queryError(void*,QString)));
+}
+
+QDeclarativeXmlListModel::~QDeclarativeXmlListModel()
+{
+}
+
+/*!
+ \qmlproperty list<XmlRole> XmlListModel::roles
+
+ The roles to make available for this model.
+*/
+QDeclarativeListProperty<QDeclarativeXmlListModelRole> QDeclarativeXmlListModel::roleObjects()
+{
+ Q_D(QDeclarativeXmlListModel);
+ QDeclarativeListProperty<QDeclarativeXmlListModelRole> list(this, d->roleObjects);
+ list.append = &QDeclarativeXmlListModelPrivate::append_role;
+ list.clear = &QDeclarativeXmlListModelPrivate::clear_role;
+ return list;
+}
+
+QHash<int,QVariant> QDeclarativeXmlListModel::data(int index, const QList<int> &roles) const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ QHash<int, QVariant> rv;
+ for (int i = 0; i < roles.size(); ++i) {
+ int role = roles.at(i);
+ int roleIndex = d->roles.indexOf(role);
+ rv.insert(role, roleIndex == -1 ? QVariant() : d->data.value(roleIndex).value(index));
+ }
+ return rv;
+}
+
+QVariant QDeclarativeXmlListModel::data(int index, int role) const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ int roleIndex = d->roles.indexOf(role);
+ return (roleIndex == -1) ? QVariant() : d->data.value(roleIndex).value(index);
+}
+
+/*!
+ \qmlproperty int XmlListModel::count
+ The number of data entries in the model.
+*/
+int QDeclarativeXmlListModel::count() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->size;
+}
+
+QList<int> QDeclarativeXmlListModel::roles() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->roles;
+}
+
+QString QDeclarativeXmlListModel::toString(int role) const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ int index = d->roles.indexOf(role);
+ if (index == -1)
+ return QString();
+ return d->roleNames.at(index);
+}
+
+/*!
+ \qmlproperty url XmlListModel::source
+ The location of the XML data source.
+
+ If both \c source and \l xml are set, \l xml is used.
+*/
+QUrl QDeclarativeXmlListModel::source() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->src;
+}
+
+void QDeclarativeXmlListModel::setSource(const QUrl &src)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (d->src != src) {
+ d->src = src;
+ if (d->xml.isEmpty()) // src is only used if d->xml is not set
+ reload();
+ emit sourceChanged();
+ }
+}
+
+/*!
+ \qmlproperty string XmlListModel::xml
+ This property holds the XML data for this model, if set.
+
+ The text is assumed to be UTF-8 encoded.
+
+ If both \l source and \c xml are set, \c xml is used.
+*/
+QString QDeclarativeXmlListModel::xml() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->xml;
+}
+
+void QDeclarativeXmlListModel::setXml(const QString &xml)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (d->xml != xml) {
+ d->xml = xml;
+ reload();
+ emit xmlChanged();
+ }
+}
+
+/*!
+ \qmlproperty string XmlListModel::query
+ An absolute XPath query representing the base query for creating model items
+ from this model's XmlRole objects. The query should start with '/' or '//'.
+*/
+QString QDeclarativeXmlListModel::query() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->query;
+}
+
+void QDeclarativeXmlListModel::setQuery(const QString &query)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (!query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << QCoreApplication::translate("QDeclarativeXmlRoleList", "An XmlListModel query must start with '/' or \"//\"");
+ return;
+ }
+
+ if (d->query != query) {
+ d->query = query;
+ reload();
+ emit queryChanged();
+ }
+}
+
+/*!
+ \qmlproperty string XmlListModel::namespaceDeclarations
+ The namespace declarations to be used in the XPath queries.
+
+ The namespaces should be declared as in XQuery. For example, if a requested document
+ at http://mysite.com/feed.xml uses the namespace "http://www.w3.org/2005/Atom",
+ this can be declared as the default namespace:
+
+ \qml
+ XmlListModel {
+ source: "http://mysite.com/feed.xml"
+ query: "/feed/entry"
+ namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';"
+
+ XmlRole { name: "title"; query: "title/string()" }
+ }
+ \endqml
+*/
+QString QDeclarativeXmlListModel::namespaceDeclarations() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->namespaces;
+}
+
+void QDeclarativeXmlListModel::setNamespaceDeclarations(const QString &declarations)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (d->namespaces != declarations) {
+ d->namespaces = declarations;
+ reload();
+ emit namespaceDeclarationsChanged();
+ }
+}
+
+/*!
+ \qmlmethod object XmlListModel::get(int index)
+
+ Returns the item at \a index in the model.
+
+ For example, for a model like this:
+
+ \qml
+ XmlListModel {
+ id: model
+ source: "http://mysite.com/feed.xml"
+ query: "/feed/entry"
+ XmlRole { name: "title"; query: "title/string()" }
+ }
+ \endqml
+
+ This will access the \c title value for the first item in the model:
+
+ \js
+ var title = model.get(0).title;
+ \endjs
+*/
+QScriptValue QDeclarativeXmlListModel::get(int index) const
+{
+ Q_D(const QDeclarativeXmlListModel);
+
+ QScriptEngine *sengine = QDeclarativeEnginePrivate::getScriptEngine(qmlContext(this)->engine());
+ if (index < 0 || index >= count())
+ return sengine->undefinedValue();
+
+ QScriptValue sv = sengine->newObject();
+ for (int i=0; i<d->roleObjects.count(); i++)
+ sv.setProperty(d->roleObjects[i]->name(), sengine->toScriptValue(d->data.value(i).value(index)));
+ return sv;
+}
+
+/*!
+ \qmlproperty enumeration XmlListModel::status
+ Specifies the model loading status, which can be one of the following:
+
+ \list
+ \o XmlListModel.Null - No XML data has been set for this model.
+ \o XmlListModel.Ready - The XML data has been loaded into the model.
+ \o XmlListModel.Loading - The model is in the process of reading and loading XML data.
+ \o XmlListModel.Error - An error occurred while the model was loading. See errorString() for details
+ about the error.
+ \endlist
+
+ \sa progress
+
+*/
+QDeclarativeXmlListModel::Status QDeclarativeXmlListModel::status() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->status;
+}
+
+/*!
+ \qmlproperty real XmlListModel::progress
+
+ This indicates the current progress of the downloading of the XML data
+ source. This value ranges from 0.0 (no data downloaded) to
+ 1.0 (all data downloaded). If the XML data is not from a remote source,
+ the progress becomes 1.0 as soon as the data is read.
+
+ Note that when the progress is 1.0, the XML data has been downloaded, but
+ it is yet to be loaded into the model at this point. Use the status
+ property to find out when the XML data has been read and loaded into
+ the model.
+
+ \sa status, source
+*/
+qreal QDeclarativeXmlListModel::progress() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->progress;
+}
+
+/*!
+ \qmlmethod void XmlListModel::errorString()
+
+ Returns a string description of the last error that occurred
+ if \l status is XmlListModel::Error.
+*/
+QString QDeclarativeXmlListModel::errorString() const
+{
+ Q_D(const QDeclarativeXmlListModel);
+ return d->errorString;
+}
+
+void QDeclarativeXmlListModel::classBegin()
+{
+ Q_D(QDeclarativeXmlListModel);
+ d->isComponentComplete = false;
+}
+
+void QDeclarativeXmlListModel::componentComplete()
+{
+ Q_D(QDeclarativeXmlListModel);
+ d->isComponentComplete = true;
+ reload();
+}
+
+/*!
+ \qmlmethod XmlListModel::reload()
+
+ Reloads the model.
+
+ If no key roles have been specified, all existing model
+ data is removed, and the model is rebuilt from scratch.
+
+ Otherwise, items are only added if the model does not already
+ contain items with matching key role values.
+
+ \sa {Using key XML roles}, XmlRole::isKey
+*/
+void QDeclarativeXmlListModel::reload()
+{
+ Q_D(QDeclarativeXmlListModel);
+
+ if (!d->isComponentComplete)
+ return;
+
+ globalXmlQuery()->abort(d->queryId);
+ d->queryId = -1;
+
+ if (d->size < 0)
+ d->size = 0;
+
+ if (d->reply) {
+ d->reply->abort();
+ if (d->reply) {
+ // abort will generally have already done this (and more)
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+ }
+
+ if (!d->xml.isEmpty()) {
+ d->queryId = globalXmlQuery()->doQuery(d->query, d->namespaces, d->xml.toUtf8(), &d->roleObjects, d->keyRoleResultsCache);
+ d->notifyQueryStarted(false);
+
+ } else if (d->src.isEmpty()) {
+ d->queryId = XMLLISTMODEL_CLEAR_ID;
+ d->notifyQueryStarted(false);
+ QTimer::singleShot(0, this, SLOT(dataCleared()));
+
+ } else {
+ d->notifyQueryStarted(true);
+ QNetworkRequest req(d->src);
+ req.setRawHeader("Accept", "application/xml,*/*");
+ d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished()));
+ QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ }
+}
+
+#define XMLLISTMODEL_MAX_REDIRECT 16
+
+void QDeclarativeXmlListModel::requestFinished()
+{
+ Q_D(QDeclarativeXmlListModel);
+
+ d->redirectCount++;
+ if (d->redirectCount < XMLLISTMODEL_MAX_REDIRECT) {
+ 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;
+
+ if (d->reply->error() != QNetworkReply::NoError) {
+ d->errorString = d->reply->errorString();
+ disconnect(d->reply, 0, this, 0);
+ d->reply->deleteLater();
+ d->reply = 0;
+
+ int count = this->count();
+ d->data.clear();
+ d->size = 0;
+ if (count > 0) {
+ emit itemsRemoved(0, count);
+ emit countChanged();
+ }
+
+ d->status = Error;
+ d->queryId = -1;
+ emit statusChanged(d->status);
+ } else {
+ QByteArray data = d->reply->readAll();
+ if (data.isEmpty()) {
+ d->queryId = XMLLISTMODEL_CLEAR_ID;
+ QTimer::singleShot(0, this, SLOT(dataCleared()));
+ } else {
+ d->queryId = globalXmlQuery()->doQuery(d->query, d->namespaces, data, &d->roleObjects, d->keyRoleResultsCache);
+ }
+ disconnect(d->reply, 0, this, 0);
+ d->reply->deleteLater();
+ d->reply = 0;
+
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QDeclarativeXmlListModel::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QDeclarativeXmlListModel::dataCleared()
+{
+ Q_D(QDeclarativeXmlListModel);
+ QDeclarativeXmlQueryResult r;
+ r.queryId = XMLLISTMODEL_CLEAR_ID;
+ r.size = 0;
+ r.removed << qMakePair(0, count());
+ r.keyRoleResultsCache = d->keyRoleResultsCache;
+ queryCompleted(r);
+}
+
+void QDeclarativeXmlListModel::queryError(void* object, const QString& error)
+{
+ // Be extra careful, object may no longer exist, it's just an ID.
+ Q_D(QDeclarativeXmlListModel);
+ for (int i=0; i<d->roleObjects.count(); i++) {
+ if (d->roleObjects.at(i) == static_cast<QDeclarativeXmlListModelRole*>(object)) {
+ qmlInfo(d->roleObjects.at(i)) << QObject::tr("invalid query: \"%1\"").arg(error);
+ return;
+ }
+ }
+ qmlInfo(this) << QObject::tr("invalid query: \"%1\"").arg(error);
+}
+
+void QDeclarativeXmlListModel::queryCompleted(const QDeclarativeXmlQueryResult &result)
+{
+ Q_D(QDeclarativeXmlListModel);
+ if (result.queryId != d->queryId)
+ return;
+
+ int origCount = d->size;
+ bool sizeChanged = result.size != d->size;
+
+ d->size = result.size;
+ d->data = result.data;
+ d->keyRoleResultsCache = result.keyRoleResultsCache;
+ d->status = Ready;
+ d->errorString.clear();
+ d->queryId = -1;
+
+ bool hasKeys = false;
+ for (int i=0; i<d->roleObjects.count(); i++) {
+ if (d->roleObjects[i]->isKey()) {
+ hasKeys = true;
+ break;
+ }
+ }
+ if (!hasKeys) {
+ if (!(origCount == 0 && d->size == 0)) {
+ emit itemsRemoved(0, origCount);
+ emit itemsInserted(0, d->size);
+ emit countChanged();
+ }
+
+ } else {
+ for (int i=0; i<result.removed.count(); i++)
+ emit itemsRemoved(result.removed[i].first, result.removed[i].second);
+ for (int i=0; i<result.inserted.count(); i++)
+ emit itemsInserted(result.inserted[i].first, result.inserted[i].second);
+
+ if (sizeChanged)
+ emit countChanged();
+ }
+
+ emit statusChanged(d->status);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativexmllistmodel.moc>
diff --git a/src/declarative/util/qdeclarativexmllistmodel_p.h b/src/declarative/util/qdeclarativexmllistmodel_p.h
new file mode 100644
index 0000000000..72fc478c8c
--- /dev/null
+++ b/src/declarative/util/qdeclarativexmllistmodel_p.h
@@ -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 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 QDECLARATIVEXMLLISTMODEL_H
+#define QDECLARATIVEXMLLISTMODEL_H
+
+#include <qdeclarative.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstringlist.h>
+#include <QtScript/qscriptvalue.h>
+
+#include <private/qlistmodelinterface_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeContext;
+class QDeclarativeXmlListModelRole;
+class QDeclarativeXmlListModelPrivate;
+
+struct QDeclarativeXmlQueryResult {
+ int queryId;
+ int size;
+ QList<QList<QVariant> > data;
+ QList<QPair<int, int> > inserted;
+ QList<QPair<int, int> > removed;
+ QStringList keyRoleResultsCache;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeXmlListModel : public QListModelInterface, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QString xml READ xml WRITE setXml NOTIFY xmlChanged)
+ Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(QString namespaceDeclarations READ namespaceDeclarations WRITE setNamespaceDeclarations NOTIFY namespaceDeclarationsChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeXmlListModelRole> roles READ roleObjects)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_CLASSINFO("DefaultProperty", "roles")
+
+public:
+ QDeclarativeXmlListModel(QObject *parent = 0);
+ ~QDeclarativeXmlListModel();
+
+ virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const;
+ virtual QVariant data(int index, int role) const;
+ virtual int count() const;
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+
+ QDeclarativeListProperty<QDeclarativeXmlListModelRole> roleObjects();
+
+ QUrl source() const;
+ void setSource(const QUrl&);
+
+ QString xml() const;
+ void setXml(const QString&);
+
+ QString query() const;
+ void setQuery(const QString&);
+
+ QString namespaceDeclarations() const;
+ void setNamespaceDeclarations(const QString&);
+
+ Q_INVOKABLE QScriptValue get(int index) const;
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ Q_INVOKABLE QString errorString() const;
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void statusChanged(QDeclarativeXmlListModel::Status);
+ void progressChanged(qreal progress);
+ void countChanged();
+ void sourceChanged();
+ void xmlChanged();
+ void queryChanged();
+ void namespaceDeclarationsChanged();
+
+public Q_SLOTS:
+ // ### need to use/expose Expiry to guess when to call this?
+ // ### property to auto-call this on reasonable Expiry?
+ // ### LastModified/Age also useful to guess.
+ // ### Probably also applies to other network-requesting types.
+ void reload();
+
+private Q_SLOTS:
+ void requestFinished();
+ void requestProgress(qint64,qint64);
+ void dataCleared();
+ void queryCompleted(const QDeclarativeXmlQueryResult &);
+ void queryError(void* object, const QString& error);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeXmlListModel)
+ Q_DISABLE_COPY(QDeclarativeXmlListModel)
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeXmlListModelRole : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
+ Q_PROPERTY(bool isKey READ isKey WRITE setIsKey NOTIFY isKeyChanged)
+public:
+ QDeclarativeXmlListModelRole() : m_isKey(false) {}
+ ~QDeclarativeXmlListModelRole() {}
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) {
+ if (name == m_name)
+ return;
+ m_name = name;
+ emit nameChanged();
+ }
+
+ QString query() const { return m_query; }
+ void setQuery(const QString &query)
+ {
+ if (query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << tr("An XmlRole query must not start with '/'");
+ return;
+ }
+ if (m_query == query)
+ return;
+ m_query = query;
+ emit queryChanged();
+ }
+
+ bool isKey() const { return m_isKey; }
+ void setIsKey(bool b) {
+ if (m_isKey == b)
+ return;
+ m_isKey = b;
+ emit isKeyChanged();
+ }
+
+ bool isValid() {
+ return !m_name.isEmpty() && !m_query.isEmpty();
+ }
+
+Q_SIGNALS:
+ void nameChanged();
+ void queryChanged();
+ void isKeyChanged();
+
+private:
+ QString m_name;
+ QString m_query;
+ bool m_isKey;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeXmlListModel)
+QML_DECLARE_TYPE(QDeclarativeXmlListModelRole)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEXMLLISTMODEL_H
diff --git a/src/declarative/util/qlistmodelinterface.cpp b/src/declarative/util/qlistmodelinterface.cpp
new file mode 100644
index 0000000000..4bad33f348
--- /dev/null
+++ b/src/declarative/util/qlistmodelinterface.cpp
@@ -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 QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt 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/qlistmodelinterface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QListModelInterface
+ \since 4.7
+ \brief The QListModelInterface class can be subclassed to provide C++ models to QDeclarativeGraphics Views
+
+ This class is comprised primarily of pure virtual functions which
+ you must implement in a subclass. You can then use the subclass
+ as a model for a QDeclarativeGraphics view, such as a QDeclarativeListView.
+*/
+
+/*! \fn QListModelInterface::QListModelInterface(QObject *parent)
+ Constructs a QListModelInterface with the specified \a parent.
+*/
+
+ /*! \fn QListModelInterface::QListModelInterface(QObjectPrivate &dd, QObject *parent)
+
+ \internal
+ */
+
+/*! \fn QListModelInterface::~QListModelInterface()
+ The destructor is virtual.
+ */
+
+/*! \fn int QListModelInterface::count() const
+ Returns the number of data entries in the model.
+*/
+
+/*! \fn QVariant QListModelInterface::data(int index, int role) const
+ Returns the data at the given \a index for the specified \a roles.
+*/
+
+/*! \fn QList<int> QListModelInterface::roles() const
+ Returns the list of roles for which the list model interface
+ provides data.
+*/
+
+/*! \fn QString QListModelInterface::toString(int role) const
+ Returns a string description of the specified \a role.
+*/
+
+/*! \fn void QListModelInterface::itemsInserted(int index, int count)
+ Emit this signal when \a count items are inserted at \a index.
+ */
+
+/*! \fn void QListModelInterface::itemsRemoved(int index, int count)
+ Emit this signal when \a count items are removed at \a index.
+ */
+
+/*! \fn void QListModelInterface::itemsMoved(int from, int to, int count)
+ Emit this signal when \a count items are moved from index \a from
+ to index \a to.
+ */
+
+/*! \fn void QListModelInterface::itemsChanged(int index, int count, const QList<int> &roles)
+ Emit this signal when \a count items at \a index have had their
+ \a roles changed.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qlistmodelinterface_p.h b/src/declarative/util/qlistmodelinterface_p.h
new file mode 100644
index 0000000000..3b44d0ad76
--- /dev/null
+++ b/src/declarative/util/qlistmodelinterface_p.h
@@ -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 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 QLISTMODELINTERFACE_H
+#define QLISTMODELINTERFACE_H
+
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QListModelInterface : public QObject
+{
+ Q_OBJECT
+ public:
+ QListModelInterface(QObject *parent = 0) : QObject(parent) {}
+ virtual ~QListModelInterface() {}
+
+ virtual int count() const = 0;
+ virtual QVariant data(int index, int role) const = 0;
+
+ virtual QList<int> roles() const = 0;
+ virtual QString toString(int role) const = 0;
+
+ Q_SIGNALS:
+ 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, const QList<int> &roles);
+
+ protected:
+ QListModelInterface(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent) {}
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QTREEMODELINTERFACE_H
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
new file mode 100644
index 0000000000..62fa8f1664
--- /dev/null
+++ b/src/declarative/util/util.pri
@@ -0,0 +1,72 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qdeclarativeapplication.cpp \
+ $$PWD/qdeclarativeutilmodule.cpp\
+ $$PWD/qdeclarativeview.cpp \
+ $$PWD/qdeclarativeconnections.cpp \
+ $$PWD/qdeclarativepackage.cpp \
+ $$PWD/qdeclarativeanimation.cpp \
+ $$PWD/qdeclarativesystempalette.cpp \
+ $$PWD/qdeclarativespringanimation.cpp \
+ $$PWD/qdeclarativesmoothedanimation.cpp \
+ $$PWD/qdeclarativestate.cpp\
+ $$PWD/qdeclarativetransitionmanager.cpp \
+ $$PWD/qdeclarativestateoperations.cpp \
+ $$PWD/qdeclarativepropertychanges.cpp \
+ $$PWD/qdeclarativestategroup.cpp \
+ $$PWD/qdeclarativetransition.cpp \
+ $$PWD/qdeclarativelistmodel.cpp\
+ $$PWD/qdeclarativelistaccessor.cpp \
+ $$PWD/qdeclarativeopenmetaobject.cpp \
+ $$PWD/qdeclarativetimeline.cpp \
+ $$PWD/qdeclarativetimer.cpp \
+ $$PWD/qdeclarativebind.cpp \
+ $$PWD/qdeclarativepropertymap.cpp \
+ $$PWD/qdeclarativepixmapcache.cpp \
+ $$PWD/qdeclarativebehavior.cpp \
+ $$PWD/qdeclarativefontloader.cpp \
+ $$PWD/qdeclarativestyledtext.cpp \
+ $$PWD/qdeclarativelistmodelworkeragent.cpp \
+ $$PWD/qlistmodelinterface.cpp
+
+HEADERS += \
+ $$PWD/qdeclarativeapplication_p.h \
+ $$PWD/qdeclarativeutilmodule_p.h\
+ $$PWD/qdeclarativeview.h \
+ $$PWD/qdeclarativeconnections_p.h \
+ $$PWD/qdeclarativepackage_p.h \
+ $$PWD/qdeclarativeanimation_p.h \
+ $$PWD/qdeclarativeanimation_p_p.h \
+ $$PWD/qdeclarativesystempalette_p.h \
+ $$PWD/qdeclarativespringanimation_p.h \
+ $$PWD/qdeclarativesmoothedanimation_p.h \
+ $$PWD/qdeclarativesmoothedanimation_p_p.h \
+ $$PWD/qdeclarativestate_p.h\
+ $$PWD/qdeclarativestateoperations_p.h \
+ $$PWD/qdeclarativepropertychanges_p.h \
+ $$PWD/qdeclarativestate_p_p.h\
+ $$PWD/qdeclarativetransitionmanager_p_p.h \
+ $$PWD/qdeclarativestategroup_p.h \
+ $$PWD/qdeclarativetransition_p.h \
+ $$PWD/qdeclarativelistmodel_p.h\
+ $$PWD/qdeclarativelistmodel_p_p.h\
+ $$PWD/qdeclarativelistaccessor_p.h \
+ $$PWD/qdeclarativeopenmetaobject_p.h \
+ $$PWD/qdeclarativenullablevalue_p_p.h \
+ $$PWD/qdeclarativetimeline_p_p.h \
+ $$PWD/qdeclarativetimer_p.h \
+ $$PWD/qdeclarativebind_p.h \
+ $$PWD/qdeclarativepropertymap.h \
+ $$PWD/qdeclarativepixmapcache_p.h \
+ $$PWD/qdeclarativebehavior_p.h \
+ $$PWD/qdeclarativefontloader_p.h \
+ $$PWD/qdeclarativestyledtext_p.h \
+ $$PWD/qdeclarativelistmodelworkeragent_p.h \
+ $$PWD/qlistmodelinterface_p.h
+
+contains(QT_CONFIG, xmlpatterns) {
+ QT+=xmlpatterns
+ SOURCES += $$PWD/qdeclarativexmllistmodel.cpp
+ HEADERS += $$PWD/qdeclarativexmllistmodel_p.h
+}