aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-02-16 14:43:03 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-24 04:51:31 +0100
commitb855240b782395f94315f43ea3e7e182299fac48 (patch)
treebc594c04449be8cd14cd0ab0bb72dafc2be0ffb2 /src/qml
parent6a42a6e0a9a1abdda0d07a5a20b4ac7e45348684 (diff)
Rename QDeclarative symbols to QQuick and QQml
Symbols beginning with QDeclarative are already exported by the quick1 module. Users can apply the bin/rename-qtdeclarative-symbols.sh script to modify client code using the previous names of the renamed symbols. Task-number: QTBUG-23737 Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66 Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/animations.pri16
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp544
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h233
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp164
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h93
-rw-r--r--src/qml/animations/qanimationjobutil_p.h59
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp227
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h81
-rw-r--r--src/qml/animations/qpauseanimationjob.cpp71
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h75
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp388
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h108
-rw-r--r--src/qml/debugger/debugger.pri32
-rw-r--r--src/qml/debugger/qdebugmessageservice.cpp124
-rw-r--r--src/qml/debugger/qdebugmessageservice_p.h91
-rw-r--r--src/qml/debugger/qpacketprotocol.cpp550
-rw-r--r--src/qml/debugger/qpacketprotocol_p.h137
-rw-r--r--src/qml/debugger/qqmldebug.h66
-rw-r--r--src/qml/debugger/qqmldebugclient.cpp421
-rw-r--r--src/qml/debugger/qqmldebugclient_p.h131
-rw-r--r--src/qml/debugger/qqmldebughelper.cpp70
-rw-r--r--src/qml/debugger/qqmldebughelper_p.h84
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp540
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h105
-rw-r--r--src/qml/debugger/qqmldebugserverconnection_p.h85
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp268
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h113
-rw-r--r--src/qml/debugger/qqmldebugservice_p_p.h82
-rw-r--r--src/qml/debugger/qqmldebugstatesdelegate_p.h98
-rw-r--r--src/qml/debugger/qqmlenginedebug.cpp1072
-rw-r--r--src/qml/debugger/qqmlenginedebug_p.h397
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp733
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h136
-rw-r--r--src/qml/debugger/qqmlinspectorinterface_p.h83
-rw-r--r--src/qml/debugger/qqmlinspectorservice.cpp186
-rw-r--r--src/qml/debugger/qqmlinspectorservice_p.h101
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp357
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h183
-rw-r--r--src/qml/debugger/qv8debugservice.cpp294
-rw-r--r--src/qml/debugger/qv8debugservice_p.h105
-rw-r--r--src/qml/debugger/qv8profilerservice.cpp287
-rw-r--r--src/qml/debugger/qv8profilerservice_p.h119
-rw-r--r--src/qml/qml.pro37
-rw-r--r--src/qml/qml/ftw/ftw.pri29
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h165
-rw-r--r--src/qml/qml/ftw/qdeletewatcher_p.h113
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder.cpp369
-rw-r--r--src/qml/qml/ftw/qfastmetabuilder_p.h206
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h426
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h186
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h338
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp490
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h1418
-rw-r--r--src/qml/qml/ftw/qhashfield_p.h120
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp179
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h274
-rw-r--r--src/qml/qml/ftw/qlazilyallocated_p.h146
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h173
-rw-r--r--src/qml/qml/ftw/qpointervaluepair_p.h196
-rw-r--r--src/qml/qml/ftw/qqmlpool.cpp92
-rw-r--r--src/qml/qml/ftw/qqmlpool_p.h278
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h192
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp359
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h318
-rw-r--r--src/qml/qml/ftw/qqmltrace.cpp154
-rw-r--r--src/qml/qml/ftw/qqmltrace_p.h294
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h105
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h220
-rw-r--r--src/qml/qml/parser/parser.pri19
-rw-r--r--src/qml/qml/parser/qqmljs.g3016
-rw-r--r--src/qml/qml/parser/qqmljsast.cpp931
-rw-r--r--src/qml/qml/parser/qqmljsast_p.h2640
-rw-r--r--src/qml/qml/parser/qqmljsastfwd_p.h186
-rw-r--r--src/qml/qml/parser/qqmljsastvisitor.cpp58
-rw-r--r--src/qml/qml/parser/qqmljsastvisitor_p.h329
-rw-r--r--src/qml/qml/parser/qqmljsengine_p.cpp161
-rw-r--r--src/qml/qml/parser/qqmljsengine_p.h126
-rw-r--r--src/qml/qml/parser/qqmljsglobal_p.h69
-rw-r--r--src/qml/qml/parser/qqmljsgrammar.cpp1013
-rw-r--r--src/qml/qml/parser/qqmljsgrammar_p.h211
-rw-r--r--src/qml/qml/parser/qqmljskeywords_p.h860
-rw-r--r--src/qml/qml/parser/qqmljslexer.cpp1166
-rw-r--r--src/qml/qml/parser/qqmljslexer_p.h248
-rw-r--r--src/qml/qml/parser/qqmljsmemorypool_p.h173
-rw-r--r--src/qml/qml/parser/qqmljsparser.cpp1812
-rw-r--r--src/qml/qml/parser/qqmljsparser_p.h248
-rw-r--r--src/qml/qml/qlistmodelinterface.cpp104
-rw-r--r--src/qml/qml/qlistmodelinterface_p.h83
-rw-r--r--src/qml/qml/qml.pri125
-rw-r--r--src/qml/qml/qqml.h451
-rw-r--r--src/qml/qml/qqmlaccessors.cpp127
-rw-r--r--src/qml/qml/qqmlaccessors_p.h166
-rw-r--r--src/qml/qml/qqmlbinding.cpp551
-rw-r--r--src/qml/qml/qqmlbinding_p.h219
-rw-r--r--src/qml/qml/qqmlbinding_p_p.h89
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp300
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h103
-rw-r--r--src/qml/qml/qqmlcleanup.cpp118
-rw-r--r--src/qml/qml/qqmlcleanup_p.h87
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp261
-rw-r--r--src/qml/qml/qqmlcompiler.cpp3882
-rw-r--r--src/qml/qml/qqmlcompiler_p.h466
-rw-r--r--src/qml/qml/qqmlcomponent.cpp1350
-rw-r--r--src/qml/qml/qqmlcomponent.h138
-rw-r--r--src/qml/qml/qqmlcomponent_p.h129
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h85
-rw-r--r--src/qml/qml/qqmlcontext.cpp811
-rw-r--r--src/qml/qml/qqmlcontext.h113
-rw-r--r--src/qml/qml/qqmlcontext_p.h334
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp319
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h168
-rw-r--r--src/qml/qml/qqmlcustomparser_p_p.h89
-rw-r--r--src/qml/qml/qqmldata_p.h207
-rw-r--r--src/qml/qml/qqmldirparser.cpp298
-rw-r--r--src/qml/qml/qqmldirparser_p.h166
-rw-r--r--src/qml/qml/qqmlengine.cpp1854
-rw-r--r--src/qml/qml/qqmlengine.h138
-rw-r--r--src/qml/qml/qqmlengine_p.h522
-rw-r--r--src/qml/qml/qqmlerror.cpp285
-rw-r--r--src/qml/qml/qqmlerror.h87
-rw-r--r--src/qml/qml/qqmlexpression.cpp982
-rw-r--r--src/qml/qml/qqmlexpression.h121
-rw-r--r--src/qml/qml/qqmlexpression_p.h406
-rw-r--r--src/qml/qml/qqmlextensioninterface.h76
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp171
-rw-r--r--src/qml/qml/qqmlextensionplugin.h77
-rw-r--r--src/qml/qml/qqmlglobal_p.h129
-rw-r--r--src/qml/qml/qqmlguard_p.h218
-rw-r--r--src/qml/qml/qqmlimageprovider.cpp334
-rw-r--r--src/qml/qml/qqmlimageprovider.h96
-rw-r--r--src/qml/qml/qqmlimport.cpp1183
-rw-r--r--src/qml/qml/qqmlimport_p.h157
-rw-r--r--src/qml/qml/qqmlincubator.cpp696
-rw-r--r--src/qml/qml/qqmlincubator.h129
-rw-r--r--src/qml/qml/qqmlincubator_p.h106
-rw-r--r--src/qml/qml/qqmlinfo.cpp192
-rw-r--r--src/qml/qml/qqmlinfo.h103
-rw-r--r--src/qml/qml/qqmlinstruction.cpp278
-rw-r--r--src/qml/qml/qqmlinstruction_p.h558
-rw-r--r--src/qml/qml/qqmlintegercache.cpp82
-rw-r--r--src/qml/qml/qqmlintegercache_p.h97
-rw-r--r--src/qml/qml/qqmllist.cpp417
-rw-r--r--src/qml/qml/qqmllist.h151
-rw-r--r--src/qml/qml/qqmllist_p.h85
-rw-r--r--src/qml/qml/qqmllocale.cpp1123
-rw-r--r--src/qml/qml/qqmllocale_p.h135
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1359
-rw-r--r--src/qml/qml/qqmlmetatype_p.h268
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp103
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h66
-rw-r--r--src/qml/qml/qqmlnotifier.cpp115
-rw-r--r--src/qml/qml/qqmlnotifier_p.h206
-rw-r--r--src/qml/qml/qqmlnullablevalue_p_p.h81
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp387
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h130
-rw-r--r--src/qml/qml/qqmlparserstatus.cpp107
-rw-r--r--src/qml/qml/qqmlparserstatus.h75
-rw-r--r--src/qml/qml/qqmlprivate.h265
-rw-r--r--src/qml/qml/qqmlproperty.cpp1917
-rw-r--r--src/qml/qml/qqmlproperty.h143
-rw-r--r--src/qml/qml/qqmlproperty_p.h171
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp889
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h383
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor.cpp79
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h74
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.cpp76
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.h67
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp124
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h99
-rw-r--r--src/qml/qml/qqmlrewrite.cpp441
-rw-r--r--src/qml/qml/qqmlrewrite_p.h149
-rw-r--r--src/qml/qml/qqmlscript.cpp1700
-rw-r--r--src/qml/qml/qqmlscript_p.h533
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp157
-rw-r--r--src/qml/qml/qqmlscriptstring.h90
-rw-r--r--src/qml/qml/qqmlscriptstring_p.h64
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp311
-rw-r--r--src/qml/qml/qqmlstringconverters_p.h93
-rw-r--r--src/qml/qml/qqmltypeloader.cpp1928
-rw-r--r--src/qml/qml/qqmltypeloader_p.h435
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp127
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h187
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp53
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h64
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp868
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h635
-rw-r--r--src/qml/qml/qqmlvme.cpp1370
-rw-r--r--src/qml/qml/qqmlvme_p.h240
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp1110
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h221
-rw-r--r--src/qml/qml/qqmlwatcher.cpp188
-rw-r--r--src/qml/qml/qqmlwatcher_p.h94
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp1797
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h73
-rw-r--r--src/qml/qml/qquickapplication.cpp124
-rw-r--r--src/qml/qml/qquickapplication_p.h87
-rw-r--r--src/qml/qml/qquicklistmodel.cpp2467
-rw-r--r--src/qml/qml/qquicklistmodel_p.h199
-rw-r--r--src/qml/qml/qquicklistmodel_p_p.h378
-rw-r--r--src/qml/qml/qquicklistmodelworkeragent.cpp246
-rw-r--r--src/qml/qml/qquicklistmodelworkeragent_p.h161
-rw-r--r--src/qml/qml/qquickworkerscript.cpp730
-rw-r--r--src/qml/qml/qquickworkerscript_p.h130
-rw-r--r--src/qml/qml/rewriter/rewriter.pri2
-rw-r--r--src/qml/qml/rewriter/textwriter.cpp217
-rw-r--r--src/qml/qml/rewriter/textwriter_p.h101
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp1538
-rw-r--r--src/qml/qml/v4/qv4bindings_p.h153
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp1399
-rw-r--r--src/qml/qml/v4/qv4compiler_p.h105
-rw-r--r--src/qml/qml/v4/qv4compiler_p_p.h245
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp412
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h432
-rw-r--r--src/qml/qml/v4/qv4ir.cpp882
-rw-r--r--src/qml/qml/v4/qv4ir_p.h604
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp1303
-rw-r--r--src/qml/qml/v4/qv4irbuilder_p.h240
-rw-r--r--src/qml/qml/v4/qv4program_p.h122
-rw-r--r--src/qml/qml/v4/v4.pri15
-rw-r--r--src/qml/qml/v8/notes.txt4
-rw-r--r--src/qml/qml/v8/qjsconverter_impl_p.h268
-rw-r--r--src/qml/qml/v8/qjsconverter_p.h93
-rw-r--r--src/qml/qml/v8/qjsengine.cpp476
-rw-r--r--src/qml/qml/v8/qjsengine.h141
-rw-r--r--src/qml/qml/v8/qjsengine_p.h57
-rw-r--r--src/qml/qml/v8/qjsvalue.cpp856
-rw-r--r--src/qml/qml/v8/qjsvalue.h143
-rw-r--r--src/qml/qml/v8/qjsvalue_impl_p.h977
-rw-r--r--src/qml/qml/v8/qjsvalue_p.h195
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.cpp157
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.h63
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_impl_p.h121
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_p.h68
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1320
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h110
-rw-r--r--src/qml/qml/v8/qscript_impl_p.h43
-rw-r--r--src/qml/qml/v8/qscriptisolate_p.h71
-rw-r--r--src/qml/qml/v8/qscriptoriginalglobalobject_p.h159
-rw-r--r--src/qml/qml/v8/qscriptshareddata_p.h151
-rw-r--r--src/qml/qml/v8/qscripttools_p.h68
-rw-r--r--src/qml/qml/v8/qv8_p.h42
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp285
-rw-r--r--src/qml/qml/v8/qv8bindings_p.h148
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp455
-rw-r--r--src/qml/qml/v8/qv8contextwrapper_p.h120
-rw-r--r--src/qml/qml/v8/qv8debug_p.h42
-rw-r--r--src/qml/qml/v8/qv8domerrors.cpp73
-rw-r--r--src/qml/qml/v8/qv8domerrors_p.h94
-rw-r--r--src/qml/qml/v8/qv8engine.cpp1598
-rw-r--r--src/qml/qml/v8/qv8engine_impl_p.h155
-rw-r--r--src/qml/qml/v8/qv8engine_p.h631
-rw-r--r--src/qml/qml/v8/qv8include.cpp244
-rw-r--r--src/qml/qml/v8/qv8include_p.h113
-rw-r--r--src/qml/qml/v8/qv8listwrapper.cpp194
-rw-r--r--src/qml/qml/v8/qv8listwrapper_p.h97
-rw-r--r--src/qml/qml/v8/qv8profiler_p.h42
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp2113
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h159
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper.cpp264
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p.h106
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p_p.h503
-rw-r--r--src/qml/qml/v8/qv8sqlerrors.cpp64
-rw-r--r--src/qml/qml/v8/qv8sqlerrors_p.h77
-rw-r--r--src/qml/qml/v8/qv8stringwrapper.cpp78
-rw-r--r--src/qml/qml/v8/qv8stringwrapper_p.h78
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp314
-rw-r--r--src/qml/qml/v8/qv8typewrapper_p.h94
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp387
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper_p.h104
-rw-r--r--src/qml/qml/v8/qv8variantresource_p.h81
-rw-r--r--src/qml/qml/v8/qv8variantwrapper.cpp279
-rw-r--r--src/qml/qml/v8/qv8variantwrapper_p.h110
-rw-r--r--src/qml/qml/v8/qv8worker.cpp392
-rw-r--r--src/qml/qml/v8/qv8worker_p.h75
-rw-r--r--src/qml/qml/v8/script.pri21
-rw-r--r--src/qml/qml/v8/v8.pri45
-rw-r--r--src/qml/qtqmlglobal.h67
-rw-r--r--src/qml/qtqmlglobal_p.h60
-rw-r--r--src/qml/util/qqmlpropertymap.cpp309
-rw-r--r--src/qml/util/qqmlpropertymap.h91
-rw-r--r--src/qml/util/util.pri5
281 files changed, 99733 insertions, 0 deletions
diff --git a/src/qml/animations/animations.pri b/src/qml/animations/animations.pri
new file mode 100644
index 0000000000..01ac25af46
--- /dev/null
+++ b/src/qml/animations/animations.pri
@@ -0,0 +1,16 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qabstractanimationjob_p.h \
+ $$PWD/qanimationgroupjob_p.h \
+ $$PWD/qsequentialanimationgroupjob_p.h \
+ $$PWD/qparallelanimationgroupjob_p.h \
+ $$PWD/qpauseanimationjob_p.h \
+ $$PWD/qanimationjobutil_p.h
+
+SOURCES += \
+ $$PWD/qabstractanimationjob.cpp \
+ $$PWD/qanimationgroupjob.cpp \
+ $$PWD/qsequentialanimationgroupjob.cpp \
+ $$PWD/qparallelanimationgroupjob.cpp \
+ $$PWD/qpauseanimationjob.cpp
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
new file mode 100644
index 0000000000..2bfc66fea0
--- /dev/null
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -0,0 +1,544 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qthreadstorage.h>
+
+#include "private/qabstractanimationjob_p.h"
+#include "private/qanimationgroupjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+#define DEFAULT_TIMER_INTERVAL 16
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_THREAD
+Q_GLOBAL_STATIC(QThreadStorage<QQmlAnimationTimer *>, animationTimer)
+#endif
+
+QQmlAnimationTimer::QQmlAnimationTimer() :
+ QAbstractAnimationTimer(), lastTick(0), lastDelta(0),
+ currentAnimationIdx(0), insideTick(false),
+ startAnimationPending(false), stopTimerPending(false),
+ runningLeafAnimations(0)
+{
+}
+
+QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create)
+{
+ QQmlAnimationTimer *inst;
+#ifndef QT_NO_THREAD
+ if (create && !animationTimer()->hasLocalData()) {
+ inst = new QQmlAnimationTimer;
+ animationTimer()->setLocalData(inst);
+ } else {
+ inst = animationTimer() ? animationTimer()->localData() : 0;
+ }
+#else
+ static QAnimationTimer unifiedTimer;
+ inst = &unifiedTimer;
+#endif
+ return inst;
+}
+
+QQmlAnimationTimer *QQmlAnimationTimer::instance()
+{
+ return instance(true);
+}
+
+void QQmlAnimationTimer::ensureTimerUpdate()
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ QUnifiedTimer *instU = QUnifiedTimer::instance(false);
+ if (instU && inst && inst->isPaused)
+ instU->updateAnimationTimers(-1);
+}
+
+void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
+{
+ //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
+ if (insideTick)
+ return;
+
+ lastTick += delta;
+ lastDelta = delta;
+
+ //we make sure we only call update time if the time has actually changed
+ //it might happen in some cases that the time doesn't change because events are delayed
+ //when the CPU load is high
+ if (delta) {
+ insideTick = true;
+ for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
+ QAbstractAnimationJob *animation = animations.at(currentAnimationIdx);
+ int elapsed = animation->m_totalCurrentTime
+ + (animation->direction() == QAbstractAnimationJob::Forward ? delta : -delta);
+ animation->setCurrentTime(elapsed);
+ }
+ insideTick = false;
+ currentAnimationIdx = 0;
+ }
+}
+
+void QQmlAnimationTimer::updateAnimationTimer()
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ if (inst)
+ inst->restartAnimationTimer();
+}
+
+void QQmlAnimationTimer::restartAnimationTimer()
+{
+ if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
+ QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
+ else if (isPaused)
+ QUnifiedTimer::resumeAnimationTimer(this);
+ else if (!isRegistered)
+ QUnifiedTimer::startAnimationTimer(this);
+}
+
+void QQmlAnimationTimer::startAnimations()
+{
+ startAnimationPending = false;
+ //force timer to update, which prevents large deltas for our newly added animations
+ if (!animations.isEmpty())
+ QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
+
+ //we transfer the waiting animations into the "really running" state
+ animations += animationsToStart;
+ animationsToStart.clear();
+ if (!animations.isEmpty())
+ restartAnimationTimer();
+}
+
+void QQmlAnimationTimer::stopTimer()
+{
+ stopTimerPending = false;
+ if (animations.isEmpty()) {
+ QUnifiedTimer::resumeAnimationTimer(this);
+ QUnifiedTimer::stopAnimationTimer(this);
+ // invalidate the start reference time
+ lastTick = 0;
+ lastDelta = 0;
+ }
+}
+
+void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel)
+{
+ QQmlAnimationTimer *inst = instance(true); //we create the instance if needed
+ inst->registerRunningAnimation(animation);
+ if (isTopLevel) {
+ Q_ASSERT(!animation->m_hasRegisteredTimer);
+ animation->m_hasRegisteredTimer = true;
+ inst->animationsToStart << animation;
+ if (!inst->startAnimationPending) {
+ inst->startAnimationPending = true;
+ QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
+ }
+ }
+}
+
+void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
+{
+ QQmlAnimationTimer *inst = QQmlAnimationTimer::instance(false);
+ if (inst) {
+ //at this point the unified timer should have been created
+ //but it might also have been already destroyed in case the application is shutting down
+
+ inst->unregisterRunningAnimation(animation);
+
+ if (!animation->m_hasRegisteredTimer)
+ return;
+
+ int idx = inst->animations.indexOf(animation);
+ if (idx != -1) {
+ inst->animations.removeAt(idx);
+ // this is needed if we unregister an animation while its running
+ if (idx <= inst->currentAnimationIdx)
+ --inst->currentAnimationIdx;
+
+ if (inst->animations.isEmpty() && !inst->stopTimerPending) {
+ inst->stopTimerPending = true;
+ QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
+ }
+ } else {
+ inst->animationsToStart.removeOne(animation);
+ }
+ }
+ animation->m_hasRegisteredTimer = false;
+}
+
+void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animation)
+{
+ if (animation->m_isGroup)
+ return;
+
+ if (animation->m_isPause) {
+ runningPauseAnimations << animation;
+ } else
+ runningLeafAnimations++;
+}
+
+void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation)
+{
+ if (animation->m_isGroup)
+ return;
+
+ if (animation->m_isPause)
+ runningPauseAnimations.removeOne(animation);
+ else
+ runningLeafAnimations--;
+ Q_ASSERT(runningLeafAnimations >= 0);
+}
+
+int QQmlAnimationTimer::closestPauseAnimationTimeToFinish()
+{
+ int closestTimeToFinish = INT_MAX;
+ for (int i = 0; i < runningPauseAnimations.size(); ++i) {
+ QAbstractAnimationJob *animation = runningPauseAnimations.at(i);
+ int timeToFinish;
+
+ if (animation->direction() == QAbstractAnimationJob::Forward)
+ timeToFinish = animation->duration() - animation->currentLoopTime();
+ else
+ timeToFinish = animation->currentLoopTime();
+
+ if (timeToFinish < closestTimeToFinish)
+ closestTimeToFinish = timeToFinish;
+ }
+ return closestTimeToFinish;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+QAbstractAnimationJob::QAbstractAnimationJob()
+ : m_isPause(false)
+ , m_isGroup(false)
+ , m_loopCount(1)
+ , m_group(0)
+ , m_direction(QAbstractAnimationJob::Forward)
+ , m_state(QAbstractAnimationJob::Stopped)
+ , m_totalCurrentTime(0)
+ , m_currentTime(0)
+ , m_currentLoop(0)
+ , m_hasRegisteredTimer(false)
+ , m_uncontrolledFinishTime(-1)
+ , m_wasDeleted(0)
+ , m_nextSibling(0)
+ , m_previousSibling(0)
+{
+}
+
+QAbstractAnimationJob::~QAbstractAnimationJob()
+{
+ if (m_wasDeleted)
+ *m_wasDeleted = true;
+
+ //we can't call stop here. Otherwise we get pure virtual calls
+ if (m_state != Stopped) {
+ State oldState = m_state;
+ m_state = Stopped;
+ stateChanged(oldState, m_state);
+ if (oldState == Running)
+ QQmlAnimationTimer::unregisterAnimation(this);
+ }
+
+ if (m_group)
+ m_group->removeAnimation(this);
+}
+
+void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
+{
+ if (m_state == newState)
+ return;
+
+ if (m_loopCount == 0)
+ return;
+
+ State oldState = m_state;
+ int oldCurrentTime = m_currentTime;
+ int oldCurrentLoop = m_currentLoop;
+ Direction oldDirection = m_direction;
+
+ // check if we should Rewind
+ if ((newState == Paused || newState == Running) && oldState == Stopped) {
+ //here we reset the time if needed
+ //we don't call setCurrentTime because this might change the way the animation
+ //behaves: changing the state or changing the current value
+ m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
+ 0 : (m_loopCount == -1 ? duration() : totalDuration());
+ }
+
+ m_state = newState;
+ //(un)registration of the animation must always happen before calls to
+ //virtual function (updateState) to ensure a correct state of the timer
+ bool isTopLevel = !m_group || m_group->isStopped();
+ if (oldState == Running) {
+ if (newState == Paused && m_hasRegisteredTimer)
+ QQmlAnimationTimer::ensureTimerUpdate();
+ //the animation, is not running any more
+ QQmlAnimationTimer::unregisterAnimation(this);
+ } else if (newState == Running) {
+ QQmlAnimationTimer::registerAnimation(this, isTopLevel);
+ }
+
+ //starting an animation qualifies as a top level loop change
+ if (newState == Running && oldState == Stopped && !m_group)
+ topLevelAnimationLoopChanged();
+
+ RETURN_IF_DELETED(updateState(newState, oldState));
+
+ if (newState != m_state) //this is to be safe if updateState changes the state
+ return;
+
+ // Notify state change
+ stateChanged(newState, oldState);
+ if (newState != m_state) //this is to be safe if updateState changes the state
+ return;
+
+ switch (m_state) {
+ case Paused:
+ break;
+ case Running:
+ {
+ // this ensures that the value is updated now that the animation is running
+ if (oldState == Stopped) {
+ if (isTopLevel) {
+ // currentTime needs to be updated if pauseTimer is active
+ QQmlAnimationTimer::ensureTimerUpdate();
+ setCurrentTime(m_totalCurrentTime);
+ }
+ }
+ }
+ break;
+ case Stopped:
+ // Leave running state.
+ int dura = duration();
+
+ if (dura == -1 || m_loopCount < 0
+ || (oldDirection == Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * m_loopCount))
+ || (oldDirection == Backward && oldCurrentTime == 0)) {
+ finished();
+ }
+ break;
+ }
+}
+
+void QAbstractAnimationJob::setDirection(Direction direction)
+{
+ if (m_direction == direction)
+ return;
+
+ if (m_state == Stopped) {
+ if (m_direction == Backward) {
+ m_currentTime = duration();
+ m_currentLoop = m_loopCount - 1;
+ } else {
+ m_currentTime = 0;
+ m_currentLoop = 0;
+ }
+ }
+
+ // the commands order below is important: first we need to setCurrentTime with the old direction,
+ // then update the direction on this and all children and finally restart the pauseTimer if needed
+ if (m_hasRegisteredTimer)
+ QQmlAnimationTimer::ensureTimerUpdate();
+
+ m_direction = direction;
+ updateDirection(direction);
+
+ if (m_hasRegisteredTimer)
+ // needed to update the timer interval in case of a pause animation
+ QQmlAnimationTimer::updateAnimationTimer();
+}
+
+void QAbstractAnimationJob::setLoopCount(int loopCount)
+{
+ m_loopCount = loopCount;
+}
+
+int QAbstractAnimationJob::totalDuration() const
+{
+ int dura = duration();
+ if (dura <= 0)
+ return dura;
+ int loopcount = loopCount();
+ if (loopcount < 0)
+ return -1;
+ return dura * loopcount;
+}
+
+void QAbstractAnimationJob::setCurrentTime(int msecs)
+{
+ msecs = qMax(msecs, 0);
+ // Calculate new time and loop.
+ int dura = duration();
+ int totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
+ if (totalDura != -1)
+ msecs = qMin(totalDura, msecs);
+ m_totalCurrentTime = msecs;
+
+ // Update new values.
+ int oldLoop = m_currentLoop;
+ m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
+ if (m_currentLoop == m_loopCount) {
+ //we're at the end
+ m_currentTime = qMax(0, dura);
+ m_currentLoop = qMax(0, m_loopCount - 1);
+ } else {
+ if (m_direction == Forward) {
+ m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ } else {
+ m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
+ if (m_currentTime == dura)
+ --m_currentLoop;
+ }
+ }
+
+ if (m_currentLoop != oldLoop && !m_group) //### verify Running as well?
+ topLevelAnimationLoopChanged();
+
+ RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
+
+ if (m_currentLoop != oldLoop)
+ currentLoopChanged(m_currentLoop);
+
+ // All animations are responsible for stopping the animation when their
+ // own end state is reached; in this case the animation is time driven,
+ // and has reached the end.
+ if ((m_direction == Forward && m_totalCurrentTime == totalDura)
+ || (m_direction == Backward && m_totalCurrentTime == 0)) {
+ stop();
+ }
+}
+
+void QAbstractAnimationJob::start()
+{
+ if (m_state == Running)
+ return;
+ setState(Running);
+}
+
+void QAbstractAnimationJob::stop()
+{
+ if (m_state == Stopped)
+ return;
+ setState(Stopped);
+}
+
+void QAbstractAnimationJob::pause()
+{
+ if (m_state == Stopped) {
+ qWarning("QAbstractAnimationJob::pause: Cannot pause a stopped animation");
+ return;
+ }
+
+ setState(Paused);
+}
+
+void QAbstractAnimationJob::resume()
+{
+ if (m_state != Paused) {
+ qWarning("QAbstractAnimationJob::resume: "
+ "Cannot resume an animation that is not paused");
+ return;
+ }
+ setState(Running);
+}
+
+void QAbstractAnimationJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+}
+
+void QAbstractAnimationJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ Q_UNUSED(direction);
+}
+
+void QAbstractAnimationJob::finished()
+{
+ //TODO: update this code so it is valid to delete the animation in animationFinished
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::Completion)
+ change.listener->animationFinished(this);
+ }
+
+ if (m_group && (duration() == -1 || loopCount() < 0)) {
+ //this is an uncontrolled animation, need to notify the group animation we are finished
+ m_group->uncontrolledAnimationFinished(this);
+ }
+}
+
+void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
+{
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::StateChange)
+ change.listener->animationStateChanged(this, newState, oldState);
+ }
+}
+
+void QAbstractAnimationJob::currentLoopChanged(int currentLoop)
+{
+ Q_UNUSED(currentLoop);
+ for (int i = 0; i < changeListeners.count(); ++i) {
+ const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i);
+ if (change.types & QAbstractAnimationJob::CurrentLoop)
+ change.listener->animationCurrentLoopChanged(this);
+ }
+}
+
+void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
+{
+ changeListeners.append(ChangeListener(listener, changes));
+}
+
+void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
+{
+ changeListeners.removeOne(ChangeListener(listener, changes));
+}
+
+
+QT_END_NAMESPACE
+
+//#include "moc_qabstractanimation2_p.cpp"
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
new file mode 100644
index 0000000000..f00090cb30
--- /dev/null
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATIONJOB_P_H
+#define QABSTRACTANIMATIONJOB_P_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QObject>
+#include <QtCore/private/qabstractanimation_p.h>
+#include "private/qpodvector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QAnimationGroupJob;
+class QAnimationJobChangeListener;
+class Q_QML_EXPORT QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QAbstractAnimationJob)
+public:
+ enum Direction {
+ Forward,
+ Backward
+ };
+
+ enum State {
+ Stopped,
+ Paused,
+ Running
+ };
+
+ QAbstractAnimationJob();
+ virtual ~QAbstractAnimationJob();
+
+ //definition
+ inline QAnimationGroupJob *group() const {return m_group;}
+
+ inline int loopCount() const {return m_loopCount;}
+ void setLoopCount(int loopCount);
+
+ int totalDuration() const;
+ virtual int duration() const {return 0;}
+
+ inline QAbstractAnimationJob::Direction direction() const {return m_direction;}
+ void setDirection(QAbstractAnimationJob::Direction direction);
+
+ //state
+ inline int currentTime() const {return m_totalCurrentTime;}
+ inline int currentLoopTime() const {return m_currentTime;}
+ inline int currentLoop() const {return m_currentLoop;}
+ inline QAbstractAnimationJob::State state() const {return m_state;}
+ inline bool isRunning() { return m_state == Running; }
+ inline bool isStopped() { return m_state == Stopped; }
+ inline bool isPaused() { return m_state == Paused; }
+
+ void setCurrentTime(int msecs);
+
+ void start();
+ void pause();
+ void resume();
+ void stop();
+
+ enum ChangeType {
+ Completion = 0x01,
+ StateChange = 0x02,
+ CurrentLoop = 0x04
+ };
+ Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
+
+ void addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
+ void removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
+
+ QAbstractAnimationJob *nextSibling() const { return m_nextSibling; }
+ QAbstractAnimationJob *previousSibling() const { return m_previousSibling; }
+
+protected:
+ virtual void updateCurrentTime(int) {}
+ virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ virtual void updateDirection(QAbstractAnimationJob::Direction direction);
+ virtual void topLevelAnimationLoopChanged() {}
+
+ void setState(QAbstractAnimationJob::State state);
+
+ void finished();
+ void stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void currentLoopChanged(int currentLoop);
+ void directionChanged(QAbstractAnimationJob::Direction);
+
+ //definition
+ bool m_isPause;
+ bool m_isGroup;
+ int m_loopCount;
+ QAnimationGroupJob *m_group;
+ QAbstractAnimationJob::Direction m_direction;
+
+ //state
+ QAbstractAnimationJob::State m_state;
+ int m_totalCurrentTime;
+ int m_currentTime;
+ int m_currentLoop;
+ bool m_hasRegisteredTimer;
+ //records the finish time for an uncontrolled animation (used by animation groups)
+ int m_uncontrolledFinishTime;
+ bool *m_wasDeleted;
+
+ struct ChangeListener {
+ ChangeListener(QAnimationJobChangeListener *l, QAbstractAnimationJob::ChangeTypes t) : listener(l), types(t) {}
+ QAnimationJobChangeListener *listener;
+ QAbstractAnimationJob::ChangeTypes types;
+ bool operator==(const ChangeListener &other) const { return listener == other.listener && types == other.types; }
+ };
+ QPODVector<ChangeListener,4> changeListeners;
+
+ QAbstractAnimationJob *m_nextSibling;
+ QAbstractAnimationJob *m_previousSibling;
+
+ friend class QQmlAnimationTimer;
+ friend class QAnimationGroupJob;
+};
+
+class Q_AUTOTEST_EXPORT QAnimationJobChangeListener
+{
+public:
+ virtual void animationFinished(QAbstractAnimationJob *) {}
+ virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State) {}
+ virtual void animationCurrentLoopChanged(QAbstractAnimationJob *) {}
+};
+
+class Q_QML_EXPORT QQmlAnimationTimer : public QAbstractAnimationTimer
+{
+ Q_OBJECT
+private:
+ QQmlAnimationTimer();
+
+public:
+ static QQmlAnimationTimer *instance();
+ static QQmlAnimationTimer *instance(bool create);
+
+ static void registerAnimation(QAbstractAnimationJob *animation, bool isTopLevel);
+ static void unregisterAnimation(QAbstractAnimationJob *animation);
+
+ /*
+ this is used for updating the currentTime of all animations in case the pause
+ timer is active or, otherwise, only of the animation passed as parameter.
+ */
+ static void ensureTimerUpdate();
+
+ /*
+ this will evaluate the need of restarting the pause timer in case there is still
+ some pause animations running.
+ */
+ static void updateAnimationTimer();
+
+ void restartAnimationTimer();
+ void updateAnimationsTime(qint64 timeStep);
+
+ int currentDelta() { return lastDelta; }
+
+ //useful for profiling/debugging
+ int runningAnimationCount() { return animations.count(); }
+
+private Q_SLOTS:
+ void startAnimations();
+ void stopTimer();
+
+private:
+ qint64 lastTick;
+ int lastDelta;
+ int currentAnimationIdx;
+ bool insideTick;
+ bool startAnimationPending;
+ bool stopTimerPending;
+
+ QList<QAbstractAnimationJob*> animations, animationsToStart;
+
+ // this is the count of running animations that are not a group neither a pause animation
+ int runningLeafAnimations;
+ QList<QAbstractAnimationJob*> runningPauseAnimations;
+
+ void registerRunningAnimation(QAbstractAnimationJob *animation);
+ void unregisterRunningAnimation(QAbstractAnimationJob *animation);
+
+ int closestPauseAnimationTimeToFinish();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractAnimationJob::ChangeTypes)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTANIMATIONJOB_P_H
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
new file mode 100644
index 0000000000..83b2192313
--- /dev/null
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qanimationgroupjob_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QAnimationGroupJob::QAnimationGroupJob()
+ : QAbstractAnimationJob(), m_firstChild(0), m_lastChild(0)
+{
+ m_isGroup = true;
+}
+
+QAnimationGroupJob::~QAnimationGroupJob()
+{
+ while (firstChild() != 0)
+ delete firstChild();
+}
+
+void QAnimationGroupJob::topLevelAnimationLoopChanged()
+{
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ animation->topLevelAnimationLoopChanged();
+}
+
+void QAnimationGroupJob::appendAnimation(QAbstractAnimationJob *animation)
+{
+ if (QAnimationGroupJob *oldGroup = animation->m_group)
+ oldGroup->removeAnimation(animation);
+
+ Q_ASSERT(!animation->previousSibling() && !animation->nextSibling());
+
+ if (m_lastChild)
+ m_lastChild->m_nextSibling = animation;
+ else
+ m_firstChild = animation;
+ animation->m_previousSibling = m_lastChild;
+ m_lastChild = animation;
+
+ animation->m_group = this;
+ animationInserted(animation);
+}
+
+void QAnimationGroupJob::prependAnimation(QAbstractAnimationJob *animation)
+{
+ if (QAnimationGroupJob *oldGroup = animation->m_group)
+ oldGroup->removeAnimation(animation);
+
+ Q_ASSERT(!previousSibling() && !nextSibling());
+
+ if (m_firstChild)
+ m_firstChild->m_previousSibling = animation;
+ else
+ m_lastChild = animation;
+ animation->m_nextSibling = m_firstChild;
+ m_firstChild = animation;
+
+ animation->m_group = this;
+ animationInserted(animation);
+}
+
+void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation);
+ Q_ASSERT(animation->m_group == this);
+ QAbstractAnimationJob *prev = animation->previousSibling();
+ QAbstractAnimationJob *next = animation->nextSibling();
+
+ if (prev)
+ prev->m_nextSibling = next;
+ else
+ m_firstChild = next;
+
+ if (next)
+ next->m_previousSibling = prev;
+ else
+ m_lastChild = prev;
+
+ animation->m_previousSibling = 0;
+ animation->m_nextSibling = 0;
+
+ animation->m_group = 0;
+ animationRemoved(animation, prev, next);
+}
+
+void QAnimationGroupJob::clear()
+{
+ //### should this remove and delete, or just remove?
+ while (firstChild() != 0)
+ delete firstChild(); //removeAnimation(firstChild());
+}
+
+void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime()
+{
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ resetUncontrolledAnimationFinishTime(animation);
+ }
+ }
+}
+
+void QAnimationGroupJob::resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim)
+{
+ setUncontrolledAnimationFinishTime(anim, -1);
+}
+
+void QAnimationGroupJob::setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time)
+{
+ anim->m_uncontrolledFinishTime = time;
+}
+
+void QAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_UNUSED(animation);
+}
+
+void QAnimationGroupJob::animationRemoved(QAbstractAnimationJob* anim, QAbstractAnimationJob* , QAbstractAnimationJob* )
+{
+ resetUncontrolledAnimationFinishTime(anim);
+ if (!firstChild()) {
+ m_currentTime = 0;
+ stop();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
new file mode 100644
index 0000000000..303dc898d9
--- /dev/null
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUPJOB_P_H
+#define QANIMATIONGROUPJOB_P_H
+
+#include "private/qabstractanimationjob_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QAnimationGroupJob)
+public:
+ QAnimationGroupJob();
+ ~QAnimationGroupJob();
+
+ void appendAnimation(QAbstractAnimationJob *animation);
+ void prependAnimation(QAbstractAnimationJob *animation);
+ void removeAnimation(QAbstractAnimationJob *animation);
+
+ QAbstractAnimationJob *firstChild() const { return m_firstChild; }
+ QAbstractAnimationJob *lastChild() const { return m_lastChild; }
+
+ void clear();
+
+ //called by QAbstractAnimationJob
+ virtual void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+protected:
+ void topLevelAnimationLoopChanged();
+
+ virtual void animationInserted(QAbstractAnimationJob*) { }
+ virtual void animationRemoved(QAbstractAnimationJob*, QAbstractAnimationJob*, QAbstractAnimationJob*);
+
+ //TODO: confirm location of these (should any be moved into QAbstractAnimationJob?)
+ void resetUncontrolledAnimationsFinishTime();
+ void resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim);
+ int uncontrolledAnimationFinishTime(QAbstractAnimationJob *anim) const { return anim->m_uncontrolledFinishTime; }
+ void setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time);
+
+private:
+ //definition
+ QAbstractAnimationJob *m_firstChild;
+ QAbstractAnimationJob *m_lastChild;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATIONGROUPJOB_P_H
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
new file mode 100644
index 0000000000..c891b8725d
--- /dev/null
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONJOBUTIL_P_H
+#define QANIMATIONJOBUTIL_P_H
+
+#define RETURN_IF_DELETED(func) \
+{ \
+ bool *prevWasDeleted = m_wasDeleted; \
+ bool wasDeleted = false; \
+ m_wasDeleted = &wasDeleted; \
+ func; \
+ if (wasDeleted) { \
+ if (prevWasDeleted) \
+ *prevWasDeleted = true; \
+ return; \
+ } \
+ m_wasDeleted = prevWasDeleted; \
+}
+
+#endif // QANIMATIONJOBUTIL_P_H
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
new file mode 100644
index 0000000000..0472c959f4
--- /dev/null
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qparallelanimationgroupjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QParallelAnimationGroupJob::QParallelAnimationGroupJob()
+ : QAnimationGroupJob()
+ , m_previousLoop(0)
+ , m_previousCurrentTime(0)
+{
+}
+
+QParallelAnimationGroupJob::~QParallelAnimationGroupJob()
+{
+}
+
+int QParallelAnimationGroupJob::duration() const
+{
+ int ret = 0;
+
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ int currentDuration = animation->totalDuration();
+ //this takes care of the case where a parallel animation group has controlled and uncontrolled
+ //animations, and the uncontrolled stop before the controlled
+ if (currentDuration == -1)
+ currentDuration = uncontrolledAnimationFinishTime(animation);
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret = qMax(ret, currentDuration);
+ }
+
+ return ret;
+}
+
+void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
+{
+ if (!firstChild())
+ return;
+
+ if (m_currentLoop > m_previousLoop) {
+ // simulate completion of the loop
+ int dura = duration();
+ if (dura > 0) {
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (!animation->isStopped())
+ RETURN_IF_DELETED(animation->setCurrentTime(dura)); // will stop
+ }
+ }
+ } else if (m_currentLoop < m_previousLoop) {
+ // simulate completion of the loop seeking backwards
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ //we need to make sure the animation is in the right state
+ //and then rewind it
+ applyGroupState(animation);
+ RETURN_IF_DELETED(animation->setCurrentTime(0));
+ animation->stop();
+ }
+ }
+
+ // finally move into the actual time of the current loop
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ const int dura = animation->totalDuration();
+ //if the loopcount is bigger we should always start all animations
+ if (m_currentLoop > m_previousLoop
+ //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
+ //this happens in Backward direction where not all animations are started at the same time
+ || shouldAnimationStart(animation, m_previousCurrentTime > dura /*startIfAtEnd*/)) {
+ applyGroupState(animation);
+ }
+
+ if (animation->state() == state()) {
+ RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
+ if (dura > 0 && m_currentTime > dura)
+ animation->stop();
+ }
+ }
+ m_previousLoop = m_currentLoop;
+ m_previousCurrentTime = m_currentTime;
+}
+
+void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ QAnimationGroupJob::updateState(newState, oldState);
+
+ switch (newState) {
+ case Stopped:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ animation->stop();
+ break;
+ case Paused:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ if (animation->isRunning())
+ animation->pause();
+ break;
+ case Running:
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ if (oldState == Stopped)
+ animation->stop();
+ resetUncontrolledAnimationFinishTime(animation);
+ animation->setDirection(m_direction);
+ if (shouldAnimationStart(animation, oldState == Stopped))
+ animation->start();
+ }
+ break;
+ }
+}
+
+bool QParallelAnimationGroupJob::shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const
+{
+ const int dura = animation->totalDuration();
+
+ if (dura == -1)
+ return uncontrolledAnimationFinishTime(animation) == -1;
+
+ if (startIfAtEnd)
+ return m_currentTime <= dura;
+ if (m_direction == Forward)
+ return m_currentTime < dura;
+ else //direction == Backward
+ return m_currentTime && m_currentTime <= dura;
+}
+
+void QParallelAnimationGroupJob::applyGroupState(QAbstractAnimationJob *animation)
+{
+ switch (m_state)
+ {
+ case Running:
+ animation->start();
+ break;
+ case Paused:
+ animation->pause();
+ break;
+ case Stopped:
+ default:
+ break;
+ }
+}
+
+void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ //we need to update the direction of the current animation
+ if (!isStopped()) {
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ animation->setDirection(direction);
+ }
+ } else {
+ if (direction == Forward) {
+ m_previousLoop = 0;
+ m_previousCurrentTime = 0;
+ } else {
+ // Looping backwards with loopCount == -1 does not really work well...
+ m_previousLoop = (m_loopCount == -1 ? 0 : m_loopCount - 1);
+ m_previousCurrentTime = duration();
+ }
+ }
+}
+
+void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
+ int uncontrolledRunningCount = 0;
+
+ for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ if (child == animation) {
+ setUncontrolledAnimationFinishTime(animation, animation->currentTime());
+ } else if (child->duration() == -1 || child->loopCount() < 0) {
+ if (uncontrolledAnimationFinishTime(child) == -1)
+ ++uncontrolledRunningCount;
+ }
+ }
+
+ if (uncontrolledRunningCount > 0)
+ return;
+
+ int maxDuration = 0;
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ maxDuration = qMax(maxDuration, animation->totalDuration());
+
+ if (m_currentTime >= maxDuration)
+ stop();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
new file mode 100644
index 0000000000..d77a8c84f9
--- /dev/null
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUPJOB_P_H
+#define QPARALLELANIMATIONGROUPJOB_P_H
+
+#include "private/qanimationgroupjob_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
+{
+ Q_DISABLE_COPY(QParallelAnimationGroupJob)
+public:
+ QParallelAnimationGroupJob();
+ ~QParallelAnimationGroupJob();
+
+ int duration() const;
+
+protected:
+ void updateCurrentTime(int currentTime);
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void updateDirection(QAbstractAnimationJob::Direction direction);
+ void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+
+private:
+ bool shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const;
+ void applyGroupState(QAbstractAnimationJob *animation);
+
+ //state
+ int m_previousLoop;
+ int m_previousCurrentTime;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPARALLELANIMATIONGROUPJOB_P_H
diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp
new file mode 100644
index 0000000000..40bcef7e89
--- /dev/null
+++ b/src/qml/animations/qpauseanimationjob.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qpauseanimationjob_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPauseAnimationJob::QPauseAnimationJob(int duration)
+ : QAbstractAnimationJob()
+ , m_duration(duration)
+{
+ m_isPause = true;
+}
+
+QPauseAnimationJob::~QPauseAnimationJob()
+{
+}
+
+int QPauseAnimationJob::duration() const
+{
+ return m_duration;
+}
+
+void QPauseAnimationJob::setDuration(int msecs)
+{
+ m_duration = msecs;
+}
+
+void QPauseAnimationJob::updateCurrentTime(int)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
new file mode 100644
index 0000000000..82462be101
--- /dev/null
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAUSEANIMATIONJOB_P_H
+#define QPAUSEANIMATIONJOB_P_H
+
+#include <private/qanimationgroupjob_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class Q_QML_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
+{
+ Q_DISABLE_COPY(QPauseAnimationJob)
+public:
+ explicit QPauseAnimationJob(int duration = 250);
+ ~QPauseAnimationJob();
+
+ int duration() const;
+ void setDuration(int msecs);
+
+protected:
+ void updateCurrentTime(int);
+
+private:
+ //definition
+ int m_duration;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPAUSEANIMATIONJOB_P_H
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
new file mode 100644
index 0000000000..12cce39fbc
--- /dev/null
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qsequentialanimationgroupjob_p.h"
+#include "private/qpauseanimationjob_p.h"
+#include "private/qanimationjobutil_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSequentialAnimationGroupJob::QSequentialAnimationGroupJob()
+ : QAnimationGroupJob()
+ , m_currentAnimation(0)
+ , m_previousLoop(0)
+{
+}
+
+QSequentialAnimationGroupJob::~QSequentialAnimationGroupJob()
+{
+}
+
+bool QSequentialAnimationGroupJob::atEnd() const
+{
+ // we try to detect if we're at the end of the group
+ //this is true if the following conditions are true:
+ // 1. we're in the last loop
+ // 2. the direction is forward
+ // 3. the current animation is the last one
+ // 4. the current animation has reached its end
+ const int animTotalCurrentTime = m_currentAnimation->currentTime();
+ return (m_currentLoop == m_loopCount - 1
+ && m_direction == Forward
+ && !m_currentAnimation->nextSibling()
+ && animTotalCurrentTime == animationActualTotalDuration(m_currentAnimation));
+}
+
+int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
+{
+ int ret = anim->totalDuration();
+ if (ret == -1)
+ ret = uncontrolledAnimationFinishTime(anim); //we can try the actual duration there
+ return ret;
+}
+
+QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::indexForCurrentTime() const
+{
+ Q_ASSERT(firstChild());
+
+ AnimationIndex ret;
+ QAbstractAnimationJob *anim = 0;
+ int duration = 0;
+
+ for (anim = firstChild(); anim; anim = anim->nextSibling()) {
+ duration = animationActualTotalDuration(anim);
+
+ // 'animation' is the current animation if one of these reasons is true:
+ // 1. it's duration is undefined
+ // 2. it ends after msecs
+ // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
+ // 4. it ends exactly in msecs and the direction is backwards
+ if (duration == -1 || m_currentTime < (ret.timeOffset + duration)
+ || (m_currentTime == (ret.timeOffset + duration) && m_direction == QAbstractAnimationJob::Backward)) {
+ ret.animation = anim;
+ return ret;
+ }
+
+ if (anim == m_currentAnimation)
+ ret.afterCurrent = true;
+
+ // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
+ ret.timeOffset += duration;
+ }
+
+ // this can only happen when one of those conditions is true:
+ // 1. the duration of the group is undefined and we passed its actual duration
+ // 2. there are only 0-duration animations in the group
+ ret.timeOffset -= duration;
+ ret.animation = lastChild();
+ return ret;
+}
+
+void QSequentialAnimationGroupJob::restart()
+{
+ // restarting the group by making the first/last animation the current one
+ if (m_direction == Forward) {
+ m_previousLoop = 0;
+ if (m_currentAnimation == firstChild())
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(firstChild());
+ }
+ else { // direction == Backward
+ m_previousLoop = m_loopCount - 1;
+ if (m_currentAnimation == lastChild())
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(lastChild());
+ }
+}
+
+void QSequentialAnimationGroupJob::advanceForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (m_previousLoop < m_currentLoop) {
+ // we need to fast forward to the end
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->nextSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
+ }
+ // this will make sure the current animation is reset to the beginning
+ if (firstChild() && !firstChild()->nextSibling()) //count == 1
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(firstChild(), true);
+ }
+
+ // and now we need to fast forward from the current position to
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->nextSibling()) { //### WRONG,
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
+ }
+ // setting the new current animation will happen later
+}
+
+void QSequentialAnimationGroupJob::rewindForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (m_previousLoop > m_currentLoop) {
+ // we need to fast rewind to the beginning
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->previousSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(0));
+ }
+ // this will make sure the current animation is reset to the end
+ if (lastChild() && !lastChild()->previousSibling()) //count == 1
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else {
+ setCurrentAnimation(lastChild(), true);
+ }
+ }
+
+ // and now we need to fast rewind from the current position to
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->previousSibling()) {
+ setCurrentAnimation(anim, true);
+ RETURN_IF_DELETED(anim->setCurrentTime(0));
+ }
+ // setting the new current animation will happen later
+}
+
+int QSequentialAnimationGroupJob::duration() const
+{
+ int ret = 0;
+
+ for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ const int currentDuration = anim->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret += currentDuration;
+ }
+
+ return ret;
+}
+
+void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
+{
+ if (!m_currentAnimation)
+ return;
+
+ const QSequentialAnimationGroupJob::AnimationIndex newAnimationIndex = indexForCurrentTime();
+
+ // newAnimationIndex.index is the new current animation
+ if (m_previousLoop < m_currentLoop
+ || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && newAnimationIndex.afterCurrent)) {
+ // advancing with forward direction is the same as rewinding with backwards direction
+ RETURN_IF_DELETED(advanceForwards(newAnimationIndex));
+ } else if (m_previousLoop > m_currentLoop
+ || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && !newAnimationIndex.afterCurrent)) {
+ // rewinding with forward direction is the same as advancing with backwards direction
+ RETURN_IF_DELETED(rewindForwards(newAnimationIndex));
+ }
+
+ setCurrentAnimation(newAnimationIndex.animation);
+
+ const int newCurrentTime = currentTime - newAnimationIndex.timeOffset;
+
+ if (m_currentAnimation) {
+ RETURN_IF_DELETED(m_currentAnimation->setCurrentTime(newCurrentTime));
+ if (atEnd()) {
+ //we make sure that we don't exceed the duration here
+ m_currentTime += m_currentAnimation->currentTime() - newCurrentTime;
+ stop();
+ }
+ } else {
+ //the only case where currentAnimation could be null
+ //is when all animations have been removed
+ Q_ASSERT(!firstChild());
+ m_currentTime = 0;
+ stop();
+ }
+
+ m_previousLoop = m_currentLoop;
+}
+
+void QSequentialAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState)
+{
+ QAnimationGroupJob::updateState(newState, oldState);
+
+ if (!m_currentAnimation)
+ return;
+
+ switch (newState) {
+ case Stopped:
+ m_currentAnimation->stop();
+ break;
+ case Paused:
+ if (oldState == m_currentAnimation->state() && oldState == Running)
+ m_currentAnimation->pause();
+ else
+ restart();
+ break;
+ case Running:
+ if (oldState == m_currentAnimation->state() && oldState == Paused)
+ m_currentAnimation->start();
+ else
+ restart();
+ break;
+ }
+}
+
+void QSequentialAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
+{
+ // we need to update the direction of the current animation
+ if (!isStopped() && m_currentAnimation)
+ m_currentAnimation->setDirection(direction);
+}
+
+void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate)
+{
+ if (!anim) {
+ Q_ASSERT(!firstChild());
+ m_currentAnimation = 0;
+ return;
+ }
+
+ if (anim == m_currentAnimation)
+ return;
+
+ // stop the old current animation
+ if (m_currentAnimation)
+ m_currentAnimation->stop();
+
+ m_currentAnimation = anim;
+
+ activateCurrentAnimation(intermediate);
+}
+
+void QSequentialAnimationGroupJob::activateCurrentAnimation(bool intermediate)
+{
+ if (!m_currentAnimation || isStopped())
+ return;
+
+ m_currentAnimation->stop();
+
+ // we ensure the direction is consistent with the group's direction
+ m_currentAnimation->setDirection(m_direction);
+
+ // reset the finish time of the animation if it is uncontrolled
+ if (m_currentAnimation->totalDuration() == -1)
+ resetUncontrolledAnimationFinishTime(m_currentAnimation);
+
+ m_currentAnimation->start();
+ if (!intermediate && isPaused())
+ m_currentAnimation->pause();
+}
+
+void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
+{
+ Q_UNUSED(animation);
+ Q_ASSERT(animation == m_currentAnimation);
+
+ setUncontrolledAnimationFinishTime(m_currentAnimation, m_currentAnimation->currentTime());
+
+ if ((m_direction == Forward && m_currentAnimation == lastChild())
+ || (m_direction == Backward && m_currentAnimation == firstChild())) {
+ // we don't handle looping of a group with undefined duration
+ stop();
+ } else if (m_direction == Forward) {
+ // set the current animation to be the next one
+ setCurrentAnimation(m_currentAnimation->nextSibling());
+ } else {
+ // set the current animation to be the previous one
+ setCurrentAnimation(m_currentAnimation->previousSibling());
+ }
+}
+
+void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
+{
+ if (m_currentAnimation == 0)
+ setCurrentAnimation(firstChild()); // initialize the current animation
+
+ if (m_currentAnimation == anim->nextSibling()
+ && m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
+ //in this case we simply insert the animation before the current one has actually started
+ setCurrentAnimation(anim);
+ }
+
+// TODO
+// if (index < m_currentAnimationIndex || m_currentLoop != 0) {
+// qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one.");
+// return; //we're not affected because it is added after the current one
+// }
+}
+
+void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim, QAbstractAnimationJob *prev, QAbstractAnimationJob *next)
+{
+ QAnimationGroupJob::animationRemoved(anim, prev, next);
+
+ Q_ASSERT(m_currentAnimation); // currentAnimation should always be set
+
+ bool removingCurrent = anim == m_currentAnimation;
+ if (removingCurrent) {
+ if (next)
+ setCurrentAnimation(next); //let's try to take the next one
+ else if (prev)
+ setCurrentAnimation(prev);
+ else// case all animations were removed
+ setCurrentAnimation(0);
+ }
+
+ // duration of the previous animations up to the current animation
+ m_currentTime = 0;
+ for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ if (anim == m_currentAnimation)
+ break;
+ m_currentTime += animationActualTotalDuration(anim);
+
+ }
+
+ if (!removingCurrent) {
+ //the current animation is not the one being removed
+ //so we add its current time to the current time of this group
+ m_currentTime += m_currentAnimation->currentTime();
+ }
+
+ //let's also update the total current time
+ m_totalCurrentTime = m_currentTime + m_loopCount * duration();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
new file mode 100644
index 0000000000..b406d04f6f
--- /dev/null
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUPJOB_P_H
+#define QSEQUENTIALANIMATIONGROUPJOB_P_H
+
+#include <private/qanimationgroupjob_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QPauseAnimationJob;
+class Q_QML_EXPORT QSequentialAnimationGroupJob : public QAnimationGroupJob
+{
+ Q_DISABLE_COPY(QSequentialAnimationGroupJob)
+public:
+ QSequentialAnimationGroupJob();
+ ~QSequentialAnimationGroupJob();
+
+ int duration() const;
+
+ QAbstractAnimationJob *currentAnimation() const { return m_currentAnimation; }
+
+protected:
+ void updateCurrentTime(int);
+ void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
+ void updateDirection(QAbstractAnimationJob::Direction direction);
+ void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
+
+private:
+ struct AnimationIndex
+ {
+ AnimationIndex() : afterCurrent(false), timeOffset(0), animation(0) {}
+ // AnimationIndex points to the animation at timeOffset, skipping 0 duration animations.
+ // Note that the index semantic is slightly different depending on the direction.
+ bool afterCurrent; //whether animation is before or after m_currentAnimation //TODO: make enum Before/After/Same
+ int timeOffset; // time offset when the animation at index starts.
+ QAbstractAnimationJob *animation; //points to the animation at timeOffset
+ };
+
+ int animationActualTotalDuration(QAbstractAnimationJob *anim) const;
+ AnimationIndex indexForCurrentTime() const;
+
+ void setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate = false);
+ void activateCurrentAnimation(bool intermediate = false);
+
+ void animationInserted(QAbstractAnimationJob *anim);
+ void animationRemoved(QAbstractAnimationJob *anim,QAbstractAnimationJob*,QAbstractAnimationJob*);
+
+ bool atEnd() const;
+
+ void restart();
+
+ // handle time changes
+ void rewindForwards(const AnimationIndex &newAnimationIndex);
+ void advanceForwards(const AnimationIndex &newAnimationIndex);
+
+ //state
+ QAbstractAnimationJob *m_currentAnimation;
+ int m_previousLoop;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QSEQUENTIALANIMATIONGROUPJOB_P_H
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
new file mode 100644
index 0000000000..10ca9706c4
--- /dev/null
+++ b/src/qml/debugger/debugger.pri
@@ -0,0 +1,32 @@
+SOURCES += \
+ $$PWD/qpacketprotocol.cpp \
+ $$PWD/qqmldebugservice.cpp \
+ $$PWD/qqmldebugclient.cpp \
+ $$PWD/qqmlenginedebug.cpp \
+ $$PWD/qqmlprofilerservice.cpp \
+ $$PWD/qqmldebughelper.cpp \
+ $$PWD/qqmldebugserver.cpp \
+ $$PWD/qqmlinspectorservice.cpp \
+ $$PWD/qv8debugservice.cpp \
+ $$PWD/qv8profilerservice.cpp \
+ $$PWD/qqmlenginedebugservice.cpp \
+ $$PWD/qdebugmessageservice.cpp
+
+HEADERS += \
+ $$PWD/qpacketprotocol_p.h \
+ $$PWD/qqmldebugservice_p.h \
+ $$PWD/qqmldebugservice_p_p.h \
+ $$PWD/qqmldebugclient_p.h \
+ $$PWD/qqmlenginedebug_p.h \
+ $$PWD/qqmlprofilerservice_p.h \
+ $$PWD/qqmldebughelper_p.h \
+ $$PWD/qqmldebugserver_p.h \
+ $$PWD/qqmldebugserverconnection_p.h \
+ $$PWD/qqmldebugstatesdelegate_p.h \
+ $$PWD/qqmlinspectorservice_p.h \
+ $$PWD/qqmlinspectorinterface_p.h \
+ $$PWD/qv8debugservice_p.h \
+ $$PWD/qv8profilerservice_p.h \
+ $$PWD/qqmlenginedebugservice_p.h \
+ $$PWD/qqmldebug.h \
+ $$PWD/qdebugmessageservice_p.h
diff --git a/src/qml/debugger/qdebugmessageservice.cpp b/src/qml/debugger/qdebugmessageservice.cpp
new file mode 100644
index 0000000000..2c52809e56
--- /dev/null
+++ b/src/qml/debugger/qdebugmessageservice.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdebugmessageservice_p.h"
+#include "qqmldebugservice_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDebugMessageService, qmlDebugMessageService)
+
+void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt,
+ const char *buf)
+{
+ QDebugMessageService::instance()->sendDebugMessage(type, ctxt, buf);
+}
+
+class QDebugMessageServicePrivate : public QQmlDebugServicePrivate
+{
+public:
+ QDebugMessageServicePrivate()
+ : oldMsgHandler(0)
+ , prevState(QQmlDebugService::NotConnected)
+ {
+ }
+
+ QMessageHandler oldMsgHandler;
+ QQmlDebugService::State prevState;
+};
+
+QDebugMessageService::QDebugMessageService(QObject *parent) :
+ QQmlDebugService(*(new QDebugMessageServicePrivate()),
+ QLatin1String("DebugMessages"), 2, parent)
+{
+ Q_D(QDebugMessageService);
+
+ registerService();
+ if (state() == Enabled) {
+ d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
+ d->prevState = Enabled;
+ }
+}
+
+QDebugMessageService *QDebugMessageService::instance()
+{
+ return qmlDebugMessageService();
+}
+
+void QDebugMessageService::sendDebugMessage(QtMsgType type,
+ const QMessageLogContext &ctxt,
+ const char *buf)
+{
+ Q_D(QDebugMessageService);
+
+ //We do not want to alter the message handling mechanism
+ //We just eavesdrop and forward the messages to a port
+ //only if a client is connected to it.
+ QByteArray message;
+ QDataStream ws(&message, QIODevice::WriteOnly);
+ ws << QByteArray("MESSAGE") << type << QString::fromLocal8Bit(buf).toUtf8();
+ ws << QString::fromLatin1(ctxt.file).toUtf8();
+ ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8();
+
+ sendMessage(message);
+ if (d->oldMsgHandler)
+ (*d->oldMsgHandler)(type, ctxt, buf);
+}
+
+void QDebugMessageService::stateChanged(State state)
+{
+ Q_D(QDebugMessageService);
+
+ if (state != Enabled && d->prevState == Enabled) {
+ QMessageHandler handler = qInstallMessageHandler(d->oldMsgHandler);
+ // has our handler been overwritten in between?
+ if (handler != DebugMessageHandler)
+ qInstallMessageHandler(handler);
+
+ } else if (state == Enabled && d->prevState != Enabled) {
+ d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
+
+ }
+
+ d->prevState = state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qdebugmessageservice_p.h b/src/qml/debugger/qdebugmessageservice_p.h
new file mode 100644
index 0000000000..88b918e217
--- /dev/null
+++ b/src/qml/debugger/qdebugmessageservice_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDEBUGMESSAGESERVICE_P_H
+#define QDEBUGMESSAGESERVICE_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 "qqmldebugservice_p.h"
+
+#include <QtCore/qlogging.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qml)
+
+class QDebugMessageServicePrivate;
+
+class QDebugMessageService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QDebugMessageService(QObject *parent = 0);
+
+ static QDebugMessageService *instance();
+
+ void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt,
+ const char *buf);
+
+protected:
+ void stateChanged(State);
+
+private:
+ Q_DISABLE_COPY(QDebugMessageService)
+ Q_DECLARE_PRIVATE(QDebugMessageService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDEBUGMESSAGESERVICE_P_H
diff --git a/src/qml/debugger/qpacketprotocol.cpp b/src/qml/debugger/qpacketprotocol.cpp
new file mode 100644
index 0000000000..978054a238
--- /dev/null
+++ b/src/qml/debugger/qpacketprotocol.cpp
@@ -0,0 +1,550 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QElapsedTimer>
+
+QT_BEGIN_NAMESPACE
+
+static const unsigned int 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),
+ waitingForPacket(false), 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()));
+ 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()
+ {
+ while (true) {
+ // Need to get trailing data
+ 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);
+ } else {
+ inProgress.append(dev->read(inProgressSize - inProgress.size()));
+
+ if (inProgressSize == inProgress.size()) {
+ // Packet has arrived!
+ packets.append(inProgress);
+ inProgressSize = -1;
+ inProgress.clear();
+
+ waitingForPacket = false;
+ emit readyRead();
+ } else
+ return;
+ }
+ }
+ }
+
+public:
+ QList<qint64> sendingPackets;
+ QList<QByteArray> packets;
+ QByteArray inProgress;
+ qint32 inProgressSize;
+ qint32 maxPacketSize;
+ bool waitingForPacket;
+ 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;
+}
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/*!
+ This function locks until a new packet is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+ */
+
+bool QPacketProtocol::waitForReadyRead(int msecs)
+{
+ if (!d->packets.isEmpty())
+ return true;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ d->waitingForPacket = true;
+ do {
+ if (!d->dev->waitForReadyRead(msecs))
+ return false;
+ if (!d->waitingForPacket)
+ return true;
+ msecs = qt_timeout_value(msecs, stopWatch.elapsed());
+ } while (true);
+}
+
+/*!
+ Return the QIODevice passed to the QPacketProtocol constructor.
+*/
+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/qml/debugger/qpacketprotocol_p.h b/src/qml/debugger/qpacketprotocol_p.h
new file mode 100644
index 0000000000..c6123d2836
--- /dev/null
+++ b/src/qml/debugger/qpacketprotocol_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPACKETPROTOCOL_H
+#define QPACKETPROTOCOL_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/qdatastream.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QIODevice;
+class QBuffer;
+class QPacket;
+class QPacketAutoSend;
+class QPacketProtocolPrivate;
+
+class Q_QML_PRIVATE_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();
+
+ bool waitForReadyRead(int msecs = 3000);
+
+ void clear();
+
+ QIODevice *device();
+
+Q_SIGNALS:
+ void readyRead();
+ void invalidPacket();
+ void packetWritten();
+
+private:
+ QPacketProtocolPrivate *d;
+};
+
+
+class Q_QML_PRIVATE_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_QML_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/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
new file mode 100644
index 0000000000..8036032150
--- /dev/null
+++ b/src/qml/debugger/qqmldebug.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUG_H
+#define QQMLDEBUG_H
+
+#include <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+struct Q_QML_EXPORT QQmlDebuggingEnabler
+{
+ QQmlDebuggingEnabler();
+};
+
+// Execute code in constructor before first QQmlEngine is instantiated
+#if defined(QT_DECLARATIVE_DEBUG)
+static QQmlDebuggingEnabler qmlEnableDebuggingHelper;
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUG_H
diff --git a/src/qml/debugger/qqmldebugclient.cpp b/src/qml/debugger/qqmldebugclient.cpp
new file mode 100644
index 0000000000..12276b48fa
--- /dev/null
+++ b/src/qml/debugger/qqmldebugclient.cpp
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugclient_p.h"
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtNetwork/qnetworkproxy.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+const int protocolVersion = 1;
+const QString serverId = QLatin1String("QQmlDebugServer");
+const QString clientId = QLatin1String("QQmlDebugClient");
+
+class QQmlDebugClientPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugClient)
+public:
+ QQmlDebugClientPrivate();
+
+ QString name;
+ QQmlDebugConnection *connection;
+};
+
+class QQmlDebugConnectionPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDebugConnectionPrivate(QQmlDebugConnection *c);
+ QQmlDebugConnection *q;
+ QPacketProtocol *protocol;
+ QIODevice *device;
+
+ bool gotHello;
+ QHash <QString, float> serverPlugins;
+ QHash<QString, QQmlDebugClient *> plugins;
+
+ void advertisePlugins();
+ void connectDeviceSignals();
+
+public Q_SLOTS:
+ void connected();
+ void readyRead();
+ void deviceAboutToClose();
+};
+
+QQmlDebugConnectionPrivate::QQmlDebugConnectionPrivate(QQmlDebugConnection *c)
+ : QObject(c), q(c), protocol(0), device(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 QQmlDebugConnectionPrivate::advertisePlugins()
+{
+ if (!q->isConnected())
+ return;
+
+ QPacket pack;
+ pack << serverId << 1 << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QQmlDebugConnectionPrivate::connected()
+{
+ QPacket pack;
+ pack << serverId << 0 << protocolVersion << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QQmlDebugConnectionPrivate::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) {
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.isEmpty())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ validHello = true;
+ }
+ }
+ }
+
+ if (!validHello) {
+ qWarning("QQmlDebugConnection: Invalid hello message");
+ QObject::disconnect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ return;
+ }
+ gotHello = true;
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ QQmlDebugClient::State newState = QQmlDebugClient::Unavailable;
+ if (serverPlugins.contains(iter.key()))
+ newState = QQmlDebugClient::Enabled;
+ iter.value()->stateChanged(newState);
+ }
+ }
+
+ while (protocol->packetsAvailable()) {
+ QPacket pack = protocol->read();
+ QString name;
+ pack >> name;
+
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QHash<QString, float> oldServerPlugins = serverPlugins;
+ serverPlugins.clear();
+
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.isEmpty())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QQmlDebugClient::State newSate = QQmlDebugClient::Unavailable;
+ if (serverPlugins.contains(pluginName))
+ newSate = QQmlDebugClient::Enabled;
+
+ if (oldServerPlugins.contains(pluginName)
+ != serverPlugins.contains(pluginName)) {
+ iter.value()->stateChanged(newSate);
+ }
+ }
+ } else {
+ qWarning() << "QQmlDebugConnection: Unknown control message id" << op;
+ }
+ } else {
+ QByteArray message;
+ pack >> message;
+
+ QHash<QString, QQmlDebugClient *>::Iterator iter =
+ plugins.find(name);
+ if (iter == plugins.end()) {
+ qWarning() << "QQmlDebugConnection: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+void QQmlDebugConnectionPrivate::deviceAboutToClose()
+{
+ // This is nasty syntax but we want to emit our own aboutToClose signal (by calling QIODevice::close())
+ // without calling the underlying device close fn as that would cause an infinite loop
+ q->QIODevice::close();
+}
+
+QQmlDebugConnection::QQmlDebugConnection(QObject *parent)
+ : QIODevice(parent), d(new QQmlDebugConnectionPrivate(this))
+{
+}
+
+QQmlDebugConnection::~QQmlDebugConnection()
+{
+ QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->d_func()->connection = 0;
+ iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ }
+}
+
+bool QQmlDebugConnection::isConnected() const
+{
+ return state() == QAbstractSocket::ConnectedState;
+}
+
+qint64 QQmlDebugConnection::readData(char *data, qint64 maxSize)
+{
+ return d->device->read(data, maxSize);
+}
+
+qint64 QQmlDebugConnection::writeData(const char *data, qint64 maxSize)
+{
+ return d->device->write(data, maxSize);
+}
+
+qint64 QQmlDebugConnection::bytesAvailable() const
+{
+ return d->device->bytesAvailable();
+}
+
+bool QQmlDebugConnection::isSequential() const
+{
+ return true;
+}
+
+void QQmlDebugConnection::close()
+{
+ if (isOpen()) {
+ QIODevice::close();
+ d->device->close();
+ emit stateChanged(QAbstractSocket::UnconnectedState);
+
+ QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ }
+ }
+}
+
+bool QQmlDebugConnection::waitForConnected(int msecs)
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket)
+ return socket->waitForConnected(msecs);
+ return false;
+}
+
+QAbstractSocket::SocketState QQmlDebugConnection::state() const
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket)
+ return socket->state();
+
+ return QAbstractSocket::UnconnectedState;
+}
+
+void QQmlDebugConnection::flush()
+{
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
+ if (socket) {
+ socket->flush();
+ return;
+ }
+}
+
+void QQmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
+{
+ QTcpSocket *socket = new QTcpSocket(d);
+ socket->setProxy(QNetworkProxy::NoProxy);
+ d->device = socket;
+ d->connectDeviceSignals();
+ d->gotHello = false;
+ connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)));
+ connect(socket, SIGNAL(connected()), this, SIGNAL(connected()));
+ socket->connectToHost(hostName, port);
+ QIODevice::open(ReadWrite | Unbuffered);
+}
+
+void QQmlDebugConnectionPrivate::connectDeviceSignals()
+{
+ connect(device, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
+ connect(device, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
+ connect(device, SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose()));
+}
+
+//
+
+QQmlDebugClientPrivate::QQmlDebugClientPrivate()
+ : connection(0)
+{
+}
+
+QQmlDebugClient::QQmlDebugClient(const QString &name,
+ QQmlDebugConnection *parent)
+ : QObject(*(new QQmlDebugClientPrivate), parent)
+{
+ Q_D(QQmlDebugClient);
+ d->name = name;
+ d->connection = parent;
+
+ if (!d->connection)
+ return;
+
+ if (d->connection->d->plugins.contains(name)) {
+ qWarning() << "QQmlDebugClient: Conflicting plugin name" << name;
+ d->connection = 0;
+ } else {
+ d->connection->d->plugins.insert(name, this);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QQmlDebugClient::~QQmlDebugClient()
+{
+ Q_D(QQmlDebugClient);
+ if (d->connection && d->connection->d) {
+ d->connection->d->plugins.remove(d->name);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QString QQmlDebugClient::name() const
+{
+ Q_D(const QQmlDebugClient);
+ return d->name;
+}
+
+float QQmlDebugClient::serviceVersion() const
+{
+ Q_D(const QQmlDebugClient);
+ if (d->connection->d->serverPlugins.contains(d->name))
+ return d->connection->d->serverPlugins.value(d->name);
+ return -1;
+}
+
+QQmlDebugClient::State QQmlDebugClient::state() const
+{
+ Q_D(const QQmlDebugClient);
+ 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 QQmlDebugClient::sendMessage(const QByteArray &message)
+{
+ Q_D(QQmlDebugClient);
+ if (state() != Enabled)
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->connection->d->protocol->send(pack);
+ d->connection->flush();
+}
+
+void QQmlDebugClient::stateChanged(State)
+{
+}
+
+void QQmlDebugClient::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qqmldebugclient.moc>
diff --git a/src/qml/debugger/qqmldebugclient_p.h b/src/qml/debugger/qqmldebugclient_p.h
new file mode 100644
index 0000000000..064e15cf49
--- /dev/null
+++ b/src/qml/debugger/qqmldebugclient_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGCLIENT_H
+#define QQMLDEBUGCLIENT_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 <QtNetwork/qtcpsocket.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugConnectionPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugConnection : public QIODevice
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QQmlDebugConnection)
+public:
+ QQmlDebugConnection(QObject * = 0);
+ ~QQmlDebugConnection();
+
+ void connectToHost(const QString &hostName, quint16 port);
+
+ qint64 bytesAvailable() const;
+ bool isConnected() const;
+ QAbstractSocket::SocketState state() const;
+ void flush();
+ bool isSequential() const;
+ void close();
+ bool waitForConnected(int msecs = 30000);
+
+signals:
+ void connected();
+ void stateChanged(QAbstractSocket::SocketState socketState);
+ void error(QAbstractSocket::SocketError socketError);
+
+protected:
+ qint64 readData(char *data, qint64 maxSize);
+ qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+ QQmlDebugConnectionPrivate *d;
+ friend class QQmlDebugClient;
+ friend class QQmlDebugClientPrivate;
+};
+
+class QQmlDebugClientPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugClient : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugClient)
+ Q_DISABLE_COPY(QQmlDebugClient)
+
+public:
+ enum State { NotConnected, Unavailable, Enabled };
+
+ QQmlDebugClient(const QString &, QQmlDebugConnection *parent);
+ ~QQmlDebugClient();
+
+ QString name() const;
+ float serviceVersion() const;
+ State state() const;
+
+ virtual void sendMessage(const QByteArray &);
+
+protected:
+ virtual void stateChanged(State);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QQmlDebugConnection;
+ friend class QQmlDebugConnectionPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGCLIENT_H
diff --git a/src/qml/debugger/qqmldebughelper.cpp b/src/qml/debugger/qqmldebughelper.cpp
new file mode 100644
index 0000000000..7158b3609d
--- /dev/null
+++ b/src/qml/debugger/qqmldebughelper.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebughelper_p.h"
+
+#include <QtCore/QAbstractAnimation>
+#include <QtQml/QJSEngine>
+
+#include <private/qqmlengine_p.h>
+#include <private/qabstractanimation_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQmlDebugHelper::setAnimationSlowDownFactor(qreal factor)
+{
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setSlowModeEnabled(factor != 1.0);
+ timer->setSlowdownFactor(factor);
+}
+
+void QQmlDebugHelper::enableDebugging() {
+ qWarning("QQmlDebugHelper::enableDebugging() is deprecated! Add CONFIG += declarative_debug to your .pro file instead.");
+#ifndef QQML_NO_DEBUG_PROTOCOL
+ if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning("Qml debugging is enabled. Only use this in a safe environment!");
+ }
+ QQmlEnginePrivate::qml_debugging_enabled = true;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebughelper_p.h b/src/qml/debugger/qqmldebughelper_p.h
new file mode 100644
index 0000000000..5d2bcc2be0
--- /dev/null
+++ b/src/qml/debugger/qqmldebughelper_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGHELPER_P_H
+#define QQMLDEBUGHELPER_P_H
+
+#include <private/qtqmlglobal_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_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+
+#ifndef QT_BUILD_QML_LIB
+#warning Use of this header file is deprecated! Add CONFIG += declarative_debug to your .pro file instead.
+#endif
+
+// Helper methods to access private API through a stable interface
+// This is used in the qmljsdebugger library of QtCreator.
+class Q_QML_EXPORT QQmlDebugHelper
+{
+public:
+ 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 // QQMLDEBUGHELPER_P_H
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
new file mode 100644
index 0000000000..8d5c597a78
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugserver_p.h"
+#include "qqmldebugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QStringList>
+#include <QtCore/qwaitcondition.h>
+
+#include <private/qobject_p.h>
+#include <private/qcoreapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QQmlDebug Protocol (Version 1):
+
+ handshake:
+ 1. Client sends
+ "QQmlDebugServer" 0 version pluginNames
+ version: an int representing the highest protocol version the client knows
+ pluginNames: plugins available on client side
+ 2. Server sends
+ "QQmlDebugClient" 0 version pluginNames pluginVersions
+ 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
+ "QQmlDebugServer" 1 pluginNames
+ server plugin advertisement
+ 1. Server sends
+ "QQmlDebugClient" 1 pluginNames pluginVersions
+ plugin communication:
+ Everything send with a header different to "QQmlDebugServer" is sent to the appropriate plugin.
+ */
+
+const int protocolVersion = 1;
+
+// print detailed information about loading of plugins
+DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE)
+
+class QQmlDebugServerThread;
+
+class QQmlDebugServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugServer)
+public:
+ QQmlDebugServerPrivate();
+
+ void advertisePlugins();
+ QQmlDebugServerConnection *loadConnectionPlugin(const QString &pluginName);
+
+ QQmlDebugServerConnection *connection;
+ QHash<QString, QQmlDebugService *> plugins;
+ mutable QReadWriteLock pluginsLock;
+ QStringList clientPlugins;
+ bool gotHello;
+
+ QMutex messageArrivedMutex;
+ QWaitCondition messageArrivedCondition;
+ QStringList waitingForMessageNames;
+ QQmlDebugServerThread *thread;
+ QPluginLoader loader;
+
+private:
+ // private slot
+ void _q_sendMessages(const QList<QByteArray> &messages);
+};
+
+class QQmlDebugServerThread : public QThread
+{
+public:
+ void setPluginName(const QString &pluginName) {
+ m_pluginName = pluginName;
+ }
+
+ void setPort(int port, bool block) {
+ m_port = port;
+ m_block = block;
+ }
+
+ void run();
+
+private:
+ QString m_pluginName;
+ int m_port;
+ bool m_block;
+};
+
+QQmlDebugServerPrivate::QQmlDebugServerPrivate() :
+ connection(0),
+ gotHello(false),
+ thread(0)
+{
+ // used in _q_sendMessages
+ qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
+}
+
+void QQmlDebugServerPrivate::advertisePlugins()
+{
+ Q_Q(QQmlDebugServer);
+
+ if (!gotHello)
+ return;
+
+ QByteArray message;
+ {
+ QDataStream out(&message, QIODevice::WriteOnly);
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ foreach (QQmlDebugService *service, plugins.values()) {
+ pluginNames << service->name();
+ pluginVersions << service->version();
+ }
+ out << QString(QLatin1String("QQmlDebugClient")) << 1 << pluginNames << pluginVersions;
+ }
+
+ QMetaObject::invokeMethod(q, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, QList<QByteArray>() << message));
+}
+
+QQmlDebugServerConnection *QQmlDebugServerPrivate::loadConnectionPlugin(
+ const QString &pluginName)
+{
+#ifndef QT_NO_LIBRARY
+ 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) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Trying to load plugin " << pluginPath << "...";
+
+ loader.setFileName(pluginPath);
+ if (!loader.load()) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Error while loading: " << loader.errorString();
+ continue;
+ }
+ if (QObject *instance = loader.instance())
+ connection = qobject_cast<QQmlDebugServerConnection*>(instance);
+
+ if (connection) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Plugin successfully loaded.";
+
+ return connection;
+ }
+
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlDebugServer: Plugin does not implement interface QQmlDebugServerConnection.";
+
+ loader.unload();
+ }
+#endif
+ return 0;
+}
+
+void QQmlDebugServerThread::run()
+{
+ QQmlDebugServer *server = QQmlDebugServer::instance();
+ QQmlDebugServerConnection *connection
+ = server->d_func()->loadConnectionPlugin(m_pluginName);
+ if (connection) {
+ connection->setServer(QQmlDebugServer::instance());
+ connection->setPort(m_port, m_block);
+ } else {
+ QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+ qWarning() << QString::fromAscii("QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString());
+ }
+
+ exec();
+
+ // make sure events still waiting are processed
+ QEventLoop eventLoop;
+ eventLoop.processEvents(QEventLoop::AllEvents);
+}
+
+bool QQmlDebugServer::hasDebuggingClient() const
+{
+ Q_D(const QQmlDebugServer);
+ return d->connection
+ && d->connection->isConnected()
+ && d->gotHello;
+}
+
+static QQmlDebugServer *qQmlDebugServer = 0;
+
+
+static void cleanup()
+{
+ delete qQmlDebugServer;
+ qQmlDebugServer = 0;
+}
+
+QQmlDebugServer *QQmlDebugServer::instance()
+{
+ static bool commandLineTested = false;
+
+ if (!commandLineTested) {
+ commandLineTested = true;
+
+ QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
+#ifndef QQML_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 (!QQmlEnginePrivate::qml_debugging_enabled) {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Debugging has not been enabled.").arg(
+ appD->qmljsDebugArgumentsString());
+ 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(QLatin1String("ost"))) {
+ pluginName = QLatin1String("qmldbg_ost");
+ ok = true;
+ }
+
+ block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
+
+ if (ok) {
+ qQmlDebugServer = new QQmlDebugServer();
+ QQmlDebugServerThread *thread = new QQmlDebugServerThread;
+ qQmlDebugServer->d_func()->thread = thread;
+ qQmlDebugServer->moveToThread(thread);
+ thread->setPluginName(pluginName);
+ thread->setPort(port, block);
+ thread->start();
+
+ if (block) {
+ QQmlDebugServerPrivate *d = qQmlDebugServer->d_func();
+ d->messageArrivedMutex.lock();
+ d->messageArrivedCondition.wait(&d->messageArrivedMutex);
+ d->messageArrivedMutex.unlock();
+ }
+
+ } else {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Format is -qmljsdebugger=port:<port>[,block]").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+ }
+#else
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ qWarning() << QString::fromLatin1(
+ "QQmlDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "QtQml is not configured for debugging.").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+#endif
+ }
+
+ return qQmlDebugServer;
+}
+
+QQmlDebugServer::QQmlDebugServer()
+ : QObject(*(new QQmlDebugServerPrivate))
+{
+ qAddPostRoutine(cleanup);
+}
+
+QQmlDebugServer::~QQmlDebugServer()
+{
+ Q_D(QQmlDebugServer);
+
+ QReadLocker(&d->pluginsLock);
+ {
+ foreach (QQmlDebugService *service, d->plugins.values()) {
+ service->stateAboutToBeChanged(QQmlDebugService::NotConnected);
+ service->d_func()->server = 0;
+ service->d_func()->state = QQmlDebugService::NotConnected;
+ service->stateChanged(QQmlDebugService::NotConnected);
+ }
+ }
+
+ if (d->thread) {
+ d->thread->exit();
+ d->thread->wait();
+ delete d->thread;
+ }
+ delete d->connection;
+}
+
+void QQmlDebugServer::receiveMessage(const QByteArray &message)
+{
+ Q_D(QQmlDebugServer);
+
+ QDataStream in(message);
+
+ QString name;
+
+ in >> name;
+ if (name == QLatin1String("QQmlDebugServer")) {
+ int op = -1;
+ in >> op;
+ if (op == 0) {
+ int version;
+ in >> version >> d->clientPlugins;
+
+ // Send the hello answer immediately, since it needs to arrive before
+ // the plugins below start sending messages.
+ QByteArray helloAnswer;
+ {
+ QDataStream out(&helloAnswer, QIODevice::WriteOnly);
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ foreach (QQmlDebugService *service, d->plugins.values()) {
+ pluginNames << service->name();
+ pluginVersions << service->version();
+ }
+
+ out << QString(QLatin1String("QQmlDebugClient")) << 0 << protocolVersion << pluginNames << pluginVersions;
+ }
+ d->connection->send(QList<QByteArray>() << helloAnswer);
+
+ d->gotHello = true;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
+ for (; iter != d->plugins.constEnd(); ++iter) {
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(iter.key()))
+ newState = QQmlDebugService::Enabled;
+ iter.value()->d_func()->state = newState;
+ iter.value()->stateChanged(newState);
+ }
+
+ qWarning("QQmlDebugServer: Connection established");
+ d->messageArrivedCondition.wakeAll();
+
+ } else if (op == 1) {
+
+ // Service Discovery
+ QStringList oldClientPlugins = d->clientPlugins;
+ in >> d->clientPlugins;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService*>::ConstIterator iter = d->plugins.constBegin();
+ for (; iter != d->plugins.constEnd(); ++iter) {
+ const QString pluginName = iter.key();
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(pluginName))
+ newState = QQmlDebugService::Enabled;
+
+ if (oldClientPlugins.contains(pluginName)
+ != d->clientPlugins.contains(pluginName)) {
+ iter.value()->d_func()->state = newState;
+ iter.value()->stateChanged(newState);
+ }
+ }
+
+ } else {
+ qWarning("QQmlDebugServer: Invalid control message %d", op);
+ d->connection->disconnect();
+ return;
+ }
+
+ } else {
+ if (d->gotHello) {
+ QByteArray message;
+ in >> message;
+
+ QReadLocker(&d->pluginsLock);
+ QHash<QString, QQmlDebugService *>::Iterator iter = d->plugins.find(name);
+ if (iter == d->plugins.end()) {
+ qWarning() << "QQmlDebugServer: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+
+ if (d->waitingForMessageNames.removeOne(name))
+ d->messageArrivedCondition.wakeAll();
+ }
+ } else {
+ qWarning("QQmlDebugServer: Invalid hello message");
+ }
+
+ }
+}
+
+void QQmlDebugServerPrivate::_q_sendMessages(const QList<QByteArray> &messages)
+{
+ if (connection)
+ connection->send(messages);
+}
+
+QList<QQmlDebugService*> QQmlDebugServer::services() const
+{
+ const Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+ return d->plugins.values();
+}
+
+QStringList QQmlDebugServer::serviceNames() const
+{
+ const Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+ return d->plugins.keys();
+}
+
+bool QQmlDebugServer::addService(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ {
+ QWriteLocker(&d->pluginsLock);
+ if (!service || d->plugins.contains(service->name()))
+ return false;
+ d->plugins.insert(service->name(), service);
+ }
+ {
+ QReadLocker(&d->pluginsLock);
+ d->advertisePlugins();
+ QQmlDebugService::State newState = QQmlDebugService::Unavailable;
+ if (d->clientPlugins.contains(service->name()))
+ newState = QQmlDebugService::Enabled;
+ service->d_func()->state = newState;
+ }
+ return true;
+}
+
+bool QQmlDebugServer::removeService(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ {
+ QWriteLocker(&d->pluginsLock);
+ if (!service || !d->plugins.contains(service->name()))
+ return false;
+ d->plugins.remove(service->name());
+ }
+ {
+ QReadLocker(&d->pluginsLock);
+ QQmlDebugService::State newState = QQmlDebugService::NotConnected;
+ service->stateAboutToBeChanged(newState);
+ d->advertisePlugins();
+ service->d_func()->server = 0;
+ service->d_func()->state = newState;
+ service->stateChanged(newState);
+ }
+
+ return true;
+}
+
+void QQmlDebugServer::sendMessages(QQmlDebugService *service,
+ const QList<QByteArray> &messages)
+{
+ QList<QByteArray> prefixedMessages;
+ foreach (const QByteArray &message, messages) {
+ QByteArray prefixed;
+ QDataStream out(&prefixed, QIODevice::WriteOnly);
+ out << service->name() << message;
+ prefixedMessages << prefixed;
+ }
+
+ QMetaObject::invokeMethod(this, "_q_sendMessages", Qt::QueuedConnection, Q_ARG(QList<QByteArray>, prefixedMessages));
+}
+
+bool QQmlDebugServer::waitForMessage(QQmlDebugService *service)
+{
+ Q_D(QQmlDebugServer);
+ QReadLocker(&d->pluginsLock);
+
+ if (!service
+ || !d->plugins.contains(service->name()))
+ return false;
+
+ d->messageArrivedMutex.lock();
+ d->waitingForMessageNames << service->name();
+ do {
+ d->messageArrivedCondition.wait(&d->messageArrivedMutex);
+ } while (d->waitingForMessageNames.contains(service->name()));
+ d->messageArrivedMutex.unlock();
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserver_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
new file mode 100644
index 0000000000..9c6b5435c8
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVER_H
+#define QQMLDEBUGSERVER_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <private/qqmldebugserverconnection_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_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugService;
+
+class QQmlDebugServerPrivate;
+class Q_QML_EXPORT QQmlDebugServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugServer)
+ Q_DISABLE_COPY(QQmlDebugServer)
+public:
+ ~QQmlDebugServer();
+
+ static QQmlDebugServer *instance();
+
+ void setConnection(QQmlDebugServerConnection *connection);
+
+ bool hasDebuggingClient() const;
+
+ QList<QQmlDebugService*> services() const;
+ QStringList serviceNames() const;
+
+
+ bool addService(QQmlDebugService *service);
+ bool removeService(QQmlDebugService *service);
+
+ void receiveMessage(const QByteArray &message);
+
+ bool waitForMessage(QQmlDebugService *service);
+ void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages);
+
+private:
+ friend class QQmlDebugService;
+ friend class QQmlDebugServicePrivate;
+ friend class QQmlDebugServerThread;
+ QQmlDebugServer();
+ Q_PRIVATE_SLOT(d_func(), void _q_sendMessages(QList<QByteArray>))
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_H
diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h
new file mode 100644
index 0000000000..c9092f1911
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserverconnection_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVERCONNECTION_H
+#define QQMLDEBUGSERVERCONNECTION_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QtPlugin>
+
+//
+// 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_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServer;
+class Q_QML_EXPORT QQmlDebugServerConnection
+{
+public:
+ QQmlDebugServerConnection() {}
+ virtual ~QQmlDebugServerConnection() {}
+
+ virtual void setServer(QQmlDebugServer *server) = 0;
+ virtual void setPort(int port, bool bock) = 0;
+ virtual bool isConnected() const = 0;
+ virtual void send(const QList<QByteArray> &messages) = 0;
+ virtual void disconnect() = 0;
+ virtual bool waitForMessage() = 0;
+};
+
+Q_DECLARE_INTERFACE(QQmlDebugServerConnection, "com.trolltech.Qt.QQmlDebugServerConnection/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVERCONNECTION_H
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
new file mode 100644
index 0000000000..9eb9489566
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include "qqmldebugserver_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServicePrivate::QQmlDebugServicePrivate()
+ : server(0)
+{
+}
+
+QQmlDebugService::QQmlDebugService(const QString &name, float version, QObject *parent)
+ : QObject(*(new QQmlDebugServicePrivate), parent)
+{
+ Q_D(QQmlDebugService);
+ d->name = name;
+ d->version = version;
+ d->server = QQmlDebugServer::instance();
+ d->state = QQmlDebugService::NotConnected;
+
+
+}
+
+QQmlDebugService::QQmlDebugService(QQmlDebugServicePrivate &dd,
+ const QString &name, float version, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QQmlDebugService);
+ d->name = name;
+ d->version = version;
+ d->server = QQmlDebugServer::instance();
+ d->state = QQmlDebugService::NotConnected;
+}
+
+/**
+ Registers the service. This should be called in the constructor of the inherited class. From
+ then on the service might get asynchronous calls to messageReceived().
+ */
+QQmlDebugService::State QQmlDebugService::registerService()
+{
+ Q_D(QQmlDebugService);
+ if (!d->server)
+ return NotConnected;
+
+ if (d->server->serviceNames().contains(d->name)) {
+ qWarning() << "QQmlDebugService: Conflicting plugin name" << d->name;
+ d->server = 0;
+ } else {
+ d->server->addService(this);
+ }
+ return state();
+}
+
+QQmlDebugService::~QQmlDebugService()
+{
+ Q_D(const QQmlDebugService);
+ if (d->server) {
+ d->server->removeService(this);
+ }
+}
+
+QString QQmlDebugService::name() const
+{
+ Q_D(const QQmlDebugService);
+ return d->name;
+}
+
+float QQmlDebugService::version() const
+{
+ Q_D(const QQmlDebugService);
+ return d->version;
+}
+
+QQmlDebugService::State QQmlDebugService::state() const
+{
+ Q_D(const QQmlDebugService);
+ return d->state;
+}
+
+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 QQmlDebugService::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 *QQmlDebugService::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 QQmlDebugService::isDebuggingEnabled()
+{
+ return QQmlDebugServer::instance() != 0;
+}
+
+bool QQmlDebugService::hasDebuggingClient()
+{
+ return QQmlDebugServer::instance() != 0
+ && QQmlDebugServer::instance()->hasDebuggingClient();
+}
+
+QString QQmlDebugService::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 QQmlDebugService::sendMessage(const QByteArray &message)
+{
+ sendMessages(QList<QByteArray>() << message);
+}
+
+void QQmlDebugService::sendMessages(const QList<QByteArray> &messages)
+{
+ Q_D(QQmlDebugService);
+
+ if (state() != Enabled)
+ return;
+
+ d->server->sendMessages(this, messages);
+}
+
+bool QQmlDebugService::waitForMessage()
+{
+ Q_D(QQmlDebugService);
+
+ if (state() != Enabled)
+ return false;
+
+ return d->server->waitForMessage(this);
+}
+
+void QQmlDebugService::stateAboutToBeChanged(State)
+{
+}
+
+void QQmlDebugService::stateChanged(State)
+{
+}
+
+void QQmlDebugService::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
new file mode 100644
index 0000000000..f19b64f42b
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVICE_H
+#define QQMLDEBUGSERVICE_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qtqmlglobal_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_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServicePrivate;
+class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQmlDebugService)
+ Q_DISABLE_COPY(QQmlDebugService)
+
+public:
+ explicit QQmlDebugService(const QString &, float version, QObject *parent = 0);
+ ~QQmlDebugService();
+
+ QString name() const;
+ float version() const;
+
+ enum State { NotConnected, Unavailable, Enabled };
+ State state() const;
+
+ void sendMessage(const QByteArray &);
+ void sendMessages(const QList<QByteArray> &);
+ bool waitForMessage();
+
+ static int idForObject(QObject *);
+ static QObject *objectForId(int);
+
+ static QString objectToString(QObject *obj);
+
+ static bool isDebuggingEnabled();
+ static bool hasDebuggingClient();
+
+protected:
+ QQmlDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0);
+
+ State registerService();
+
+ virtual void stateAboutToBeChanged(State);
+ virtual void stateChanged(State);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QQmlDebugServer;
+ friend class QQmlDebugServerPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_H
+
diff --git a/src/qml/debugger/qqmldebugservice_p_p.h b/src/qml/debugger/qqmldebugservice_p_p.h
new file mode 100644
index 0000000000..c066e41fe6
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservice_p_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSERVICE_P_H
+#define QQMLDEBUGSERVICE_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 <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugServer;
+
+class QQmlDebugServicePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlDebugService)
+public:
+ QQmlDebugServicePrivate();
+
+ QString name;
+ float version;
+ QQmlDebugServer *server;
+ QQmlDebugService::State state;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSERVICE_P_H
diff --git a/src/qml/debugger/qqmldebugstatesdelegate_p.h b/src/qml/debugger/qqmldebugstatesdelegate_p.h
new file mode 100644
index 0000000000..6e3cc978f2
--- /dev/null
+++ b/src/qml/debugger/qqmldebugstatesdelegate_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGSTATESDELEGATE_P_H
+#define QQMLDEBUGSTATESDELEGATE_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 <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlContext;
+class QQmlProperty;
+class QObject;
+class QString;
+class QVariant;
+
+class QQmlDebugStatesDelegate
+{
+protected:
+ QQmlDebugStatesDelegate() {}
+
+public:
+ virtual ~QQmlDebugStatesDelegate() {}
+
+ virtual void buildStatesList(QQmlContext *ctxt, bool cleanList) = 0;
+ virtual void updateBinding(QQmlContext *context,
+ const QQmlProperty &property,
+ const QVariant &expression, bool isLiteralValue,
+ const QString &fileName, int line, int column,
+ bool *inBaseState) = 0;
+ virtual bool setBindingForInvalidProperty(QObject *object,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue) = 0;
+ virtual void resetBindingForInvalidProperty(QObject *object,
+ const QString &propertyName) = 0;
+
+private:
+ Q_DISABLE_COPY(QQmlDebugStatesDelegate)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLDEBUGSTATESDELEGATE_P_H
diff --git a/src/qml/debugger/qqmlenginedebug.cpp b/src/qml/debugger/qqmlenginedebug.cpp
new file mode 100644
index 0000000000..597e7aeb04
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebug.cpp
@@ -0,0 +1,1072 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlenginedebug_p.h"
+
+#include "qqmldebugclient_p.h"
+
+#include "qqmlenginedebugservice_p.h"
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngineDebugClient : public QQmlDebugClient
+{
+public:
+ QQmlEngineDebugClient(QQmlDebugConnection *client, QQmlEngineDebugPrivate *p);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ QQmlEngineDebugPrivate *priv;
+ friend class QQmlEngineDebugPrivate;
+};
+
+class QQmlEngineDebugPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQmlEngineDebug)
+public:
+ QQmlEngineDebugPrivate(QQmlDebugConnection *);
+ ~QQmlEngineDebugPrivate();
+
+ void stateChanged(QQmlEngineDebug::State status);
+ void message(const QByteArray &);
+
+ QQmlEngineDebugClient *client;
+ int nextId;
+ int getId();
+
+ void decode(QDataStream &, QQmlDebugContextReference &);
+ void decode(QDataStream &, QQmlDebugObjectReference &, bool simple);
+
+ static void remove(QQmlEngineDebug *, QQmlDebugEnginesQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugRootContextQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugObjectQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugExpressionQuery *);
+ static void remove(QQmlEngineDebug *, QQmlDebugWatch *);
+
+ QHash<int, QQmlDebugEnginesQuery *> enginesQuery;
+ QHash<int, QQmlDebugRootContextQuery *> rootContextQuery;
+ QHash<int, QQmlDebugObjectQuery *> objectQuery;
+ QHash<int, QQmlDebugExpressionQuery *> expressionQuery;
+
+ QHash<int, QQmlDebugWatch *> watched;
+};
+
+QQmlEngineDebugClient::QQmlEngineDebugClient(QQmlDebugConnection *client,
+ QQmlEngineDebugPrivate *p)
+ : QQmlDebugClient(QLatin1String("QQmlEngine"), client), priv(p)
+{
+}
+
+void QQmlEngineDebugClient::stateChanged(State status)
+{
+ if (priv)
+ priv->stateChanged(static_cast<QQmlEngineDebug::State>(status));
+}
+
+void QQmlEngineDebugClient::messageReceived(const QByteArray &data)
+{
+ if (priv)
+ priv->message(data);
+}
+
+QQmlEngineDebugPrivate::QQmlEngineDebugPrivate(QQmlDebugConnection *c)
+ : client(new QQmlEngineDebugClient(c, this)), nextId(0)
+{
+}
+
+QQmlEngineDebugPrivate::~QQmlEngineDebugPrivate()
+{
+ if (client)
+ client->priv = 0;
+ delete client;
+
+ QHash<int, QQmlDebugEnginesQuery*>::iterator enginesIter = enginesQuery.begin();
+ for (; enginesIter != enginesQuery.end(); ++enginesIter) {
+ enginesIter.value()->m_client = 0;
+ if (enginesIter.value()->state() == QQmlDebugQuery::Waiting)
+ enginesIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugRootContextQuery*>::iterator rootContextIter = rootContextQuery.begin();
+ for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) {
+ rootContextIter.value()->m_client = 0;
+ if (rootContextIter.value()->state() == QQmlDebugQuery::Waiting)
+ rootContextIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugObjectQuery*>::iterator objectIter = objectQuery.begin();
+ for (; objectIter != objectQuery.end(); ++objectIter) {
+ objectIter.value()->m_client = 0;
+ if (objectIter.value()->state() == QQmlDebugQuery::Waiting)
+ objectIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugExpressionQuery*>::iterator exprIter = expressionQuery.begin();
+ for (; exprIter != expressionQuery.end(); ++exprIter) {
+ exprIter.value()->m_client = 0;
+ if (exprIter.value()->state() == QQmlDebugQuery::Waiting)
+ exprIter.value()->setState(QQmlDebugQuery::Error);
+ }
+
+ QHash<int, QQmlDebugWatch*>::iterator watchIter = watched.begin();
+ for (; watchIter != watched.end(); ++watchIter) {
+ watchIter.value()->m_client = 0;
+ watchIter.value()->setState(QQmlDebugWatch::Dead);
+ }
+}
+
+int QQmlEngineDebugPrivate::getId()
+{
+ return nextId++;
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugEnginesQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->enginesQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c,
+ QQmlDebugRootContextQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->rootContextQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugObjectQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->objectQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugExpressionQuery *q)
+{
+ if (c && q) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->expressionQuery.remove(q->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::remove(QQmlEngineDebug *c, QQmlDebugWatch *w)
+{
+ if (c && w) {
+ QQmlEngineDebugPrivate *p = (QQmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->watched.remove(w->m_queryId);
+ }
+}
+
+void QQmlEngineDebugPrivate::decode(QDataStream &ds, QQmlDebugObjectReference &o,
+ bool simple)
+{
+ QQmlEngineDebugService::QQmlObjectData 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(QQmlDebugObjectReference());
+ decode(ds, o.m_children.last(), !recur);
+ }
+
+ int propCount;
+ ds >> propCount;
+
+ for (int ii = 0; ii < propCount; ++ii) {
+ QQmlEngineDebugService::QQmlObjectProperty data;
+ ds >> data;
+ QQmlDebugPropertyReference 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 QQmlEngineDebugService::QQmlObjectProperty::Basic:
+ case QQmlEngineDebugService::QQmlObjectProperty::List:
+ case QQmlEngineDebugService::QQmlObjectProperty::SignalProperty:
+ {
+ prop.m_value = data.value;
+ break;
+ }
+ case QQmlEngineDebugService::QQmlObjectProperty::Object:
+ {
+ QQmlDebugObjectReference obj;
+ obj.m_debugId = prop.m_value.toInt();
+ prop.m_value = QVariant::fromValue(obj);
+ break;
+ }
+ case QQmlEngineDebugService::QQmlObjectProperty::Unknown:
+ break;
+ }
+ o.m_properties << prop;
+ }
+}
+
+void QQmlEngineDebugPrivate::decode(QDataStream &ds, QQmlDebugContextReference &c)
+{
+ ds >> c.m_name >> c.m_debugId;
+
+ int contextCount;
+ ds >> contextCount;
+
+ for (int ii = 0; ii < contextCount; ++ii) {
+ c.m_contexts.append(QQmlDebugContextReference());
+ decode(ds, c.m_contexts.last());
+ }
+
+ int objectCount;
+ ds >> objectCount;
+
+ for (int ii = 0; ii < objectCount; ++ii) {
+ QQmlDebugObjectReference obj;
+ decode(ds, obj, true);
+
+ obj.m_contextDebugId = c.m_debugId;
+ c.m_objects << obj;
+ }
+}
+
+void QQmlEngineDebugPrivate::stateChanged(QQmlEngineDebug::State status)
+{
+ emit q_func()->stateChanged(status);
+}
+
+void QQmlEngineDebugPrivate::message(const QByteArray &data)
+{
+ QDataStream ds(data);
+
+ QByteArray type;
+ ds >> type;
+
+ //qDebug() << "QQmlEngineDebugPrivate::message()" << type;
+
+ if (type == "LIST_ENGINES_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugEnginesQuery *query = enginesQuery.value(queryId);
+ if (!query)
+ return;
+ enginesQuery.remove(queryId);
+
+ int count;
+ ds >> count;
+
+ for (int ii = 0; ii < count; ++ii) {
+ QQmlDebugEngineReference ref;
+ ds >> ref.m_name;
+ ds >> ref.m_debugId;
+ query->m_engines << ref;
+ }
+
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "LIST_OBJECTS_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugRootContextQuery *query = rootContextQuery.value(queryId);
+ if (!query)
+ return;
+ rootContextQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_context);
+
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "FETCH_OBJECT_R") {
+ int queryId;
+ ds >> queryId;
+
+ QQmlDebugObjectQuery *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(QQmlDebugQuery::Completed);
+ } else if (type == "EVAL_EXPRESSION_R") {
+ int queryId;
+ QVariant result;
+ ds >> queryId >> result;
+
+ QQmlDebugExpressionQuery *query = expressionQuery.value(queryId);
+ if (!query)
+ return;
+ expressionQuery.remove(queryId);
+
+ query->m_result = result;
+ query->m_client = 0;
+ query->setState(QQmlDebugQuery::Completed);
+ } else if (type == "WATCH_PROPERTY_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "WATCH_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "WATCH_EXPR_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QQmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QQmlDebugWatch::Active : QQmlDebugWatch::Inactive);
+ } else if (type == "UPDATE_WATCH") {
+ int queryId;
+ int debugId;
+ QByteArray name;
+ QVariant value;
+ ds >> queryId >> debugId >> name >> value;
+
+ QQmlDebugWatch *watch = watched.value(queryId, 0);
+ if (!watch)
+ return;
+ emit watch->valueChanged(name, value);
+ } else if (type == "OBJECT_CREATED") {
+ emit q_func()->newObjects();
+ }
+}
+
+QQmlEngineDebug::QQmlEngineDebug(QQmlDebugConnection *client, QObject *parent)
+ : QObject(*(new QQmlEngineDebugPrivate(client)), parent)
+{
+}
+
+QQmlEngineDebug::~QQmlEngineDebug()
+{
+}
+
+QQmlEngineDebug::State QQmlEngineDebug::state() const
+{
+ Q_D(const QQmlEngineDebug);
+
+ return static_cast<QQmlEngineDebug::State>(d->client->state());
+}
+
+QQmlDebugPropertyWatch *QQmlEngineDebug::addWatch(const QQmlDebugPropertyReference &property, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugPropertyWatch *watch = new QQmlDebugPropertyWatch(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugContextReference &, const QString &, QObject *)
+{
+ qWarning("QQmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+QQmlDebugObjectExpressionWatch *QQmlEngineDebug::addWatch(const QQmlDebugObjectReference &object, const QString &expr, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+ QQmlDebugObjectExpressionWatch *watch = new QQmlDebugObjectExpressionWatch(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugWatch::Dead;
+ }
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugWatch *watch = new QQmlDebugWatch(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QQmlDebugWatch *QQmlEngineDebug::addWatch(const QQmlDebugFileReference &, QObject *)
+{
+ qWarning("QQmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+void QQmlEngineDebug::removeWatch(QQmlDebugWatch *watch)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (!watch || !watch->m_client)
+ return;
+
+ watch->m_client = 0;
+ watch->setState(QQmlDebugWatch::Inactive);
+
+ d->watched.remove(watch->queryId());
+
+ if (d->client && d->client->state() == QQmlDebugClient::Enabled) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("NO_WATCH") << watch->queryId();
+ d->client->sendMessage(message);
+ }
+}
+
+QQmlDebugEnginesQuery *QQmlEngineDebug::queryAvailableEngines(QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugEnginesQuery *query = new QQmlDebugEnginesQuery(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugRootContextQuery *QQmlEngineDebug::queryRootContexts(const QQmlDebugEngineReference &engine, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugRootContextQuery *query = new QQmlDebugRootContextQuery(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugObjectQuery *QQmlEngineDebug::queryObject(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugObjectQuery *query = new QQmlDebugObjectQuery(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugObjectQuery *QQmlEngineDebug::queryObjectRecursive(const QQmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugObjectQuery *query = new QQmlDebugObjectQuery(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QQmlDebugExpressionQuery *QQmlEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
+{
+ Q_D(QQmlEngineDebug);
+
+ QQmlDebugExpressionQuery *query = new QQmlDebugExpressionQuery(parent);
+ if (d->client->state() == QQmlDebugClient::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 = QQmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+bool QQmlEngineDebug::setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression,
+ bool isLiteralValue,
+ QString source, int line)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_BINDING") << objectDebugId << propertyName << bindingExpression << isLiteralValue << source << line;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QQmlEngineDebug::resetBindingForObject(int objectDebugId, const QString &propertyName)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::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 QQmlEngineDebug::setMethodBody(int objectDebugId, const QString &methodName,
+ const QString &methodBody)
+{
+ Q_D(QQmlEngineDebug);
+
+ if (d->client->state() == QQmlDebugClient::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;
+ }
+}
+
+QQmlDebugWatch::QQmlDebugWatch(QObject *parent)
+ : QObject(parent), m_state(Waiting), m_queryId(-1), m_client(0), m_objectDebugId(-1)
+{
+}
+
+QQmlDebugWatch::~QQmlDebugWatch()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+int QQmlDebugWatch::queryId() const
+{
+ return m_queryId;
+}
+
+int QQmlDebugWatch::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QQmlDebugWatch::State QQmlDebugWatch::state() const
+{
+ return m_state;
+}
+
+void QQmlDebugWatch::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QQmlDebugPropertyWatch::QQmlDebugPropertyWatch(QObject *parent)
+ : QQmlDebugWatch(parent)
+{
+}
+
+QString QQmlDebugPropertyWatch::name() const
+{
+ return m_name;
+}
+
+
+QQmlDebugObjectExpressionWatch::QQmlDebugObjectExpressionWatch(QObject *parent)
+ : QQmlDebugWatch(parent)
+{
+}
+
+QString QQmlDebugObjectExpressionWatch::expression() const
+{
+ return m_expr;
+}
+
+
+QQmlDebugQuery::QQmlDebugQuery(QObject *parent)
+ : QObject(parent), m_state(Waiting)
+{
+}
+
+QQmlDebugQuery::State QQmlDebugQuery::state() const
+{
+ return m_state;
+}
+
+bool QQmlDebugQuery::isWaiting() const
+{
+ return m_state == Waiting;
+}
+
+void QQmlDebugQuery::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QQmlDebugEnginesQuery::QQmlDebugEnginesQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugEnginesQuery::~QQmlDebugEnginesQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QList<QQmlDebugEngineReference> QQmlDebugEnginesQuery::engines() const
+{
+ return m_engines;
+}
+
+QQmlDebugRootContextQuery::QQmlDebugRootContextQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugRootContextQuery::~QQmlDebugRootContextQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QQmlDebugContextReference QQmlDebugRootContextQuery::rootContext() const
+{
+ return m_context;
+}
+
+QQmlDebugObjectQuery::QQmlDebugObjectQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugObjectQuery::~QQmlDebugObjectQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QQmlDebugObjectReference QQmlDebugObjectQuery::object() const
+{
+ return m_object;
+}
+
+QQmlDebugExpressionQuery::QQmlDebugExpressionQuery(QObject *parent)
+ : QQmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QQmlDebugExpressionQuery::~QQmlDebugExpressionQuery()
+{
+ if (m_client && m_queryId != -1)
+ QQmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QVariant QQmlDebugExpressionQuery::expression() const
+{
+ return m_expr;
+}
+
+QVariant QQmlDebugExpressionQuery::result() const
+{
+ return m_result;
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference()
+ : m_debugId(-1)
+{
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference(int debugId)
+ : m_debugId(debugId)
+{
+}
+
+QQmlDebugEngineReference::QQmlDebugEngineReference(const QQmlDebugEngineReference &o)
+ : m_debugId(o.m_debugId), m_name(o.m_name)
+{
+}
+
+QQmlDebugEngineReference &
+QQmlDebugEngineReference::operator=(const QQmlDebugEngineReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name;
+ return *this;
+}
+
+int QQmlDebugEngineReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugEngineReference::name() const
+{
+ return m_name;
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference()
+ : m_debugId(-1), m_contextDebugId(-1)
+{
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference(int debugId)
+ : m_debugId(debugId), m_contextDebugId(-1)
+{
+}
+
+QQmlDebugObjectReference::QQmlDebugObjectReference(const QQmlDebugObjectReference &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)
+{
+}
+
+QQmlDebugObjectReference &
+QQmlDebugObjectReference::operator=(const QQmlDebugObjectReference &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 QQmlDebugObjectReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugObjectReference::className() const
+{
+ return m_class;
+}
+
+QString QQmlDebugObjectReference::idString() const
+{
+ return m_idString;
+}
+
+QString QQmlDebugObjectReference::name() const
+{
+ return m_name;
+}
+
+QQmlDebugFileReference QQmlDebugObjectReference::source() const
+{
+ return m_source;
+}
+
+int QQmlDebugObjectReference::contextDebugId() const
+{
+ return m_contextDebugId;
+}
+
+QList<QQmlDebugPropertyReference> QQmlDebugObjectReference::properties() const
+{
+ return m_properties;
+}
+
+QList<QQmlDebugObjectReference> QQmlDebugObjectReference::children() const
+{
+ return m_children;
+}
+
+QQmlDebugContextReference::QQmlDebugContextReference()
+ : m_debugId(-1)
+{
+}
+
+QQmlDebugContextReference::QQmlDebugContextReference(const QQmlDebugContextReference &o)
+ : m_debugId(o.m_debugId), m_name(o.m_name), m_objects(o.m_objects), m_contexts(o.m_contexts)
+{
+}
+
+QQmlDebugContextReference &QQmlDebugContextReference::operator=(const QQmlDebugContextReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name; m_objects = o.m_objects;
+ m_contexts = o.m_contexts;
+ return *this;
+}
+
+int QQmlDebugContextReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QQmlDebugContextReference::name() const
+{
+ return m_name;
+}
+
+QList<QQmlDebugObjectReference> QQmlDebugContextReference::objects() const
+{
+ return m_objects;
+}
+
+QList<QQmlDebugContextReference> QQmlDebugContextReference::contexts() const
+{
+ return m_contexts;
+}
+
+QQmlDebugFileReference::QQmlDebugFileReference()
+ : m_lineNumber(-1), m_columnNumber(-1)
+{
+}
+
+QQmlDebugFileReference::QQmlDebugFileReference(const QQmlDebugFileReference &o)
+ : m_url(o.m_url), m_lineNumber(o.m_lineNumber), m_columnNumber(o.m_columnNumber)
+{
+}
+
+QQmlDebugFileReference &QQmlDebugFileReference::operator=(const QQmlDebugFileReference &o)
+{
+ m_url = o.m_url; m_lineNumber = o.m_lineNumber; m_columnNumber = o.m_columnNumber;
+ return *this;
+}
+
+QUrl QQmlDebugFileReference::url() const
+{
+ return m_url;
+}
+
+void QQmlDebugFileReference::setUrl(const QUrl &u)
+{
+ m_url = u;
+}
+
+int QQmlDebugFileReference::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void QQmlDebugFileReference::setLineNumber(int l)
+{
+ m_lineNumber = l;
+}
+
+int QQmlDebugFileReference::columnNumber() const
+{
+ return m_columnNumber;
+}
+
+void QQmlDebugFileReference::setColumnNumber(int c)
+{
+ m_columnNumber = c;
+}
+
+QQmlDebugPropertyReference::QQmlDebugPropertyReference()
+ : m_objectDebugId(-1), m_hasNotifySignal(false)
+{
+}
+
+QQmlDebugPropertyReference::QQmlDebugPropertyReference(const QQmlDebugPropertyReference &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)
+{
+}
+
+QQmlDebugPropertyReference &QQmlDebugPropertyReference::operator=(const QQmlDebugPropertyReference &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 QQmlDebugPropertyReference::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QString QQmlDebugPropertyReference::name() const
+{
+ return m_name;
+}
+
+QString QQmlDebugPropertyReference::valueTypeName() const
+{
+ return m_valueTypeName;
+}
+
+QVariant QQmlDebugPropertyReference::value() const
+{
+ return m_value;
+}
+
+QString QQmlDebugPropertyReference::binding() const
+{
+ return m_binding;
+}
+
+bool QQmlDebugPropertyReference::hasNotifySignal() const
+{
+ return m_hasNotifySignal;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/debugger/qqmlenginedebug_p.h b/src/qml/debugger/qqmlenginedebug_p.h
new file mode 100644
index 0000000000..0562d8755b
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebug_p.h
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINEDEBUG_H
+#define QQMLENGINEDEBUG_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 <QtCore/qvariant.h>
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlDebugConnection;
+class QQmlDebugWatch;
+class QQmlDebugPropertyWatch;
+class QQmlDebugObjectExpressionWatch;
+class QQmlDebugEnginesQuery;
+class QQmlDebugRootContextQuery;
+class QQmlDebugObjectQuery;
+class QQmlDebugExpressionQuery;
+class QQmlDebugPropertyReference;
+class QQmlDebugContextReference;
+class QQmlDebugObjectReference;
+class QQmlDebugFileReference;
+class QQmlDebugEngineReference;
+class QQmlEngineDebugPrivate;
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebug : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { NotConnected, Unavailable, Enabled };
+
+ explicit QQmlEngineDebug(QQmlDebugConnection *, QObject * = 0);
+ ~QQmlEngineDebug();
+
+ State state() const;
+
+ QQmlDebugPropertyWatch *addWatch(const QQmlDebugPropertyReference &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugContextReference &, const QString &,
+ QObject *parent = 0);
+ QQmlDebugObjectExpressionWatch *addWatch(const QQmlDebugObjectReference &, const QString &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugWatch *addWatch(const QQmlDebugFileReference &,
+ QObject *parent = 0);
+
+ void removeWatch(QQmlDebugWatch *watch);
+
+ QQmlDebugEnginesQuery *queryAvailableEngines(QObject *parent = 0);
+ QQmlDebugRootContextQuery *queryRootContexts(const QQmlDebugEngineReference &,
+ QObject *parent = 0);
+ QQmlDebugObjectQuery *queryObject(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugObjectQuery *queryObjectRecursive(const QQmlDebugObjectReference &,
+ QObject *parent = 0);
+ QQmlDebugExpressionQuery *queryExpressionResult(int objectDebugId,
+ const QString &expr,
+ QObject *parent = 0);
+ bool setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression, bool isLiteralValue,
+ QString source = QString(), int line = -1);
+ bool resetBindingForObject(int objectDebugId, const QString &propertyName);
+ bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody);
+
+Q_SIGNALS:
+ void newObjects();
+ void stateChanged(State state);
+
+private:
+ Q_DECLARE_PRIVATE(QQmlEngineDebug)
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugWatch : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { Waiting, Active, Inactive, Dead };
+
+ QQmlDebugWatch(QObject *);
+ ~QQmlDebugWatch();
+
+ int queryId() const;
+ int objectDebugId() const;
+ State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QQmlDebugWatch::State);
+ //void objectChanged(int, const QQmlDebugObjectReference &);
+ //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 QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+ int m_queryId;
+ QQmlEngineDebug *m_client;
+ int m_objectDebugId;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugPropertyWatch : public QQmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QQmlDebugPropertyWatch(QObject *parent);
+
+ QString name() const;
+
+private:
+ friend class QQmlEngineDebug;
+ QString m_name;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectExpressionWatch : public QQmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QQmlDebugObjectExpressionWatch(QObject *parent);
+
+ QString expression() const;
+
+private:
+ friend class QQmlEngineDebug;
+ QString m_expr;
+ int m_debugId;
+};
+
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugQuery : public QObject
+{
+ Q_OBJECT
+public:
+ enum State { Waiting, Error, Completed };
+
+ State state() const;
+ bool isWaiting() const;
+
+Q_SIGNALS:
+ void stateChanged(QQmlDebugQuery::State);
+
+protected:
+ QQmlDebugQuery(QObject *);
+
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugFileReference
+{
+public:
+ QQmlDebugFileReference();
+ QQmlDebugFileReference(const QQmlDebugFileReference &);
+ QQmlDebugFileReference &operator=(const QQmlDebugFileReference &);
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ int lineNumber() const;
+ void setLineNumber(int);
+ int columnNumber() const;
+ void setColumnNumber(int);
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ QUrl m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugEngineReference
+{
+public:
+ QQmlDebugEngineReference();
+ QQmlDebugEngineReference(int);
+ QQmlDebugEngineReference(const QQmlDebugEngineReference &);
+ QQmlDebugEngineReference &operator=(const QQmlDebugEngineReference &);
+
+ int debugId() const;
+ QString name() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectReference
+{
+public:
+ QQmlDebugObjectReference();
+ QQmlDebugObjectReference(int);
+ QQmlDebugObjectReference(const QQmlDebugObjectReference &);
+ QQmlDebugObjectReference &operator=(const QQmlDebugObjectReference &);
+
+ int debugId() const;
+ QString className() const;
+ QString idString() const;
+ QString name() const;
+
+ QQmlDebugFileReference source() const;
+ int contextDebugId() const;
+
+ QList<QQmlDebugPropertyReference> properties() const;
+ QList<QQmlDebugObjectReference> children() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_class;
+ QString m_idString;
+ QString m_name;
+ QQmlDebugFileReference m_source;
+ int m_contextDebugId;
+ QList<QQmlDebugPropertyReference> m_properties;
+ QList<QQmlDebugObjectReference> m_children;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugContextReference
+{
+public:
+ QQmlDebugContextReference();
+ QQmlDebugContextReference(const QQmlDebugContextReference &);
+ QQmlDebugContextReference &operator=(const QQmlDebugContextReference &);
+
+ int debugId() const;
+ QString name() const;
+
+ QList<QQmlDebugObjectReference> objects() const;
+ QList<QQmlDebugContextReference> contexts() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+ QList<QQmlDebugObjectReference> m_objects;
+ QList<QQmlDebugContextReference> m_contexts;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugPropertyReference
+{
+public:
+ QQmlDebugPropertyReference();
+ QQmlDebugPropertyReference(const QQmlDebugPropertyReference &);
+ QQmlDebugPropertyReference &operator=(const QQmlDebugPropertyReference &);
+
+ int objectDebugId() const;
+ QString name() const;
+ QVariant value() const;
+ QString valueTypeName() const;
+ QString binding() const;
+ bool hasNotifySignal() const;
+
+private:
+ friend class QQmlEngineDebugPrivate;
+ int m_objectDebugId;
+ QString m_name;
+ QVariant m_value;
+ QString m_valueTypeName;
+ QString m_binding;
+ bool m_hasNotifySignal;
+};
+
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugEnginesQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugEnginesQuery();
+ QList<QQmlDebugEngineReference> engines() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugEnginesQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QList<QQmlDebugEngineReference> m_engines;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugRootContextQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugRootContextQuery();
+ QQmlDebugContextReference rootContext() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugRootContextQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QQmlDebugContextReference m_context;
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugObjectQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugObjectQuery();
+ QQmlDebugObjectReference object() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugObjectQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QQmlDebugObjectReference m_object;
+
+};
+
+class Q_QML_PRIVATE_EXPORT QQmlDebugExpressionQuery : public QQmlDebugQuery
+{
+ Q_OBJECT
+public:
+ virtual ~QQmlDebugExpressionQuery();
+ QVariant expression() const;
+ QVariant result() const;
+private:
+ friend class QQmlEngineDebug;
+ friend class QQmlEngineDebugPrivate;
+ QQmlDebugExpressionQuery(QObject *);
+ QQmlEngineDebug *m_client;
+ int m_queryId;
+ QVariant m_expr;
+ QVariant m_result;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQmlDebugEngineReference)
+Q_DECLARE_METATYPE(QQmlDebugObjectReference)
+Q_DECLARE_METATYPE(QQmlDebugContextReference)
+Q_DECLARE_METATYPE(QQmlDebugPropertyReference)
+
+QT_END_HEADER
+
+#endif // QQMLENGINEDEBUG_H
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
new file mode 100644
index 0000000000..be2e826bdf
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -0,0 +1,733 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlenginedebugservice_p.h"
+
+#include "qqmldebugstatesdelegate_p.h"
+#include <private/qqmlboundsignal_p.h>
+#include <qqmlengine.h>
+#include <private/qqmlmetatype_p.h>
+#include <qqmlproperty.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlwatcher_p.h>
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlexpression_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlEngineDebugService, qmlEngineDebugService);
+
+QQmlEngineDebugService *QQmlEngineDebugService::instance()
+{
+ return qmlEngineDebugService();
+}
+
+QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent)
+ : QQmlDebugService(QLatin1String("QQmlEngine"), 1, parent),
+ m_watch(new QQmlWatcher(this)),
+ m_statesDelegate(0)
+{
+ QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
+ this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
+
+ registerService();
+}
+
+QQmlEngineDebugService::~QQmlEngineDebugService()
+{
+ delete m_statesDelegate;
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QQmlEngineDebugService::QQmlObjectData &data)
+{
+ ds << data.url << data.lineNumber << data.columnNumber << data.idString
+ << data.objectName << data.objectType << data.objectId << data.contextId;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QQmlEngineDebugService::QQmlObjectData &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 QQmlEngineDebugService::QQmlObjectProperty &data)
+{
+ ds << (int)data.type << data.name << data.value << data.valueTypeName
+ << data.binding << data.hasNotifySignal;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QQmlEngineDebugService::QQmlObjectProperty &data)
+{
+ int type;
+ ds >> type >> data.name >> data.value >> data.valueTypeName
+ >> data.binding >> data.hasNotifySignal;
+ data.type = (QQmlEngineDebugService::QQmlObjectProperty::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 = QQmlPropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
+
+ if (sigIdx == -1)
+ return false;
+
+ return true;
+}
+
+QQmlEngineDebugService::QQmlObjectProperty
+QQmlEngineDebugService::propertyData(QObject *obj, int propIdx)
+{
+ QQmlObjectProperty rv;
+
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+
+ rv.type = QQmlObjectProperty::Unknown;
+ rv.valueTypeName = QString::fromUtf8(prop.typeName());
+ rv.name = QString::fromUtf8(prop.name());
+ rv.hasNotifySignal = prop.hasNotifySignal();
+ QQmlAbstractBinding *binding =
+ QQmlPropertyPrivate::binding(QQmlProperty(obj, rv.name));
+ if (binding)
+ rv.binding = binding->expression();
+
+ if (QQmlValueTypeFactory::isValueType(prop.userType())) {
+ rv.type = QQmlObjectProperty::Basic;
+ } else if (QQmlMetaType::isQObject(prop.userType())) {
+ rv.type = QQmlObjectProperty::Object;
+ } else if (QQmlMetaType::isList(prop.userType())) {
+ rv.type = QQmlObjectProperty::List;
+ }
+
+ QVariant value;
+ if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) {
+ value = prop.read(obj);
+ }
+ rv.value = valueContents(value);
+
+ return rv;
+}
+
+QVariant QQmlEngineDebugService::valueContents(const QVariant &value) const
+{
+ int userType = value.userType();
+
+ //QObject * is not streamable.
+ //Convert all such instances to a String value
+
+ 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 (value.type() == QVariant::Map) {
+ QVariantMap contents;
+ QMapIterator<QString, QVariant> i(value.toMap());
+ while (i.hasNext()) {
+ i.next();
+ contents.insert(i.key(), valueContents(i.value()));
+ }
+ return contents;
+ }
+
+ if (QQmlValueTypeFactory::isValueType(userType))
+ return value;
+
+ if (QQmlMetaType::isQObject(userType)) {
+ QObject *o = QQmlMetaType::toQObject(value);
+ if (o) {
+ QString name = o->objectName();
+ if (name.isEmpty())
+ name = QLatin1String("<unnamed object>");
+ return name;
+ }
+ }
+
+ return QLatin1String("<unknown value>");
+}
+
+void QQmlEngineDebugService::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<QQmlContext*>(children[ii]) || QQmlBoundSignal::cast(children[ii]))
+ --childrenCount;
+ }
+
+ message << childrenCount << recur;
+
+ QList<QQmlObjectProperty> fakeProperties;
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ if (qobject_cast<QQmlContext*>(child))
+ continue;
+ QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
+ if (signal) {
+ if (!dumpProperties)
+ continue;
+ QQmlObjectProperty prop;
+ prop.type = QQmlObjectProperty::SignalProperty;
+ prop.hasNotifySignal = false;
+ QQmlExpression *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 QQmlEngineDebugService::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 QQmlEngineDebugService::buildObjectList(QDataStream &message, QQmlContext *ctxt)
+{
+ QQmlContextData *p = QQmlContextData::get(ctxt);
+
+ QString ctxtName = ctxt->objectName();
+ int ctxtId = QQmlDebugService::idForObject(ctxt);
+
+ message << ctxtName << ctxtId;
+
+ int count = 0;
+
+ QQmlContextData *child = p->childContexts;
+ while (child) {
+ ++count;
+ child = child->nextChild;
+ }
+
+ message << count;
+
+ child = p->childContexts;
+ while (child) {
+ buildObjectList(message, child->asQQmlContext());
+ child = child->nextChild;
+ }
+
+ // Clean deleted objects
+ QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::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 QQmlEngineDebugService::buildStatesList(QQmlContext *ctxt, bool cleanList)
+{
+ if (m_statesDelegate)
+ m_statesDelegate->buildStatesList(ctxt, cleanList);
+}
+
+QQmlEngineDebugService::QQmlObjectData
+QQmlEngineDebugService::objectData(QObject *object)
+{
+ QQmlData *ddata = QQmlData::get(object);
+ QQmlObjectData 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;
+ }
+
+ QQmlContext *context = qmlContext(object);
+ if (context) {
+ QQmlContextData *cdata = QQmlContextData::get(context);
+ if (cdata)
+ rv.idString = cdata->findObjectId(object);
+ }
+
+ rv.objectName = object->objectName();
+ rv.objectId = QQmlDebugService::idForObject(object);
+ rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
+
+ QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
+ if (type) {
+ QString typeName = 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 QQmlEngineDebugService::messageReceived(const QByteArray &message)
+{
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+}
+
+void QQmlEngineDebugService::processMessage(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) {
+ QQmlEngine *engine = m_engines.at(ii);
+
+ QString engineName = engine->objectName();
+ int engineId = QQmlDebugService::idForObject(engine);
+
+ rs << engineName << engineId;
+ }
+
+ sendMessage(reply);
+ } else if (type == "LIST_OBJECTS") {
+ int queryId;
+ int engineId = -1;
+ ds >> queryId >> engineId;
+
+ QQmlEngine *engine =
+ qobject_cast<QQmlEngine *>(QQmlDebugService::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 = QQmlDebugService::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 = QQmlDebugService::objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+ QVariant result;
+ if (object && context) {
+ QQmlExpression 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;
+ QString filename;
+ int line;
+ ds >> objectId >> propertyName >> expr >> isLiteralValue;
+ if (!ds.atEnd()) { // backward compatibility from 2.1, 2.2
+ ds >> filename >> line;
+ }
+ setBinding(objectId, propertyName, expr, isLiteralValue, filename, line);
+ } 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 QQmlEngineDebugService::setBinding(int objectId,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue,
+ QString filename,
+ int line,
+ int column)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+
+ if (object && context) {
+ QQmlProperty property(object, propertyName, context);
+ if (property.isValid()) {
+
+ bool inBaseState = true;
+ if (m_statesDelegate) {
+ m_statesDelegate->updateBinding(context, property, expression, isLiteralValue,
+ filename, line, column, &inBaseState);
+ }
+
+ if (inBaseState) {
+ if (isLiteralValue) {
+ property.write(expression);
+ } else if (hasValidSignal(object, propertyName)) {
+ QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString());
+ QQmlPropertyPrivate::setSignalExpression(property, qmlExpression);
+ qmlExpression->setSourceLocation(filename, line, column);
+ } else if (property.isProperty()) {
+ QQmlBinding *binding = new QQmlBinding(expression.toString(), object, context);
+ binding->setTarget(property);
+ binding->setSourceLocation(filename, line, column);
+ binding->setNotifyOnValueChanged(true);
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, binding);
+ if (oldBinding)
+ oldBinding->destroy();
+ binding->update();
+ } else {
+ qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+
+ } else {
+ // not a valid property
+ bool ok = false;
+ if (m_statesDelegate)
+ ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue);
+ if (!ok)
+ qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+}
+
+void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+
+ if (object && context) {
+ if (object->property(propertyName.toLatin1()).isValid()) {
+ QQmlProperty property(object, propertyName);
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(property);
+ if (oldBinding) {
+ QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::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 QQuickItem has reset methods for its properties (with the
+ // notable exception of QQuickAnchors), so this is not a big issue
+ // later on, setBinding does take states into account
+ property.reset();
+ } else {
+ // overwrite with default value
+ if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) {
+ if (QObject *emptyObject = objType->create()) {
+ if (emptyObject->property(propertyName.toLatin1()).isValid()) {
+ QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read();
+ if (defaultValue.isValid()) {
+ setBinding(objectId, propertyName, defaultValue, true);
+ }
+ }
+ delete emptyObject;
+ }
+ }
+ }
+ } else if (hasValidSignal(object, propertyName)) {
+ QQmlProperty property(object, propertyName, context);
+ QQmlPropertyPrivate::setSignalExpression(property, 0);
+ } else {
+ if (m_statesDelegate)
+ m_statesDelegate->resetBindingForInvalidProperty(object, propertyName);
+ }
+ }
+}
+
+void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
+{
+ QObject *object = objectForId(objectId);
+ QQmlContext *context = qmlContext(object);
+ if (!object || !context || !context->engine())
+ return;
+ QQmlContextData *contextData = QQmlContextData::get(context);
+ if (!contextData)
+ return;
+
+ QQmlPropertyData dummy;
+ QQmlPropertyData *prop =
+ QQmlPropertyCache::property(context->engine(), object, method, dummy);
+
+ if (!prop || !prop->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})");
+
+ QQmlVMEMetaObject *vmeMetaObject =
+ static_cast<QQmlVMEMetaObject*>(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, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber));
+}
+
+void QQmlEngineDebugService::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 QQmlEngineDebugService::addEngine(QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(!m_engines.contains(engine));
+
+ m_engines.append(engine);
+}
+
+void QQmlEngineDebugService::remEngine(QQmlEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ m_engines.removeAll(engine);
+}
+
+void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ int engineId = QQmlDebugService::idForObject(engine);
+ int objectId = QQmlDebugService::idForObject(object);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
+ sendMessage(reply);
+}
+
+void QQmlEngineDebugService::setStatesDelegate(QQmlDebugStatesDelegate *delegate)
+{
+ m_statesDelegate = delegate;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
new file mode 100644
index 0000000000..1a92801fcc
--- /dev/null
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENGINEDEBUGSERVICE_P_H
+#define QQMLENGINEDEBUGSERVICE_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/qqmldebugservice_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QQmlContext;
+class QQmlWatcher;
+class QDataStream;
+class QQmlDebugStatesDelegate;
+
+class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QQmlEngineDebugService(QObject * = 0);
+ ~QQmlEngineDebugService();
+
+ struct QQmlObjectData {
+ QUrl url;
+ int lineNumber;
+ int columnNumber;
+ QString idString;
+ QString objectName;
+ QString objectType;
+ int objectId;
+ int contextId;
+ };
+
+ struct QQmlObjectProperty {
+ enum Type { Unknown, Basic, Object, List, SignalProperty };
+ Type type;
+ QString name;
+ QVariant value;
+ QString valueTypeName;
+ QString binding;
+ bool hasNotifySignal;
+ };
+
+ void addEngine(QQmlEngine *);
+ void remEngine(QQmlEngine *);
+ void objectCreated(QQmlEngine *, QObject *);
+
+ void setStatesDelegate(QQmlDebugStatesDelegate *);
+
+ static QQmlEngineDebugService *instance();
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void processMessage(const QByteArray &msg);
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ void prepareDeferredObjects(QObject *);
+ void buildObjectList(QDataStream &, QQmlContext *);
+ void buildObjectDump(QDataStream &, QObject *, bool, bool);
+ void buildStatesList(QQmlContext *, bool);
+ QQmlObjectData objectData(QObject *);
+ QQmlObjectProperty propertyData(QObject *, int);
+ QVariant valueContents(const QVariant &defaultValue) const;
+ void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0);
+ void resetBinding(int objectId, const QString &propertyName);
+ void setMethodBody(int objectId, const QString &method, const QString &body);
+
+ QList<QQmlEngine *> m_engines;
+ QQmlWatcher *m_watch;
+ QQmlDebugStatesDelegate *m_statesDelegate;
+};
+Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectData &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectData &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugService::QQmlObjectProperty &);
+Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugService::QQmlObjectProperty &);
+
+QT_END_NAMESPACE
+
+#endif // QQMLENGINEDEBUGSERVICE_P_H
+
diff --git a/src/qml/debugger/qqmlinspectorinterface_p.h b/src/qml/debugger/qqmlinspectorinterface_p.h
new file mode 100644
index 0000000000..7f52dffa2e
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorinterface_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINSPECTORINTERFACE_H
+#define QQMLINSPECTORINTERFACE_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 <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class Q_QML_EXPORT QQmlInspectorInterface
+{
+public:
+ QQmlInspectorInterface() {}
+ virtual ~QQmlInspectorInterface() {}
+
+ virtual bool canHandleView(QObject *view) = 0;
+
+ virtual void activate(QObject *view) = 0;
+ virtual void deactivate() = 0;
+
+ virtual void clientMessage(const QByteArray &message) = 0;
+};
+
+Q_DECLARE_INTERFACE(QQmlInspectorInterface, "com.trolltech.Qt.QQmlInspectorInterface/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINSPECTORINTERFACE_H
diff --git a/src/qml/debugger/qqmlinspectorservice.cpp b/src/qml/debugger/qqmlinspectorservice.cpp
new file mode 100644
index 0000000000..508d12eefa
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorservice.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlinspectorservice_p.h"
+#include "qqmlinspectorinterface_p.h"
+#include "qqmldebugserver_p.h"
+
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+
+// print detailed information about loading of plugins
+DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE)
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlInspectorService, serviceInstance)
+
+QQmlInspectorService::QQmlInspectorService()
+ : QQmlDebugService(QLatin1String("QQmlObserverMode"), 1)
+ , m_currentInspectorPlugin(0)
+{
+ registerService();
+}
+
+QQmlInspectorService *QQmlInspectorService::instance()
+{
+ return serviceInstance();
+}
+
+void QQmlInspectorService::addView(QObject *view)
+{
+ m_views.append(view);
+ updateState();
+}
+
+void QQmlInspectorService::removeView(QObject *view)
+{
+ m_views.removeAll(view);
+ updateState();
+}
+
+void QQmlInspectorService::sendMessage(const QByteArray &message)
+{
+ if (state() != Enabled)
+ return;
+
+ QQmlDebugService::sendMessage(message);
+}
+
+void QQmlInspectorService::stateChanged(State /*state*/)
+{
+ QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection);
+}
+
+void QQmlInspectorService::updateState()
+{
+ if (m_views.isEmpty()) {
+ if (m_currentInspectorPlugin) {
+ m_currentInspectorPlugin->deactivate();
+ m_currentInspectorPlugin = 0;
+ }
+ return;
+ }
+
+ if (state() == Enabled) {
+ if (m_inspectorPlugins.isEmpty())
+ loadInspectorPlugins();
+
+ if (m_inspectorPlugins.isEmpty()) {
+ qWarning() << "QQmlInspector: No plugins found.";
+ QQmlDebugServer::instance()->removeService(this);
+ return;
+ }
+
+ foreach (QQmlInspectorInterface *inspector, m_inspectorPlugins) {
+ if (inspector->canHandleView(m_views.first())) {
+ m_currentInspectorPlugin = inspector;
+ break;
+ }
+ }
+
+ if (!m_currentInspectorPlugin) {
+ qWarning() << "QQmlInspector: No plugin available for view '" << m_views.first()->metaObject()->className() << "'.";
+ return;
+ }
+ m_currentInspectorPlugin->activate(m_views.first());
+ } else {
+ if (m_currentInspectorPlugin) {
+ m_currentInspectorPlugin->deactivate();
+ m_currentInspectorPlugin = 0;
+ }
+ }
+}
+
+void QQmlInspectorService::messageReceived(const QByteArray &message)
+{
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+}
+
+void QQmlInspectorService::processMessage(const QByteArray &message)
+{
+ if (m_currentInspectorPlugin)
+ m_currentInspectorPlugin->clientMessage(message);
+}
+
+void QQmlInspectorService::loadInspectorPlugins()
+{
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists())
+ foreach (const QString &pluginPath, dir.entryList(QDir::Files))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Trying to load plugin " << pluginPath << "...";
+
+ QPluginLoader loader(pluginPath);
+ if (!loader.load()) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Error while loading: " << loader.errorString();
+
+ continue;
+ }
+
+ QQmlInspectorInterface *inspector =
+ qobject_cast<QQmlInspectorInterface*>(loader.instance());
+ if (inspector) {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Plugin successfully loaded.";
+ m_inspectorPlugins << inspector;
+ } else {
+ if (qmlDebugVerbose())
+ qDebug() << "QQmlInspector: Plugin does not implement interface QQmlInspectorInterface.";
+
+ loader.unload();
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlinspectorservice_p.h b/src/qml/debugger/qqmlinspectorservice_p.h
new file mode 100644
index 0000000000..557dc38aa8
--- /dev/null
+++ b/src/qml/debugger/qqmlinspectorservice_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLINSPECTORSERVICE_H
+#define QQMLINSPECTORSERVICE_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 "qqmldebugservice_p.h"
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QList>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlInspectorInterface;
+
+class Q_QML_EXPORT QQmlInspectorService : public QQmlDebugService
+{
+ Q_OBJECT
+
+public:
+ QQmlInspectorService();
+ static QQmlInspectorService *instance();
+
+ void addView(QObject *);
+ void removeView(QObject *);
+
+ void sendMessage(const QByteArray &message);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private slots:
+ void processMessage(const QByteArray &message);
+ void updateState();
+
+private:
+ void loadInspectorPlugins();
+
+ QList<QObject*> m_views;
+ QQmlInspectorInterface *m_currentInspectorPlugin;
+ QList<QQmlInspectorInterface*> m_inspectorPlugins;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLINSPECTORSERVICE_H
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
new file mode 100644
index 0000000000..d6a0307836
--- /dev/null
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlprofilerservice_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreapplication.h>
+
+// this contains QUnifiedTimer
+#include <private/qabstractanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance)
+
+QQmlBindingProfiler::QQmlBindingProfiler(const QString &url, int line, int column)
+{
+ QQmlProfilerService::startRange(QQmlProfilerService::Binding);
+ QQmlProfilerService::rangeLocation(QQmlProfilerService::Binding, url, line, column);
+}
+
+QQmlBindingProfiler::~QQmlBindingProfiler()
+{
+ QQmlProfilerService::endRange(QQmlProfilerService::Binding);
+}
+
+void QQmlBindingProfiler::addDetail(const QString &details)
+{
+ QQmlProfilerService::rangeData(QQmlProfilerService::Binding, details);
+}
+
+// convert to a QByteArray that can be sent to the debug client
+// use of QDataStream can skew results
+// (see tst_qqmldebugtrace::trace() benchmark)
+QByteArray QQmlProfilerData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << time << messageType << detailType;
+ if (messageType == (int)QQmlProfilerService::RangeData)
+ ds << detailData;
+ if (messageType == (int)QQmlProfilerService::RangeLocation)
+ ds << detailData << line << column;
+ if (messageType == (int)QQmlProfilerService::Event &&
+ detailType == (int)QQmlProfilerService::AnimationFrame)
+ ds << framerate << animationcount;
+ return data;
+}
+
+QQmlProfilerService::QQmlProfilerService()
+ : QQmlDebugService(QLatin1String("CanvasFrameRate"), 1),
+ m_enabled(false), m_messageReceived(false)
+{
+ m_timer.start();
+
+ if (registerService() == Enabled) {
+ // wait for first message indicating whether to trace or not
+ while (!m_messageReceived)
+ waitForMessage();
+
+ QUnifiedTimer::instance()->registerProfilerCallback( &animationFrame );
+ }
+}
+
+QQmlProfilerService::~QQmlProfilerService()
+{
+}
+
+void QQmlProfilerService::initialize()
+{
+ // just make sure that the service is properly registered
+ profilerInstance();
+}
+
+bool QQmlProfilerService::startProfiling()
+{
+ return profilerInstance()->startProfilingImpl();
+}
+
+bool QQmlProfilerService::stopProfiling()
+{
+ return profilerInstance()->stopProfilingImpl();
+}
+
+void QQmlProfilerService::sendStartedProfilingMessage()
+{
+ profilerInstance()->sendStartedProfilingMessageImpl();
+}
+
+void QQmlProfilerService::addEvent(EventType t)
+{
+ profilerInstance()->addEventImpl(t);
+}
+
+void QQmlProfilerService::startRange(RangeType t)
+{
+ profilerInstance()->startRangeImpl(t);
+}
+
+void QQmlProfilerService::rangeData(RangeType t, const QString &data)
+{
+ profilerInstance()->rangeDataImpl(t, data);
+}
+
+void QQmlProfilerService::rangeData(RangeType t, const QUrl &data)
+{
+ profilerInstance()->rangeDataImpl(t, data);
+}
+
+void QQmlProfilerService::rangeLocation(RangeType t, const QString &fileName, int line, int column)
+{
+ profilerInstance()->rangeLocationImpl(t, fileName, line, column);
+}
+
+void QQmlProfilerService::rangeLocation(RangeType t, const QUrl &fileName, int line, int column)
+{
+ profilerInstance()->rangeLocationImpl(t, fileName, line, column);
+}
+
+void QQmlProfilerService::endRange(RangeType t)
+{
+ profilerInstance()->endRangeImpl(t);
+}
+
+void QQmlProfilerService::animationFrame(qint64 delta)
+{
+ profilerInstance()->animationFrameImpl(delta);
+}
+
+void QQmlProfilerService::sendProfilingData()
+{
+ profilerInstance()->sendMessages();
+}
+
+bool QQmlProfilerService::startProfilingImpl()
+{
+ bool success = false;
+ if (!profilingEnabled()) {
+ setProfilingEnabled(true);
+ sendStartedProfilingMessageImpl();
+ success = true;
+ }
+ return success;
+}
+
+bool QQmlProfilerService::stopProfilingImpl()
+{
+ bool success = false;
+ if (profilingEnabled()) {
+ addEventImpl(EndTrace);
+ setProfilingEnabled(false);
+ success = true;
+ }
+ return success;
+}
+
+void QQmlProfilerService::sendStartedProfilingMessageImpl()
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)StartTrace, QString(), -1, -1, 0, 0};
+ QQmlDebugService::sendMessage(ed.toByteArray());
+}
+
+void QQmlProfilerService::addEventImpl(EventType event)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)event, QString(), -1, -1, 0, 0};
+ processMessage(ed);
+}
+
+void QQmlProfilerService::startRangeImpl(RangeType range)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeStart, (int)range, QString(), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeDataImpl(RangeType range, const QString &rData)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData, -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeDataImpl(RangeType range, const QUrl &rData)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeLocationImpl(RangeType range, const QString &fileName, int line, int column)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName, line, column, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::rangeLocationImpl(RangeType range, const QUrl &fileName, int line, int column)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line, column, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::endRangeImpl(RangeType range)
+{
+ if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
+ return;
+
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeEnd, (int)range, QString(), -1, -1, 0, 0};
+ processMessage(rd);
+}
+
+void QQmlProfilerService::animationFrameImpl(qint64 delta)
+{
+ Q_ASSERT(QQmlDebugService::isDebuggingEnabled());
+ if (!m_enabled)
+ return;
+
+ int animCount = QUnifiedTimer::instance()->runningAnimationCount();
+
+ if (animCount > 0 && delta > 0) {
+ // trim fps to integer
+ int fps = 1000 / delta;
+ QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)AnimationFrame, QString(), -1, -1, fps, animCount};
+ processMessage(ed);
+ }
+}
+
+/*
+ Either send the message directly, or queue up
+ a list of messages to send later (via sendMessages)
+*/
+void QQmlProfilerService::processMessage(const QQmlProfilerData &message)
+{
+ QMutexLocker locker(&m_mutex);
+ m_data.append(message);
+}
+
+bool QQmlProfilerService::profilingEnabled()
+{
+ return m_enabled;
+}
+
+void QQmlProfilerService::setProfilingEnabled(bool enable)
+{
+ m_enabled = enable;
+}
+
+/*
+ Send the messages queued up by processMessage
+*/
+void QQmlProfilerService::sendMessages()
+{
+ QMutexLocker locker(&m_mutex);
+ QList<QByteArray> messages;
+ for (int i = 0; i < m_data.count(); ++i)
+ messages << m_data.at(i).toByteArray();
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (qint64)-1 << (int)Complete;
+ messages << data;
+
+ QQmlDebugService::sendMessages(messages);
+}
+
+void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
+{
+ if (state() == newState)
+ return;
+
+ if (state() == Enabled
+ && m_enabled) {
+ stopProfilingImpl();
+ sendMessages();
+ }
+}
+
+void QQmlProfilerService::messageReceived(const QByteArray &message)
+{
+ QByteArray rwData = message;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ bool enabled;
+ stream >> enabled;
+
+ m_messageReceived = true;
+
+ if (enabled) {
+ startProfilingImpl();
+ } else {
+ if (stopProfilingImpl())
+ sendMessages();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
new file mode 100644
index 0000000000..a74ce10c74
--- /dev/null
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROFILERSERVICE_P_H
+#define QQMLPROFILERSERVICE_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/qqmldebugservice_p.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct Q_AUTOTEST_EXPORT QQmlProfilerData
+{
+ qint64 time;
+ int messageType;
+ int detailType;
+
+ //###
+ QString detailData; //used by RangeData and RangeLocation
+ int line; //used by RangeLocation
+ int column; //used by RangeLocation
+ int framerate; //used by animation events
+ int animationcount; //used by animation events
+
+ QByteArray toByteArray() const;
+};
+
+Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
+
+class QUrl;
+class QQmlEngine;
+
+// RAII
+class Q_AUTOTEST_EXPORT QQmlBindingProfiler {
+public:
+ QQmlBindingProfiler(const QString &url, int line, int column);
+ ~QQmlBindingProfiler();
+ void addDetail(const QString &details);
+};
+
+class Q_QML_EXPORT QQmlProfilerService : public QQmlDebugService
+{
+public:
+ enum Message {
+ Event,
+ RangeStart,
+ RangeData,
+ RangeLocation,
+ RangeEnd,
+ Complete, // end of transmission
+
+ MaximumMessage
+ };
+
+ enum EventType {
+ FramePaint,
+ Mouse,
+ Key,
+ AnimationFrame,
+ EndTrace,
+ StartTrace,
+
+ MaximumEventType
+ };
+
+ enum RangeType {
+ Painting,
+ Compiling,
+ Creating,
+ Binding, //running a binding
+ HandlingSignal, //running a signal handler
+
+ MaximumRangeType
+ };
+
+ static void initialize();
+
+ static bool startProfiling();
+ static bool stopProfiling();
+ static void sendStartedProfilingMessage();
+ 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, int);
+ static void rangeLocation(RangeType, const QUrl &, int, int);
+ static void endRange(RangeType);
+ static void animationFrame(qint64);
+
+ static void sendProfilingData();
+
+ QQmlProfilerService();
+ ~QQmlProfilerService();
+
+protected:
+ virtual void stateAboutToBeChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ bool startProfilingImpl();
+ bool stopProfilingImpl();
+ void sendStartedProfilingMessageImpl();
+ void addEventImpl(EventType);
+ void startRangeImpl(RangeType);
+ void rangeDataImpl(RangeType, const QString &);
+ void rangeDataImpl(RangeType, const QUrl &);
+ void rangeLocationImpl(RangeType, const QString &, int, int);
+ void rangeLocationImpl(RangeType, const QUrl &, int, int);
+ void endRangeImpl(RangeType);
+ void animationFrameImpl(qint64);
+
+ bool profilingEnabled();
+ void setProfilingEnabled(bool enable);
+ void sendMessages();
+ void processMessage(const QQmlProfilerData &);
+
+private:
+ QElapsedTimer m_timer;
+ bool m_enabled;
+ bool m_messageReceived;
+ QVector<QQmlProfilerData> m_data;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLPROFILERSERVICE_P_H
+
diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp
new file mode 100644
index 0000000000..ee60bff742
--- /dev/null
+++ b/src/qml/debugger/qv8debugservice.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8debugservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include <private/qjsconverter_impl_p.h>
+#include <private/qv8engine_p.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QFileInfo>
+#include <QtCore/QMutex>
+
+//V8 DEBUG SERVICE PROTOCOL
+// <HEADER><COMMAND><DATA>
+// <HEADER> : "V8DEBUG"
+// <COMMAND> : ["connect", "disconnect", "interrupt",
+// "v8request", "v8message", "breakonsignal",
+// "breakaftercompile"]
+// <DATA> : connect, disconnect, interrupt: empty
+// v8request, v8message: <JSONrequest_string>
+// breakonsignal: <signalname_string><enabled_bool>
+// breakaftercompile: <enabled_bool>
+
+const char *V8_DEBUGGER_KEY_VERSION = "version";
+const char *V8_DEBUGGER_KEY_CONNECT = "connect";
+const char *V8_DEBUGGER_KEY_INTERRUPT = "interrupt";
+const char *V8_DEBUGGER_KEY_DISCONNECT = "disconnect";
+const char *V8_DEBUGGER_KEY_REQUEST = "v8request";
+const char *V8_DEBUGGER_KEY_V8MESSAGE = "v8message";
+const char *V8_DEBUGGER_KEY_BREAK_ON_SIGNAL = "breakonsignal";
+const char *V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE = "breakaftercompile";
+
+QT_BEGIN_NAMESPACE
+
+struct SignalHandlerData
+{
+ QString functionName;
+ bool enabled;
+};
+
+Q_GLOBAL_STATIC(QV8DebugService, v8ServiceInstance)
+
+// DebugMessageHandler will call back already when the QV8DebugService constructor is
+// running, we therefore need a plain pointer.
+static QV8DebugService *v8ServiceInstancePtr = 0;
+
+void DebugMessageDispatchHandler()
+{
+ QMetaObject::invokeMethod(v8ServiceInstancePtr, "processDebugMessages", Qt::QueuedConnection);
+}
+
+void DebugMessageHandler(const v8::Debug::Message& message)
+{
+ v8::DebugEvent event = message.GetEvent();
+
+ if (event != v8::Break && event != v8::Exception &&
+ event != v8::AfterCompile && event != v8::BeforeCompile)
+ return;
+ v8ServiceInstancePtr->debugMessageHandler(QJSConverter::toString(message.GetJSON()), event);
+}
+
+class QV8DebugServicePrivate : public QQmlDebugServicePrivate
+{
+public:
+ QV8DebugServicePrivate()
+ : connectReceived(false)
+ , breakAfterCompile(false)
+ , engine(0)
+ {
+ }
+
+ void initializeDebuggerThread();
+
+ static QByteArray packMessage(const QString &type, const QString &message = QString());
+
+ bool connectReceived;
+ bool breakAfterCompile;
+ QMutex initializeMutex;
+ QStringList breakOnSignals;
+ const QV8Engine *engine;
+};
+
+QV8DebugService::QV8DebugService(QObject *parent)
+ : QQmlDebugService(*(new QV8DebugServicePrivate()),
+ QLatin1String("V8Debugger"), 2, parent)
+{
+ Q_D(QV8DebugService);
+ v8ServiceInstancePtr = this;
+ // wait for stateChanged() -> initialize()
+ d->initializeMutex.lock();
+ if (registerService() == Enabled) {
+ init();
+ // ,block mode, client attached
+ while (!d->connectReceived) {
+ waitForMessage();
+ }
+ } else {
+ d->initializeMutex.unlock();
+ }
+}
+
+QV8DebugService::~QV8DebugService()
+{
+}
+
+QV8DebugService *QV8DebugService::instance()
+{
+ return v8ServiceInstance();
+}
+
+void QV8DebugService::initialize(const QV8Engine *engine)
+{
+ // just make sure that the service is properly registered
+ v8ServiceInstance()->setEngine(engine);
+}
+
+void QV8DebugService::setEngine(const QV8Engine *engine)
+{
+ Q_D(QV8DebugService);
+
+ d->engine = engine;
+}
+
+void QV8DebugService::debugMessageHandler(const QString &message, const v8::DebugEvent &event)
+{
+ Q_D(QV8DebugService);
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_V8MESSAGE), message));
+ if (event == v8::AfterCompile && d->breakAfterCompile)
+ scheduledDebugBreak(true);
+}
+
+void QV8DebugService::signalEmitted(const QString &signal)
+{
+ //This function is only called by QQmlBoundSignal
+ //only if there is a slot connected to the signal. Hence, there
+ //is no need for additional check.
+ Q_D(QV8DebugService);
+
+ //Parse just the name and remove the class info
+ //Normalize to Lower case.
+ QString signalName = signal.left(signal.indexOf(QLatin1String("("))).toLower();
+
+ foreach (const QString &signal, d->breakOnSignals) {
+ if (signal == signalName) {
+ scheduledDebugBreak(true);
+ break;
+ }
+ }
+}
+
+// executed in the gui thread
+void QV8DebugService::init()
+{
+ Q_D(QV8DebugService);
+ v8::Debug::SetMessageHandler2(DebugMessageHandler);
+ v8::Debug::SetDebugMessageDispatchHandler(DebugMessageDispatchHandler);
+ d->initializeMutex.unlock();
+}
+
+// executed in the gui thread
+void QV8DebugService::scheduledDebugBreak(bool schedule)
+{
+ if (schedule)
+ v8::Debug::DebugBreak();
+ else
+ v8::Debug::CancelDebugBreak();
+}
+
+// executed in the debugger thread
+void QV8DebugService::stateChanged(QQmlDebugService::State newState)
+{
+ Q_D(QV8DebugService);
+ if (newState == Enabled) {
+ // execute in GUI thread
+ d->initializeMutex.lock();
+ QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
+ }
+}
+
+// executed in the debugger thread
+void QV8DebugService::messageReceived(const QByteArray &message)
+{
+ Q_D(QV8DebugService);
+
+ QDataStream ds(message);
+ QByteArray header;
+ ds >> header;
+
+ if (header == "V8DEBUG") {
+ QByteArray command;
+ QByteArray data;
+ ds >> command >> data;
+
+ if (command == V8_DEBUGGER_KEY_CONNECT) {
+ QMutexLocker locker(&d->initializeMutex);
+ d->connectReceived = true;
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_CONNECT)));
+
+ } else if (command == V8_DEBUGGER_KEY_INTERRUPT) {
+ // break has to be executed in gui thread
+ QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection, Q_ARG(bool, true));
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_INTERRUPT)));
+
+ } else if (command == V8_DEBUGGER_KEY_DISCONNECT) {
+ // cancel break has to be executed in gui thread
+ QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection, Q_ARG(bool, false));
+ sendDebugMessage(QString::fromUtf8(data));
+
+ } else if (command == V8_DEBUGGER_KEY_REQUEST) {
+ sendDebugMessage(QString::fromUtf8(data));
+
+ } else if (command == V8_DEBUGGER_KEY_BREAK_ON_SIGNAL) {
+ QDataStream rs(data);
+ QByteArray signal;
+ bool enabled;
+ rs >> signal >> enabled;
+ //Normalize to lower case.
+ QString signalName(QString::fromUtf8(signal).toLower());
+ if (enabled)
+ d->breakOnSignals.append(signalName);
+ else
+ d->breakOnSignals.removeOne(signalName);
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_ON_SIGNAL)));
+
+ } else if (command == V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE) {
+ QDataStream rs(data);
+ rs >> d->breakAfterCompile;
+ sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_AFTER_COMPILE)));
+
+ }
+ }
+}
+
+void QV8DebugService::sendDebugMessage(const QString &message)
+{
+ v8::Debug::SendCommand(message.utf16(), message.size());
+}
+
+void QV8DebugService::processDebugMessages()
+{
+ Q_D(QV8DebugService);
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(d->engine->context());
+ v8::Debug::ProcessDebugMessages();
+}
+
+QByteArray QV8DebugServicePrivate::packMessage(const QString &type, const QString &message)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ QByteArray cmd("V8DEBUG");
+ rs << cmd << type.toUtf8() << message.toUtf8();
+ return reply;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qv8debugservice_p.h b/src/qml/debugger/qv8debugservice_p.h
new file mode 100644
index 0000000000..8ff4adc778
--- /dev/null
+++ b/src/qml/debugger/qv8debugservice_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8DEBUGSERVICE_P_H
+#define QV8DEBUGSERVICE_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 "qqmldebugservice_p.h"
+#include <private/qv8debug_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QV8Engine;
+class QV8DebugServicePrivate;
+
+class QV8DebugService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QV8DebugService(QObject *parent = 0);
+ ~QV8DebugService();
+
+ static QV8DebugService *instance();
+ static void initialize(const QV8Engine *engine);
+
+ void debugMessageHandler(const QString &message, const v8::DebugEvent &event);
+
+ void signalEmitted(const QString &signal);
+
+public slots:
+ void processDebugMessages();
+
+private slots:
+ void scheduledDebugBreak(bool schedule);
+ void sendDebugMessage(const QString &message);
+ void init();
+
+protected:
+ void stateChanged(State newState);
+ void messageReceived(const QByteArray &);
+
+private:
+ void setEngine(const QV8Engine *engine);
+
+private:
+ Q_DISABLE_COPY(QV8DebugService)
+ Q_DECLARE_PRIVATE(QV8DebugService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8DEBUGSERVICE_P_H
diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp
new file mode 100644
index 0000000000..eba8b0feef
--- /dev/null
+++ b/src/qml/debugger/qv8profilerservice.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8profilerservice_p.h"
+#include "qqmldebugservice_p_p.h"
+#include "private/qjsconverter_impl_p.h"
+#include <private/qv8profiler_p.h>
+
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance)
+
+class DebugServiceOutputStream : public v8::OutputStream
+{
+ QQmlDebugService &_service;
+public:
+ DebugServiceOutputStream(QQmlDebugService &service)
+ : v8::OutputStream(),
+ _service(service) {}
+ void EndOfStream() {}
+ WriteResult WriteAsciiChunk(char *rawData, int size)
+ {
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << QV8ProfilerService::V8SnapshotChunk << QByteArray(rawData, size);
+ _service.sendMessage(data);
+ return kContinue;
+ }
+};
+
+// convert to a QByteArray that can be sent to the debug client
+QByteArray QV8ProfilerData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
+
+ return data;
+}
+
+class QV8ProfilerServicePrivate : public QQmlDebugServicePrivate
+{
+ Q_DECLARE_PUBLIC(QV8ProfilerService)
+
+public:
+ QV8ProfilerServicePrivate()
+ :initialized(false)
+ {
+ }
+
+ void takeSnapshot(v8::HeapSnapshot::Type);
+
+ void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
+ void sendMessages();
+
+ QList<QV8ProfilerData> m_data;
+
+ bool initialized;
+ QList<QString> m_ongoing;
+};
+
+QV8ProfilerService::QV8ProfilerService(QObject *parent)
+ : QQmlDebugService(*(new QV8ProfilerServicePrivate()), QLatin1String("V8Profiler"), 1, parent)
+{
+ Q_D(QV8ProfilerService);
+
+ if (registerService() == Enabled) {
+ // ,block mode, client attached
+ while (!d->initialized)
+ waitForMessage();
+ }
+}
+
+QV8ProfilerService::~QV8ProfilerService()
+{
+}
+
+QV8ProfilerService *QV8ProfilerService::instance()
+{
+ return v8ProfilerInstance();
+}
+
+void QV8ProfilerService::initialize()
+{
+ // just make sure that the service is properly registered
+ v8ProfilerInstance();
+}
+
+void QV8ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
+{
+ Q_D(QV8ProfilerService);
+
+ if (state() == newState)
+ return;
+
+ if (state() == Enabled) {
+ foreach (const QString &title, d->m_ongoing)
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, title));
+ sendProfilingData();
+ }
+}
+
+void QV8ProfilerService::messageReceived(const QByteArray &message)
+{
+ Q_D(QV8ProfilerService);
+
+ QDataStream ds(message);
+ QByteArray command;
+ QByteArray option;
+ QByteArray title;
+ ds >> command >> option;
+
+ if (command == "V8PROFILER") {
+ ds >> title;
+ QString titleStr = QString::fromUtf8(title);
+ if (option == "start") {
+ QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ } else if (option == "stop" && d->initialized) {
+ QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
+ QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
+ }
+ d->initialized = true;
+ }
+
+ if (command == "V8SNAPSHOT") {
+ if (option == "full")
+ QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
+ else if (option == "delete") {
+ QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
+ }
+ }
+
+ QQmlDebugService::messageReceived(message);
+}
+
+void QV8ProfilerService::startProfiling(const QString &title)
+{
+ Q_D(QV8ProfilerService);
+ // Start Profiling
+
+ if (d->m_ongoing.contains(title))
+ return;
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ v8::CpuProfiler::StartProfiling(v8title);
+
+ d->m_ongoing.append(title);
+}
+
+void QV8ProfilerService::stopProfiling(const QString &title)
+{
+ Q_D(QV8ProfilerService);
+ // Stop profiling
+
+ if (!d->m_ongoing.contains(title))
+ return;
+ d->m_ongoing.removeOne(title);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
+ const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
+ if (cpuProfile) {
+ // can happen at start
+ const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
+ d->printProfileTree(rootNode);
+ }
+}
+
+void QV8ProfilerService::takeSnapshot()
+{
+ Q_D(QV8ProfilerService);
+ d->takeSnapshot(v8::HeapSnapshot::kFull);
+}
+
+void QV8ProfilerService::deleteSnapshots()
+{
+ v8::HeapProfiler::DeleteAllSnapshots();
+}
+
+void QV8ProfilerService::sendProfilingData()
+{
+ Q_D(QV8ProfilerService);
+ // Send messages to client
+ d->sendMessages();
+}
+
+void QV8ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
+{
+ for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
+ const v8::CpuProfileNode* childNode = node->GetChild(index);
+ QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
+ if (scriptResourceName.length() > 0) {
+
+ QV8ProfilerData rd = {(int)QV8ProfilerService::V8Entry, scriptResourceName,
+ QJSConverter::toString(childNode->GetFunctionName()),
+ childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
+ m_data.append(rd);
+
+ // different nodes might have common children: fix at client side
+ if (childNode->GetChildrenCount() > 0) {
+ printProfileTree(childNode, level+1);
+ }
+ }
+ }
+}
+
+void QV8ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
+{
+ Q_Q(QV8ProfilerService);
+
+ v8::HandleScope scope;
+ v8::Local<v8::String> title = v8::String::New("");
+
+ DebugServiceOutputStream outputStream(*q);
+ const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
+ snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV8ProfilerService::V8SnapshotComplete;
+
+ q->sendMessage(data);
+}
+
+void QV8ProfilerServicePrivate::sendMessages()
+{
+ Q_Q(QV8ProfilerService);
+
+ QList<QByteArray> messages;
+ for (int i = 0; i < m_data.count(); ++i)
+ messages << m_data.at(i).toByteArray();
+ q->sendMessages(messages);
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)QV8ProfilerService::V8Complete;
+
+ q->sendMessage(data);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/debugger/qv8profilerservice_p.h b/src/qml/debugger/qv8profilerservice_p.h
new file mode 100644
index 0000000000..d408d9ed0e
--- /dev/null
+++ b/src/qml/debugger/qv8profilerservice_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8PROFILERSERVICE_P_H
+#define QV8PROFILERSERVICE_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/qqmldebugservice_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+struct Q_AUTOTEST_EXPORT QV8ProfilerData
+{
+ int messageType;
+ QString filename;
+ QString functionname;
+ int lineNumber;
+ double totalTime;
+ double selfTime;
+ int treeLevel;
+
+ QByteArray toByteArray() const;
+};
+
+class QQmlEngine;
+class QV8ProfilerServicePrivate;
+
+class Q_AUTOTEST_EXPORT QV8ProfilerService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ enum MessageType {
+ V8Entry,
+ V8Complete,
+ V8SnapshotChunk,
+ V8SnapshotComplete,
+
+ V8MaximumMessage
+ };
+
+ QV8ProfilerService(QObject *parent = 0);
+ ~QV8ProfilerService();
+
+ static QV8ProfilerService *instance();
+ static void initialize();
+
+public slots:
+ void startProfiling(const QString &title);
+ void stopProfiling(const QString &title);
+ void takeSnapshot();
+ void deleteSnapshots();
+
+ void sendProfilingData();
+
+protected:
+ void stateAboutToBeChanged(State state);
+ void messageReceived(const QByteArray &);
+
+private:
+ Q_DISABLE_COPY(QV8ProfilerService)
+ Q_DECLARE_PRIVATE(QV8ProfilerService)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QV8PROFILERSERVICE_P_H
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
new file mode 100644
index 0000000000..0bbfc9ff74
--- /dev/null
+++ b/src/qml/qml.pro
@@ -0,0 +1,37 @@
+load(qt_module)
+
+TARGET = QtQml
+QPRO_PWD = $$PWD
+
+CONFIG += module
+MODULE_PRI += ../../modules/qt_qml.pri
+
+QT = core-private gui gui-private network v8-private
+
+DEFINES += QT_BUILD_QML_LIB QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
+
+win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
+solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
+
+unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui
+
+exists("qqml_enable_gcov") {
+ QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
+ LIBS += -lgcov
+}
+
+load(qt_module_config)
+
+HEADERS += qtqmlversion.h \
+ qtqmlglobal.h \
+ qtqmlglobal_p.h
+
+#INCLUDEPATH -= $$QMAKE_INCDIR_QT/$$TARGET
+#DESTDIR=.
+
+#modules
+include(util/util.pri)
+include(qml/qml.pri)
+include(debugger/debugger.pri)
+include(animations/animations.pri)
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
new file mode 100644
index 0000000000..f2fec4e2dd
--- /dev/null
+++ b/src/qml/qml/ftw/ftw.pri
@@ -0,0 +1,29 @@
+HEADERS += \
+ $$PWD/qbitfield_p.h \
+ $$PWD/qintrusivelist_p.h \
+ $$PWD/qpodvector_p.h \
+ $$PWD/qhashedstring_p.h \
+ $$PWD/qqmlrefcount_p.h \
+ $$PWD/qqmlpool_p.h \
+ $$PWD/qfieldlist_p.h \
+ $$PWD/qfastmetabuilder_p.h \
+ $$PWD/qhashfield_p.h \
+ $$PWD/qqmlthread_p.h \
+ $$PWD/qfinitestack_p.h \
+ $$PWD/qrecursionwatcher_p.h \
+ $$PWD/qdeletewatcher_p.h \
+ $$PWD/qrecyclepool_p.h \
+ $$PWD/qflagpointer_p.h \
+ $$PWD/qqmltrace_p.h \
+ $$PWD/qpointervaluepair_p.h \
+ $$PWD/qlazilyallocated_p.h \
+
+SOURCES += \
+ $$PWD/qintrusivelist.cpp \
+ $$PWD/qhashedstring.cpp \
+ $$PWD/qqmlpool.cpp \
+ $$PWD/qfastmetabuilder.cpp \
+ $$PWD/qqmlthread.cpp \
+ $$PWD/qqmltrace.cpp \
+
+contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h
new file mode 100644
index 0000000000..75f80dd896
--- /dev/null
+++ b/src/qml/qml/ftw/qbitfield_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/ftw/qdeletewatcher_p.h
new file mode 100644
index 0000000000..9f7b100429
--- /dev/null
+++ b/src/qml/qml/ftw/qdeletewatcher_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDELETEWATCHER_P_H
+#define QDELETEWATCHER_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 QDeleteWatchable
+{
+public:
+ inline QDeleteWatchable();
+ inline ~QDeleteWatchable();
+private:
+ friend class QDeleteWatcher;
+ bool *_w;
+};
+
+class QDeleteWatcher {
+public:
+ inline QDeleteWatcher(QDeleteWatchable *data);
+ inline ~QDeleteWatcher();
+ inline bool wasDeleted() const;
+private:
+ void *operator new(size_t);
+ bool *_w;
+ bool _s;
+ QDeleteWatchable *m_d;
+};
+
+QDeleteWatchable::QDeleteWatchable()
+: _w(0)
+{
+}
+
+QDeleteWatchable::~QDeleteWatchable()
+{
+ if (_w) *_w = true;
+}
+
+QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data)
+: _s(false), m_d(data)
+{
+ if (!m_d->_w)
+ m_d->_w = &_s;
+ _w = m_d->_w;
+}
+
+QDeleteWatcher::~QDeleteWatcher()
+{
+ if (false == *_w && &_s == m_d->_w)
+ m_d->_w = 0;
+}
+
+bool QDeleteWatcher::wasDeleted() const
+{
+ return *_w;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDELETEWATCHER_P_H
diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp
new file mode 100644
index 0000000000..9663c1e944
--- /dev/null
+++ b/src/qml/qml/ftw/qfastmetabuilder.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfastmetabuilder_p.h"
+
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QFastMetaBuilderHeader
+{
+ int fieldCount;
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData; //since revision 2
+ int flags; //since revision 3
+ int signalCount; //since revision 4
+};
+
+enum MetaObjectFlag {
+ DynamicMetaObject = 0x01
+};
+
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
+ 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
+};
+
+#define FMBHEADER_FIELD_COUNT 1
+
+#define HEADER_FIELD_COUNT 14
+#define CLASSINFO_FIELD_COUNT 2
+#define METHOD_FIELD_COUNT 5
+#define PROPERTY_FIELD_COUNT 3
+#define PROPERTY_NOTIFY_FIELD_COUNT 1
+
+static inline uint *fieldPointer(QByteArray &data)
+{ return reinterpret_cast<uint *>(data.data()) + FMBHEADER_FIELD_COUNT; }
+
+static inline const uint *fieldPointer(const QByteArray &data)
+{ return reinterpret_cast<const uint *>(data.constData()) + FMBHEADER_FIELD_COUNT; }
+
+static inline QMetaObjectPrivate *priv(QByteArray &data)
+{ return reinterpret_cast<QMetaObjectPrivate*>(fieldPointer(data)); }
+
+static inline const QMetaObjectPrivate *priv(const QByteArray &data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(fieldPointer(data)); }
+
+static inline QFastMetaBuilderHeader *header(QByteArray &data)
+{ return reinterpret_cast<QFastMetaBuilderHeader*>(data.data()); }
+
+static inline const QFastMetaBuilderHeader *header(const QByteArray &data)
+{ return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); }
+
+QFastMetaBuilder::QFastMetaBuilder()
+: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0)
+{
+}
+
+QFastMetaBuilder::~QFastMetaBuilder()
+{
+}
+
+QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength,
+ int propertyCount, int methodCount,
+ int signalCount, int classInfoCount)
+{
+ Q_ASSERT(m_data.isEmpty());
+ Q_ASSERT(classNameLength > 0);
+ Q_ASSERT(propertyCount >= 0);
+ Q_ASSERT(methodCount >= 0);
+ Q_ASSERT(signalCount >= 0);
+ Q_ASSERT(classInfoCount >= 0);
+
+ int fieldCount = FMBHEADER_FIELD_COUNT +
+ HEADER_FIELD_COUNT +
+ propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) +
+ methodCount * (METHOD_FIELD_COUNT) +
+ signalCount * (METHOD_FIELD_COUNT) +
+ classInfoCount * CLASSINFO_FIELD_COUNT;
+
+ m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1);
+ m_stringData = m_data.data() + m_data.size() - classNameLength - 1;
+ m_stringDataLength = classNameLength + 1;
+ m_stringDataAllocated = classNameLength + 1;
+ m_stringData[classNameLength] = 0;
+ m_zeroPtr = classNameLength;
+
+ header(m_data)->fieldCount = fieldCount;
+
+ QMetaObjectPrivate *p = priv(m_data);
+
+ int dataIndex = HEADER_FIELD_COUNT;
+
+ p->revision = 4;
+ p->className = 0;
+
+ // Class infos
+ p->classInfoCount = classInfoCount;
+ if (p->classInfoCount) {
+ p->classInfoData = dataIndex;
+ dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT;
+ } else {
+ p->classInfoData = 0;
+ }
+
+ // Methods
+ p->methodCount = methodCount + signalCount;
+ if (p->methodCount) {
+ p->methodData = dataIndex;
+ dataIndex += p->methodCount * METHOD_FIELD_COUNT;
+ } else {
+ p->methodData = 0;
+ }
+ p->signalCount = signalCount;
+
+ // Properties
+ p->propertyCount = propertyCount;
+ if (p->propertyCount) {
+ p->propertyData = dataIndex;
+ dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT);
+ } else {
+ p->propertyData = 0;
+ }
+
+ // Flags
+ p->flags = DynamicMetaObject; // Always dynamic
+
+ // Enums and constructors not supported
+ p->enumeratorCount = 0;
+ p->enumeratorData = 0;
+ p->constructorCount = 0;
+ p->constructorData = 0;
+
+ StringRef className;
+ className._b = this;
+ className._o = 0;
+ className._l = classNameLength;
+ return className;
+}
+
+// Allocate a string of \a length. \a length should *not* include the null terminator.
+QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length)
+{
+ Q_ASSERT(length > 0);
+
+ StringRef sr;
+ sr._b = this;
+ sr._o = m_stringDataLength;
+ sr._l = length;
+
+ m_stringDataLength += length + 1 /* for null terminator */;
+
+ return sr;
+}
+
+void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!key.isEmpty() && !value.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->classInfoCount);
+
+ uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT;
+ // classinfo: key, value
+ ptr[0] = key.offset(); ptr[1] = value.offset();
+}
+
+void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type,
+ QMetaType::Type mtype, PropertyFlag flags, int notifySignal)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!name.isEmpty() && !type.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->propertyCount);
+
+ uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
+ // properties: name, type, flags
+ ptr[0] = name.offset();
+ ptr[1] = type.offset();
+ if (notifySignal == -1) {
+ ptr[2] = mtype << 24;
+ ptr[2] |= flags | Scriptable | Readable;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
+ } else {
+ ptr[2] = mtype << 24;
+ ptr[2] |= flags | Scriptable | Readable | Notify;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
+ }
+}
+
+void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type,
+ QFastMetaBuilder::PropertyFlag flags, int notifySignal)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!name.isEmpty() && !type.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < p->propertyCount);
+
+ uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT;
+ // properties: name, type, flags
+ ptr[0] = name.offset();
+ ptr[1] = type.offset();
+ if (notifySignal == -1) {
+ ptr[2] = flags | Scriptable | Readable;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0;
+ } else {
+ ptr[2] = flags | Scriptable | Readable | Notify;
+ *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal;
+ }
+}
+
+void QFastMetaBuilder::setSignal(int index, const StringRef &signature,
+ const StringRef &parameterNames,
+ const StringRef &type)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!signature.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ int mindex = metaObjectIndexForSignal(index);
+
+ uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
+ // methods: signature, parameters, type, tag, flags
+ ptr[0] = signature.offset();
+ ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
+ ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
+ ptr[3] = m_zeroPtr;
+ ptr[4] = AccessProtected | MethodSignal;
+}
+
+void QFastMetaBuilder::setMethod(int index, const StringRef &signature,
+ const StringRef &parameterNames,
+ const StringRef &type)
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(!signature.isEmpty());
+
+ QMetaObjectPrivate *p = priv(m_data);
+ int mindex = metaObjectIndexForMethod(index);
+
+ uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT;
+ // methods: signature, parameters, type, tag, flags
+ ptr[0] = signature.offset();
+ ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset();
+ ptr[2] = type.isEmpty()?m_zeroPtr:type.offset();
+ ptr[3] = m_zeroPtr;
+ ptr[4] = AccessProtected | MethodSlot;
+}
+
+int QFastMetaBuilder::metaObjectIndexForSignal(int index) const
+{
+ Q_ASSERT(!m_data.isEmpty());
+ Q_ASSERT(index < priv(m_data)->signalCount);
+ return index;
+}
+
+int QFastMetaBuilder::metaObjectIndexForMethod(int index) const
+{
+ Q_ASSERT(!m_data.isEmpty());
+
+ const QMetaObjectPrivate *p = priv(m_data);
+ Q_ASSERT(index < (p->methodCount - p->signalCount));
+ return index + p->signalCount;
+}
+
+void QFastMetaBuilder::allocateStringData()
+{
+ if (m_stringDataAllocated < m_stringDataLength) {
+ m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated);
+ m_stringDataAllocated = m_stringDataLength;
+ m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint);
+ }
+}
+
+void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data)
+{
+ output->d.superdata = parent;
+ output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint);
+ output->d.data = fieldPointer(data);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h
new file mode 100644
index 0000000000..c1f6a3de5c
--- /dev/null
+++ b/src/qml/qml/ftw/qfastmetabuilder_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFASTMETABUILDER_P_H
+#define QFASTMETABUILDER_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>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qmetaobject.h>
+
+#include <private/qhashedstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QMetaObject;
+class QFastMetaBuilder
+{
+public:
+ QFastMetaBuilder();
+ ~QFastMetaBuilder();
+
+ struct StringRef {
+ public:
+ inline StringRef();
+ inline StringRef(const StringRef &);
+ inline StringRef &operator=(const StringRef &);
+
+ inline void load(const QHashedStringRef &);
+ inline void load(const QByteArray &);
+ inline void load(const char *);
+
+ inline bool isEmpty() const;
+ inline QFastMetaBuilder *builder() const;
+ inline int offset() const;
+ inline char *data();
+ inline int length() const;
+ private:
+ friend class QFastMetaBuilder;
+
+ QFastMetaBuilder *_b;
+ int _o;
+ int _l;
+ };
+ StringRef newString(int length);
+
+ // Returns class name
+ StringRef init(int classNameLength,
+ int propertyCount, int methodCount,
+ int signalCount, int classInfoCount);
+
+ void setClassInfo(int index, const StringRef &key, const StringRef &value);
+
+ enum PropertyFlag {
+ None = 0x00000000,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ Constant = 0x00000400,
+ Final = 0x00000800
+ };
+ // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1);
+ void setProperty(int index, const StringRef &name, const StringRef &type,
+ QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1);
+ void setProperty(int index, const StringRef &name, const StringRef &type,
+ PropertyFlag flags, int notifySignal = -1);
+ void setMethod(int index, const StringRef &signature,
+ const StringRef &parameterNames = StringRef(),
+ const StringRef &type = StringRef());
+ void setSignal(int index, const StringRef &signature,
+ const StringRef &parameterNames = StringRef(),
+ const StringRef &type = StringRef());
+
+ int metaObjectIndexForSignal(int) const;
+ int metaObjectIndexForMethod(int) const;
+
+ QByteArray toData() const { return m_data; }
+ static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &);
+private:
+ friend struct StringRef;
+
+ QByteArray m_data;
+ int m_zeroPtr;
+
+ void allocateStringData();
+ char *m_stringData;
+ int m_stringDataLength;
+ int m_stringDataAllocated;
+};
+
+QFastMetaBuilder::StringRef::StringRef()
+: _b(0), _o(0), _l(0)
+{
+}
+
+QFastMetaBuilder::StringRef::StringRef(const StringRef &o)
+: _b(o._b), _o(o._o), _l(o._l)
+{
+}
+
+QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o)
+{
+ _b = o._b;
+ _o = o._o;
+ _l = o._l;
+ return *this;
+}
+
+bool QFastMetaBuilder::StringRef::isEmpty() const
+{
+ return _l == 0;
+}
+
+QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const
+{
+ return _b;
+}
+
+int QFastMetaBuilder::StringRef::offset() const
+{
+ return _o;
+}
+
+char *QFastMetaBuilder::StringRef::data()
+{
+ Q_ASSERT(_b);
+ if (_b->m_stringDataLength != _b->m_stringDataAllocated)
+ _b->allocateStringData();
+ return _b->m_stringData + _o;
+}
+
+int QFastMetaBuilder::StringRef::length() const
+{
+ return _l;
+}
+
+void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str)
+{
+ Q_ASSERT(str.utf8length() == _l);
+ str.writeUtf8(data());
+ *(data() + _l) = 0;
+}
+
+void QFastMetaBuilder::StringRef::load(const QByteArray &str)
+{
+ Q_ASSERT(str.length() == _l);
+ strcpy(data(), str.constData());
+}
+
+void QFastMetaBuilder::StringRef::load(const char *str)
+{
+ Q_ASSERT(strlen(str) == (uint)_l);
+ strcpy(data(), str);
+}
+
+QT_END_NAMESPACE
+
+#endif // QFASTMETABUILDER_P_H
+
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
new file mode 100644
index 0000000000..da5074b3cd
--- /dev/null
+++ b/src/qml/qml/ftw/qfieldlist_p.h
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFIELDLIST_P_H
+#define QFIELDLIST_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 <private/qflagpointer_p.h>
+
+// QForwardFieldList is a super simple linked list that can only prepend
+template<class N, N *N::*nextMember>
+class QForwardFieldList
+{
+public:
+ inline QForwardFieldList();
+ inline N *first() const;
+ inline N *takeFirst();
+
+ inline void prepend(N *);
+
+ inline bool isEmpty() const;
+ inline bool isOne() const;
+ inline bool isMany() const;
+
+ static inline N *next(N *v);
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline bool flag2() const;
+ inline void setFlag2();
+ inline void clearFlag2();
+ inline void setFlag2Value(bool);
+private:
+ QFlagPointer<N> _first;
+};
+
+// QFieldList is a simple linked list, that can append and prepend and also
+// maintains a count
+template<class N, N *N::*nextMember>
+class QFieldList
+{
+public:
+ inline QFieldList();
+ inline N *first() const;
+ inline N *takeFirst();
+
+ inline void append(N *);
+ inline void prepend(N *);
+
+ inline bool isEmpty() const;
+ inline bool isOne() const;
+ inline bool isMany() const;
+ inline int count() const;
+
+ inline void append(QFieldList<N, nextMember> &);
+ inline void prepend(QFieldList<N, nextMember> &);
+ inline void insertAfter(N *, QFieldList<N, nextMember> &);
+
+ inline void copyAndClear(QFieldList<N, nextMember> &);
+ inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &);
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &);
+
+ static inline N *next(N *v);
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+private:
+ N *_first;
+ N *_last;
+ quint32 _flag:1;
+ quint32 _count:31;
+};
+
+template<class N, N *N::*nextMember>
+QForwardFieldList<N, nextMember>::QForwardFieldList()
+{
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::first() const
+{
+ return *_first;
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::takeFirst()
+{
+ N *value = *_first;
+ if (value) {
+ _first = next(value);
+ value->*nextMember = 0;
+ }
+ return value;
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::prepend(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ v->*nextMember = *_first;
+ _first = v;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isEmpty() const
+{
+ return _first.isNull();
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isOne() const
+{
+ return *_first && _first->*nextMember == 0;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::isMany() const
+{
+ return *_first && _first->*nextMember != 0;
+}
+
+template<class N, N *N::*nextMember>
+N *QForwardFieldList<N, nextMember>::next(N *v)
+{
+ Q_ASSERT(v);
+ return v->*nextMember;
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::flag() const
+{
+ return _first.flag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag()
+{
+ _first.setFlag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::clearFlag()
+{
+ _first.clearFlag();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlagValue(bool v)
+{
+ _first.setFlagValue(v);
+}
+
+template<class N, N *N::*nextMember>
+bool QForwardFieldList<N, nextMember>::flag2() const
+{
+ return _first.flag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag2()
+{
+ _first.setFlag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::clearFlag2()
+{
+ _first.clearFlag2();
+}
+
+template<class N, N *N::*nextMember>
+void QForwardFieldList<N, nextMember>::setFlag2Value(bool v)
+{
+ _first.setFlag2Value(v);
+}
+
+template<class N, N *N::*nextMember>
+QFieldList<N, nextMember>::QFieldList()
+: _first(0), _last(0), _flag(0), _count(0)
+{
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::first() const
+{
+ return _first;
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::takeFirst()
+{
+ N *value = _first;
+ if (value) {
+ _first = next(value);
+ if (_last == value) {
+ Q_ASSERT(_first == 0);
+ _last = 0;
+ }
+ value->*nextMember = 0;
+ --_count;
+ }
+ return value;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::append(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ if (isEmpty()) {
+ _first = v;
+ _last = v;
+ } else {
+ _last->*nextMember = v;
+ _last = v;
+ }
+ ++_count;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::prepend(N *v)
+{
+ Q_ASSERT(v->*nextMember == 0);
+ if (isEmpty()) {
+ _first = v;
+ _last = v;
+ } else {
+ v->*nextMember = _first;
+ _first = v;
+ }
+ ++_count;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isEmpty() const
+{
+ return _count == 0;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isOne() const
+{
+ return _count == 1;
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::isMany() const
+{
+ return _count > 1;
+}
+
+template<class N, N *N::*nextMember>
+int QFieldList<N, nextMember>::count() const
+{
+ return _count;
+}
+
+template<class N, N *N::*nextMember>
+N *QFieldList<N, nextMember>::next(N *v)
+{
+ Q_ASSERT(v);
+ return v->*nextMember;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::append(QFieldList<N, nextMember> &o)
+{
+ if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ _last->*nextMember = o._first;
+ _last = o._last;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::prepend(QFieldList<N, nextMember> &o)
+{
+ if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ o._last->*nextMember = _first;
+ _first = o._first;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::insertAfter(N *after, QFieldList<N, nextMember> &o)
+{
+ if (after == 0) {
+ prepend(o);
+ } else if (after == _last) {
+ append(o);
+ } else if (!o.isEmpty()) {
+ if (isEmpty()) {
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ } else {
+ o._last->*nextMember = after->*nextMember;
+ after->*nextMember = o._first;
+ _count += o._count;
+ }
+ o._first = o._last = 0; o._count = 0;
+ }
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
+{
+ _first = o._first;
+ _last = o._last;
+ _count = o._count;
+ o._first = o._last = 0;
+ o._count = 0;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o)
+{
+ _first = 0;
+ _last = 0;
+ _count = 0;
+ while (N *n = o.takeFirst()) append(n);
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o)
+{
+ _first = 0;
+ _last = 0;
+ _count = 0;
+ while (N *n = o.takeFirst()) prepend(n);
+}
+
+template<class N, N *N::*nextMember>
+bool QFieldList<N, nextMember>::flag() const
+{
+ return _flag;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::setFlag()
+{
+ _flag = true;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::clearFlag()
+{
+ _flag = false;
+}
+
+template<class N, N *N::*nextMember>
+void QFieldList<N, nextMember>::setFlagValue(bool v)
+{
+ _flag = v;
+}
+
+#endif // QFIELDLIST_P_H
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
new file mode 100644
index 0000000000..c5a9fbaedb
--- /dev/null
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFINITESTACK_P_H
+#define QFINITESTACK_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
+
+template<typename T>
+struct QFiniteStack {
+ inline QFiniteStack();
+ inline ~QFiniteStack();
+
+ inline void deallocate();
+ inline void allocate(int size);
+
+ inline bool isEmpty() const;
+ inline const T &top() const;
+ inline T &top();
+ inline void push(const T &o);
+ inline T pop();
+ inline int count() const;
+ inline const T &at(int index) const;
+ inline T &operator[](int index);
+private:
+ T *_array;
+ int _alloc;
+ int _size;
+};
+
+template<typename T>
+QFiniteStack<T>::QFiniteStack()
+: _array(0), _alloc(0), _size(0)
+{
+}
+
+template<typename T>
+QFiniteStack<T>::~QFiniteStack()
+{
+ deallocate();
+}
+
+template<typename T>
+bool QFiniteStack<T>::isEmpty() const
+{
+ return _size == 0;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::top() const
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+T &QFiniteStack<T>::top()
+{
+ return _array[_size - 1];
+}
+
+template<typename T>
+void QFiniteStack<T>::push(const T &o)
+{
+ if (QTypeInfo<T>::isComplex) {
+ new (_array + _size++) T(o);
+ } else {
+ _array[_size++] = o;
+ }
+}
+
+template<typename T>
+T QFiniteStack<T>::pop()
+{
+ --_size;
+
+ if (QTypeInfo<T>::isComplex) {
+ T rv = _array[_size];
+ (_array + _size)->~T();
+ return rv;
+ } else {
+ return _array[_size];
+ }
+}
+
+template<typename T>
+int QFiniteStack<T>::count() const
+{
+ return _size;
+}
+
+template<typename T>
+const T &QFiniteStack<T>::at(int index) const
+{
+ return _array[index];
+}
+
+template<typename T>
+T &QFiniteStack<T>::operator[](int index)
+{
+ return _array[index];
+}
+
+template<typename T>
+void QFiniteStack<T>::allocate(int size)
+{
+ Q_ASSERT(_array == 0);
+ Q_ASSERT(_alloc == 0);
+ Q_ASSERT(_size == 0);
+
+ if (!size) return;
+
+ _array = (T *)qMalloc(size * sizeof(T));
+ _alloc = size;
+}
+
+template<typename T>
+void QFiniteStack<T>::deallocate()
+{
+ if (QTypeInfo<T>::isComplex) {
+ T *i = _array + _size;
+ while (i != _array)
+ (--i)->~T();
+ }
+
+ qFree(_array);
+
+ _array = 0;
+ _alloc = 0;
+ _size = 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QFINITESTACK_P_H
+
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
new file mode 100644
index 0000000000..a4b20d9e2a
--- /dev/null
+++ b/src/qml/qml/ftw/qflagpointer_p.h
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFLAGPOINTER_P_H
+#define QFLAGPOINTER_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
+
+template<typename T>
+class QFlagPointer {
+public:
+ inline QFlagPointer();
+ inline QFlagPointer(T *);
+ inline QFlagPointer(const QFlagPointer<T> &o);
+
+ inline bool isNull() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline bool flag2() const;
+ inline void setFlag2();
+ inline void clearFlag2();
+ inline void setFlag2Value(bool);
+
+ inline QFlagPointer<T> &operator=(const QFlagPointer &o);
+ inline QFlagPointer<T> &operator=(T *);
+
+ inline T *operator->() const;
+ inline T *operator*() const;
+
+private:
+ quintptr ptr_value;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+template<typename T, typename T2>
+class QBiPointer {
+public:
+ inline QBiPointer();
+ inline QBiPointer(T *);
+ inline QBiPointer(T2 *);
+ inline QBiPointer(const QBiPointer<T, T2> &o);
+
+ inline bool isNull() const;
+ inline bool isT1() const;
+ inline bool isT2() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o);
+ inline QBiPointer<T, T2> &operator=(T *);
+ inline QBiPointer<T, T2> &operator=(T2 *);
+
+ inline T *asT1() const;
+ inline T2 *asT2() const;
+
+private:
+ quintptr ptr_value;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer()
+: ptr_value(0)
+{
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_ASSERT((ptr_value & FlagsMask) == 0);
+}
+
+template<typename T>
+QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T>
+bool QFlagPointer<T>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T>
+bool QFlagPointer<T>::flag2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag2()
+{
+ ptr_value|= Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::clearFlag2()
+{
+ ptr_value &= ~Flag2Bit;
+}
+
+template<typename T>
+void QFlagPointer<T>::setFlag2Value(bool v)
+{
+ if (v) setFlag2();
+ else clearFlag2();
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o)
+{
+ ptr_value = o.ptr_value;
+ return *this;
+}
+
+template<typename T>
+QFlagPointer<T> &QFlagPointer<T>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagsMask);
+ return *this;
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator->() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+T *QFlagPointer<T>::operator*() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer()
+: ptr_value(0)
+{
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T2 *v)
+: ptr_value(quintptr(v) | Flag2Bit)
+{
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT1() const
+{
+ return !(ptr_value & Flag2Bit);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o)
+{
+ ptr_value = o.ptr_value;
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit);
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
+ return *this;
+}
+
+template<typename T, typename T2>
+T *QBiPointer<T, T2>::asT1() const
+{
+ Q_ASSERT(isT1());
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+T2 *QBiPointer<T, T2>::asT2() const
+{
+ Q_ASSERT(isT2());
+ return (T2 *)(ptr_value & ~FlagsMask);
+}
+
+QT_END_NAMESPACE
+
+#endif // QFLAGPOINTER_P_H
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
new file mode 100644
index 0000000000..1f09d50ed3
--- /dev/null
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhashedstring_p.h"
+
+// This is a reimplementation of V8's string hash algorithm. It is significantly
+// faster to do it here than call into V8, but it adds the maintainence burden of
+// ensuring that the two hashes are identical. We Q_ASSERT() that the two return
+// the same value. If these asserts start to fail, the hash code needs to be
+// synced with V8.
+namespace String {
+ static const int kMaxArrayIndexSize = 10;
+ static const int kMaxHashCalcLength = 16383;
+ static const int kNofHashBitFields = 2;
+ static const int kHashShift = kNofHashBitFields;
+ static const int kIsNotArrayIndexMask = 1 << 1;
+ static const int kArrayIndexValueBits = 24;
+ static const int kArrayIndexHashLengthShift = kArrayIndexValueBits + kNofHashBitFields;
+ static const int kMaxCachedArrayIndexLength = 7;
+};
+
+template <typename schar>
+uint32_t calculateHash(const schar* chars, int length) {
+ if (length > String::kMaxHashCalcLength) {
+ // V8 trivial hash
+ return (length << String::kHashShift) | String::kIsNotArrayIndexMask;
+ }
+
+ uint32_t raw_running_hash = 0;
+ uint32_t array_index = 0;
+ bool is_array_index = (0 < length && length <= String::kMaxArrayIndexSize);
+ bool is_first_char = true;
+
+ int ii = 0;
+ for (;is_array_index && ii < length; ++ii) {
+ quint32 c = *chars++;
+
+ raw_running_hash += c;
+ raw_running_hash += (raw_running_hash << 10);
+ raw_running_hash ^= (raw_running_hash >> 6);
+
+ if (c < '0' || c > '9') {
+ is_array_index = false;
+ } else {
+ int d = c - '0';
+ if (is_first_char) {
+ is_first_char = false;
+ if (c == '0' && length > 1) {
+ is_array_index = false;
+ continue;
+ }
+ }
+ if (array_index > 429496729U - ((d + 2) >> 3)) {
+ is_array_index = false;
+ } else {
+ array_index = array_index * 10 + d;
+ }
+ }
+ }
+
+ for (;ii < length; ++ii) {
+ raw_running_hash += *chars++;
+ raw_running_hash += (raw_running_hash << 10);
+ raw_running_hash ^= (raw_running_hash >> 6);
+ }
+
+ if (is_array_index) {
+ array_index <<= String::kHashShift;
+ array_index |= length << String::kArrayIndexHashLengthShift;
+ return array_index;
+ } else {
+ raw_running_hash += (raw_running_hash << 3);
+ raw_running_hash ^= (raw_running_hash >> 11);
+ raw_running_hash += (raw_running_hash << 15);
+ if (raw_running_hash == 0) {
+ raw_running_hash = 27;
+ }
+
+ return (raw_running_hash << String::kHashShift) | String::kIsNotArrayIndexMask;
+ }
+}
+
+inline quint32 stringHash(const QChar* data, int length)
+{
+ quint32 rv = calculateHash<quint16>((quint16*)data, length) >> String::kHashShift;
+ Q_ASSERT(rv == v8::String::ComputeHash((uint16_t*)data, length));
+ return rv;
+}
+
+inline quint32 stringHash(const char *data, int length)
+{
+ quint32 rv = calculateHash<quint8>((quint8*)data, length) >> String::kHashShift;
+ Q_ASSERT(rv == v8::String::ComputeHash((char *)data, length));
+ return rv;
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
+void QHashedStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+void QHashedCStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+/*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+*/
+const int MinNumBits = 4;
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The primeForNumBits() function returns the prime associated to a
+ power of two. For example, primeForNumBits(8) returns 257.
+*/
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+void QStringHashData::rehashToSize(int size, IteratorData first,
+ IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip)
+{
+ short bits = qMax(MinNumBits, (int)numBits);
+ while (primeForNumBits(bits) < size) bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits, first, Iterate, skip);
+}
+
+void QStringHashData::rehashToBits(short bits, IteratorData first,
+ IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip)
+{
+ numBits = qMax(MinNumBits, (int)bits);
+
+ int nb = primeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ numBuckets = nb;
+
+#ifdef QSTRINGHASH_LINK_DEBUG
+ if (linkCount)
+ qFatal("QStringHash: Illegal attempt to rehash a linked hash.");
+#endif
+
+ delete [] buckets;
+ buckets = new QStringHashNode *[numBuckets];
+ ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets);
+
+ IteratorData nodeList = first;
+ while (nodeList.n) {
+ if (nodeList.n != skip) {
+ int bucket = nodeList.n->hash % numBuckets;
+ nodeList.n->next = buckets[bucket];
+ buckets[bucket] = nodeList.n;
+ }
+
+ nodeList = Iterate(nodeList);
+ }
+}
+
+// Copy of QString's qMemCompare
+bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *a = (const quint16 *)lhs;
+ const quint16 *b = (const quint16 *)rhs;
+
+ if (a == b || !length)
+ return true;
+
+ register union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ register const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ register const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
+
+// Unicode stuff
+static inline bool isUnicodeNonCharacter(uint ucs4)
+{
+ // Unicode has a couple of "non-characters" that one can use internally,
+ // but are not allowed to be used for text interchange.
+ //
+ // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
+ // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
+ // U+FDEF (inclusive)
+
+ return (ucs4 & 0xfffe) == 0xfffe
+ || (ucs4 - 0xfdd0U) < 16;
+}
+
+static int utf8LengthFromUtf16(const QChar *uc, int len)
+{
+ int length = 0;
+
+ int surrogate_high = -1;
+
+ const QChar *ch = uc;
+ int invalid = 0;
+
+ const QChar *end = ch + len;
+ while (ch < end) {
+ uint u = ch->unicode();
+ if (surrogate_high >= 0) {
+ if (u >= 0xdc00 && u < 0xe000) {
+ u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
+ surrogate_high = -1;
+ } else {
+ // high surrogate without low
+ ++ch;
+ ++invalid;
+ surrogate_high = -1;
+ continue;
+ }
+ } else if (u >= 0xdc00 && u < 0xe000) {
+ // low surrogate without high
+ ++ch;
+ ++invalid;
+ continue;
+ } else if (u >= 0xd800 && u < 0xdc00) {
+ surrogate_high = u;
+ ++ch;
+ continue;
+ }
+
+ if (u < 0x80) {
+ ++length;
+ } else {
+ if (u < 0x0800) {
+ ++length;
+ } else {
+ // is it one of the Unicode non-characters?
+ if (isUnicodeNonCharacter(u)) {
+ ++length;
+ ++ch;
+ ++invalid;
+ continue;
+ }
+
+ if (u > 0xffff) {
+ ++length;
+ ++length;
+ } else {
+ ++length;
+ }
+ ++length;
+ }
+ ++length;
+ }
+ ++ch;
+ }
+
+ return length;
+}
+
+// Writes the utf8 version of uc to output. uc is of length len.
+// There must be at least utf8LengthFromUtf16(uc, len) bytes in output.
+// A null terminator is not written.
+static void utf8FromUtf16(char *output, const QChar *uc, int len)
+{
+ uchar replacement = '?';
+ int surrogate_high = -1;
+
+ uchar* cursor = (uchar*)output;
+ const QChar *ch = uc;
+ int invalid = 0;
+
+ const QChar *end = ch + len;
+ while (ch < end) {
+ uint u = ch->unicode();
+ if (surrogate_high >= 0) {
+ if (u >= 0xdc00 && u < 0xe000) {
+ u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000;
+ surrogate_high = -1;
+ } else {
+ // high surrogate without low
+ *cursor = replacement;
+ ++ch;
+ ++invalid;
+ surrogate_high = -1;
+ continue;
+ }
+ } else if (u >= 0xdc00 && u < 0xe000) {
+ // low surrogate without high
+ *cursor = replacement;
+ ++ch;
+ ++invalid;
+ continue;
+ } else if (u >= 0xd800 && u < 0xdc00) {
+ surrogate_high = u;
+ ++ch;
+ continue;
+ }
+
+ if (u < 0x80) {
+ *cursor++ = (uchar)u;
+ } else {
+ if (u < 0x0800) {
+ *cursor++ = 0xc0 | ((uchar) (u >> 6));
+ } else {
+ // is it one of the Unicode non-characters?
+ if (isUnicodeNonCharacter(u)) {
+ *cursor++ = replacement;
+ ++ch;
+ ++invalid;
+ continue;
+ }
+
+ if (u > 0xffff) {
+ *cursor++ = 0xf0 | ((uchar) (u >> 18));
+ *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f);
+ } else {
+ *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f);
+ }
+ *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f);
+ }
+ *cursor++ = 0x80 | ((uchar) (u&0x3f));
+ }
+ ++ch;
+ }
+}
+
+void QHashedStringRef::computeUtf8Length() const
+{
+ if (m_length)
+ m_utf8length = utf8LengthFromUtf16(m_data, m_length);
+ else
+ m_utf8length = 0;
+}
+
+QHashedStringRef QHashedStringRef::mid(int offset, int length) const
+{
+ Q_ASSERT(offset < m_length);
+ return QHashedStringRef(m_data + offset,
+ (length == -1 || (offset + length) > m_length)?(m_length - offset):length);
+}
+
+bool QHashedStringRef::endsWith(const QString &s) const
+{
+ return s.length() < m_length &&
+ QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length());
+}
+
+bool QHashedStringRef::startsWith(const QString &s) const
+{
+ return s.length() < m_length &&
+ QHashedString::compare(s.constData(), m_data, s.length());
+}
+
+QString QHashedStringRef::toString() const
+{
+ if (m_length == 0)
+ return QString();
+ return QString(m_data, m_length);
+}
+
+QByteArray QHashedStringRef::toUtf8() const
+{
+ if (m_length == 0)
+ return QByteArray();
+
+ QByteArray result;
+ result.resize(utf8length());
+ writeUtf8(result.data());
+ return result;
+}
+
+void QHashedStringRef::writeUtf8(char *output) const
+{
+ if (m_length) {
+ int ulen = utf8length();
+ if (ulen == m_length) {
+ // Must be a latin1 string
+ uchar *o = (uchar *)output;
+ const QChar *c = m_data;
+ while (ulen--)
+ *o++ = (uchar)((*c++).unicode());
+ } else {
+ utf8FromUtf16(output, m_data, m_length);
+ }
+ }
+}
+
+QString QHashedCStringRef::toUtf16() const
+{
+ if (m_length == 0)
+ return QString();
+
+ QString rv;
+ rv.resize(m_length);
+ writeUtf16((uint16_t*)rv.data());
+ return rv;
+}
+
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
new file mode 100644
index 0000000000..f575285ff6
--- /dev/null
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -0,0 +1,1418 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHEDSTRING_P_H
+#define QHASHEDSTRING_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/qstring.h>
+#include <private/qv8_p.h>
+
+#include <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Enable this to debug hash linking assumptions.
+// #define QSTRINGHASH_LINK_DEBUG
+
+class QHashedStringRef;
+class Q_AUTOTEST_EXPORT QHashedString : public QString
+{
+public:
+ inline QHashedString();
+ inline QHashedString(const QString &string);
+ inline QHashedString(const QString &string, quint32);
+ inline QHashedString(const QHashedString &string);
+
+ inline QHashedString &operator=(const QHashedString &string);
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+ inline quint32 existingHash() const;
+
+ static inline bool isUpper(const QChar &);
+
+ static bool compare(const QChar *lhs, const QChar *rhs, int length);
+ static inline bool compare(const QChar *lhs, const char *rhs, int length);
+ static inline bool compare(const char *lhs, const char *rhs, int length);
+private:
+ friend class QHashedStringRef;
+ friend class QStringHashNode;
+
+ void computeHash() const;
+ mutable quint32 m_hash;
+};
+
+class Q_AUTOTEST_EXPORT QHashedV8String
+{
+public:
+ inline QHashedV8String();
+ explicit inline QHashedV8String(v8::Handle<v8::String>);
+ inline QHashedV8String(const QHashedV8String &string);
+ inline QHashedV8String &operator=(const QHashedV8String &other);
+
+ inline bool operator==(const QHashedV8String &string);
+
+ inline quint32 hash() const;
+ inline int length() const;
+ inline quint32 symbolId() const;
+
+ inline v8::Handle<v8::String> string() const;
+
+ inline QString toString() const;
+
+private:
+ v8::String::CompleteHashData m_hash;
+ v8::Handle<v8::String> m_string;
+};
+
+class QHashedCStringRef;
+class Q_AUTOTEST_EXPORT QHashedStringRef
+{
+public:
+ inline QHashedStringRef();
+ inline QHashedStringRef(const QString &);
+ inline QHashedStringRef(const QStringRef &);
+ inline QHashedStringRef(const QChar *, int);
+ inline QHashedStringRef(const QChar *, int, quint32);
+ inline QHashedStringRef(const QHashedString &);
+ inline QHashedStringRef(const QHashedStringRef &);
+ inline QHashedStringRef &operator=(const QHashedStringRef &);
+
+ inline bool operator==(const QString &string) const;
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+ inline bool operator==(const QHashedCStringRef &string) const;
+ inline bool operator!=(const QString &string) const;
+ inline bool operator!=(const QHashedString &string) const;
+ inline bool operator!=(const QHashedStringRef &string) const;
+ inline bool operator!=(const QHashedCStringRef &string) const;
+
+ inline quint32 hash() const;
+
+ inline const QChar &at(int) const;
+ inline const QChar *constData() const;
+ bool startsWith(const QString &) const;
+ bool endsWith(const QString &) const;
+ QHashedStringRef mid(int, int) const;
+
+ inline bool isEmpty() const;
+ inline int length() const;
+ inline bool startsWithUpper() const;
+
+ QString toString() const;
+
+ inline int utf8length() const;
+ QByteArray toUtf8() const;
+ void writeUtf8(char *) const;
+private:
+ friend class QHashedString;
+
+ void computeHash() const;
+ void computeUtf8Length() const;
+
+ const QChar *m_data;
+ int m_length;
+ mutable int m_utf8length;
+ mutable quint32 m_hash;
+};
+
+class Q_AUTOTEST_EXPORT QHashedCStringRef
+{
+public:
+ inline QHashedCStringRef();
+ inline QHashedCStringRef(const char *, int);
+ inline QHashedCStringRef(const char *, int, quint32);
+ inline QHashedCStringRef(const QHashedCStringRef &);
+
+ inline quint32 hash() const;
+
+ inline const char *constData() const;
+ inline int length() const;
+
+ QString toUtf16() const;
+ inline int utf16length() const;
+ inline void writeUtf16(QChar *) const;
+ inline void writeUtf16(uint16_t *) const;
+private:
+ friend class QHashedStringRef;
+
+ void computeHash() const;
+
+ const char *m_data;
+ int m_length;
+ mutable quint32 m_hash;
+};
+
+class QStringHashData;
+class Q_AUTOTEST_EXPORT QStringHashNode
+{
+public:
+ QStringHashNode()
+ : length(0), hash(0), symbolId(0), ckey(0)
+ {
+ }
+
+ QStringHashNode(const QHashedString &key)
+ : length(key.length()), hash(key.hash()), symbolId(0)
+ {
+ strData = const_cast<QHashedString &>(key).data_ptr();
+ setQString(true);
+ strData->ref.ref();
+ }
+
+ QStringHashNode(const QHashedCStringRef &key)
+ : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
+ {
+ }
+
+ QStringHashNode(const QStringHashNode &o)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ {
+ setQString(o.isQString());
+ if (isQString()) { strData->ref.ref(); }
+ }
+
+ ~QStringHashNode()
+ {
+ if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ }
+
+ QFlagPointer<QStringHashNode> next;
+
+ qint32 length;
+ quint32 hash;
+ quint32 symbolId;
+
+ union {
+ const char *ckey;
+ QStringData *strData;
+ };
+
+ bool isQString() const { return next.flag(); }
+ void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+
+ inline char *cStrData() const { return (char *)ckey; }
+ inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); }
+
+ inline bool equals(v8::Handle<v8::String> string) {
+ return isQString()?string->Equals(utf16Data(), length):
+ string->Equals(cStrData(), length);
+ }
+
+ inline bool symbolEquals(const QHashedV8String &string) {
+ Q_ASSERT(string.symbolId() != 0);
+ return length == string.length() && hash == string.hash() &&
+ (string.symbolId() == symbolId || equals(string.string()));
+ }
+
+ inline bool equals(const QHashedV8String &string) {
+ return length == string.length() && hash == string.hash() &&
+ equals(string.string());
+ }
+
+ inline bool equals(const QHashedStringRef &string) {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+
+ inline bool equals(const QHashedCStringRef &string) {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+};
+
+class Q_AUTOTEST_EXPORT QStringHashData
+{
+public:
+ QStringHashData()
+ : buckets(0), numBuckets(0), size(0), numBits(0)
+#ifdef QSTRINGHASH_LINK_DEBUG
+ , linkCount(0)
+#endif
+ {}
+
+ QStringHashNode **buckets;
+ int numBuckets;
+ int size;
+ short numBits;
+#ifdef QSTRINGHASH_LINK_DEBUG
+ int linkCount;
+#endif
+
+ struct IteratorData {
+ IteratorData() : n(0), p(0) {}
+ QStringHashNode *n;
+ void *p;
+ };
+ void rehashToBits(short, IteratorData, IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip = 0);
+ void rehashToSize(int, IteratorData, IteratorData (*Iterate)(const IteratorData &),
+ QStringHashNode *skip = 0);
+
+private:
+ QStringHashData(const QStringHashData &);
+ QStringHashData &operator=(const QStringHashData &);
+};
+
+template<class T>
+class QStringHash
+{
+public:
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const Node &o) : QStringHashNode(o), value(o.value) {}
+ Node() {}
+ T value;
+ };
+ struct NewedNode : public Node {
+ NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(0) {}
+ NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(0) {}
+ NewedNode(const Node &o) : Node(o), nextNewed(0) {}
+ NewedNode *nextNewed;
+ };
+ struct ReservedNodePool
+ {
+ ReservedNodePool() : count(0), used(0), nodes(0) {}
+ ~ReservedNodePool() { delete [] nodes; }
+ int count;
+ int used;
+ Node *nodes;
+ };
+
+ QStringHashData data;
+ NewedNode *newedNodes;
+ ReservedNodePool *nodePool;
+ const QStringHash<T> *link;
+
+ inline Node *findNode(const QString &) const;
+ inline Node *findNode(const QHashedString &) const;
+ inline Node *findNode(const QHashedStringRef &) const;
+ inline Node *findNode(const QHashedCStringRef &) const;
+ inline Node *findNode(const QHashedV8String &) const;
+ inline Node *findSymbolNode(const QHashedV8String &) const;
+ inline Node *createNode(const Node &o);
+ inline Node *createNode(const QHashedString &, const T &);
+ inline Node *createNode(const QHashedCStringRef &, const T &);
+
+ inline Node *takeNode(const QHashedString &key, const T &value);
+ inline Node *takeNode(const QHashedCStringRef &key, const T &value);
+ inline Node *takeNode(const Node &o);
+
+ inline void copy(const QStringHash<T> &);
+
+ inline QStringHashData::IteratorData iterateFirst() const;
+ static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
+ void linkAndReserve(const QStringHash<T> &other, int additionalReserve);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline int numBuckets() const;
+ inline bool isLinked() const;
+
+ class ConstIterator {
+ public:
+ inline ConstIterator();
+ inline ConstIterator(const QStringHashData::IteratorData &);
+
+ inline ConstIterator &operator++();
+
+ inline bool operator==(const ConstIterator &o) const;
+ inline bool operator!=(const ConstIterator &o) const;
+
+ inline QHashedString key() const;
+ inline const T &value() const;
+ inline const T &operator*() const;
+
+ inline Node *node() const;
+ private:
+ QStringHashData::IteratorData d;
+ };
+
+ inline void insert(const QString &, const T &);
+ inline void insert(const QHashedString &, const T &);
+ inline void insert(const QHashedStringRef &, const T &);
+ inline void insert(const QHashedCStringRef &, const T &);
+ inline void insert(const ConstIterator &);
+
+ inline T *value(const QString &) const;
+ inline T *value(const QHashedString &) const;
+ inline T *value(const QHashedStringRef &) const;
+ inline T *value(const QHashedV8String &) const;
+ inline T *value(const QHashedCStringRef &) const;
+ inline T *value(const ConstIterator &) const;
+
+ inline bool contains(const QString &) const;
+ inline bool contains(const QHashedString &) const;
+ inline bool contains(const QHashedStringRef &) const;
+ inline bool contains(const QHashedCStringRef &) const;
+ inline bool contains(const ConstIterator &) const;
+
+ inline T &operator[](const QString &);
+ inline T &operator[](const QHashedString &);
+ inline T &operator[](const QHashedStringRef &);
+ inline T &operator[](const QHashedCStringRef &);
+
+ inline ConstIterator begin() const;
+ inline ConstIterator end() const;
+
+ inline void reserve(int);
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+: newedNodes(0), nodePool(0), link(0)
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: newedNodes(0), nodePool(0), link(0)
+{
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+
+ return *this;
+}
+
+template<class T>
+void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+
+ if (other.count()) {
+ data.size = other.data.size;
+ data.rehashToSize(other.count() + additionalReserve, iterateFirst(), iterateNext);
+
+ if (data.numBuckets == other.data.numBuckets) {
+ nodePool = new ReservedNodePool;
+ nodePool->count = additionalReserve;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[additionalReserve];
+
+#ifdef QSTRINGHASH_LINK_DEBUG
+ data.linkCount++;
+ const_cast<QStringHash<T>&>(other).data.linkCount++;
+#endif
+
+ for (int ii = 0; ii < data.numBuckets; ++ii) {
+ data.buckets[ii] = 0;
+ Node *n = (Node *)other.data.buckets[ii];
+ data.buckets[ii] = n;
+ }
+
+ link = &other;
+ return;
+ }
+
+ data.size = 0;
+ }
+
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+#ifdef QSTRINGHASH_LINK_DEBUG
+ if (link) {
+ data.linkCount--;
+ const_cast<QStringHash<T> *>(link)->data.linkCount--;
+ }
+
+ if (data.linkCount)
+ qFatal("QStringHash: Illegal attempt to clear a linked hash.");
+#endif
+
+ // Delete the individually allocated nodes
+ NewedNode *n = newedNodes;
+ while (n) {
+ NewedNode *c = n;
+ n = c->nextNewed;
+ delete c;
+ }
+ // Delete the pool allocated nodes
+ if (nodePool) delete nodePool;
+ delete [] data.buckets;
+
+ data.buckets = 0;
+ data.numBuckets = 0;
+ data.numBits = 0;
+ data.size = 0;
+
+ newedNodes = 0;
+ nodePool = 0;
+ link = 0;
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.size== 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+int QStringHash<T>::numBuckets() const
+{
+ return data.numBuckets;
+}
+
+template<class T>
+bool QStringHash<T>::isLinked() const
+{
+ return link != 0;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedString &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = key.length();
+ rv->hash = key.hash();
+ rv->strData = const_cast<QHashedString &>(key).data_ptr();
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(key, value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const QHashedCStringRef &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = key.length();
+ rv->hash = key.hash();
+ rv->ckey = key.constData();
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(key, value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = o.length;
+ rv->hash = o.hash;
+ if (o.isQString()) {
+ rv->strData = o.strData;
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ } else {
+ rv->ckey = o.ckey;
+ }
+ rv->symbolId = o.symbolId;
+ rv->value = o.value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(o);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+void QStringHash<T>::copy(const QStringHash<T> &other)
+{
+ Q_ASSERT(data.size == 0);
+
+ data.size = other.data.size;
+
+ // Ensure buckets array is created
+ data.rehashToBits(data.numBits, iterateFirst(), iterateNext);
+
+ if (other.link) {
+ for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
+ Node *o = iter.node();
+ Node *n = o->isQString()?findNode(QHashedStringRef((QChar *)o->strData->data(), o->length, o->hash)):
+ findNode(QHashedCStringRef(o->ckey, o->length, o->hash));
+ if (!n) {
+ Node *mynode = takeNode(*o);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+ }
+ }
+ } else {
+ for (ConstIterator iter = other.begin(); iter != other.end(); ++iter) {
+ Node *o = iter.node();
+ Node *mynode = takeNode(*o);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+ }
+ }
+}
+
+template<class T>
+QStringHashData::IteratorData
+QStringHash<T>::iterateNext(const QStringHashData::IteratorData &d)
+{
+ QStringHash<T> *This = (QStringHash<T> *)d.p;
+ Node *node = (Node *)d.n;
+
+ if (This->nodePool && node >= This->nodePool->nodes &&
+ node < (This->nodePool->nodes + This->nodePool->used)) {
+ node--;
+ if (node < This->nodePool->nodes)
+ node = 0;
+ } else {
+ NewedNode *nn = (NewedNode *)node;
+ node = nn->nextNewed;
+
+ if (node == 0 && This->nodePool && This->nodePool->used)
+ node = This->nodePool->nodes + This->nodePool->used - 1;
+ }
+
+ if (node == 0 && This->link)
+ return This->link->iterateFirst();
+
+ QStringHashData::IteratorData rv;
+ rv.n = node;
+ rv.p = d.p;
+ return rv;
+}
+
+template<class T>
+QStringHashData::IteratorData QStringHash<T>::iterateFirst() const
+{
+ Node *n = 0;
+ if (newedNodes)
+ n = newedNodes;
+ else if (nodePool && nodePool->used)
+ n = nodePool->nodes + nodePool->used - 1;
+
+ if (n == 0 && link)
+ return link->iterateFirst();
+
+ QStringHashData::IteratorData rv;
+ rv.n = n;
+ rv.p = const_cast<QStringHash<T> *>(this);
+ return rv;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
+{
+ Node *n = takeNode(o);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = n->hash % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedCStringRef &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1, iterateFirst(), iterateNext, n);
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+void QStringHash<T>::insert(const QString &key, const T &value)
+{
+ QHashedStringRef ch(key);
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(QHashedString(key, ch.hash()), value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedString &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedCStringRef &key, const T &value)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link?0:findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const ConstIterator &key)
+{
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ if (key.node()->isQString()) {
+ QHashedStringRef str((QChar *)key.node()->strData->data(), key.node()->length,
+ key.node()->hash);
+
+ Node *n = link?0:findNode(str);
+ if (n) n->value = key.node()->value;
+ else createNode(*key.node());
+ } else {
+ QHashedCStringRef str(key.node()->ckey, key.node()->length, key.node()->hash);
+
+ Node *n = link?0:findNode(str);
+ if (n) n->value = key.node()->value;
+ else createNode(str, key.node()->value);
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QString &string) const
+{
+ return findNode(QHashedStringRef(string));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedString &string) const
+{
+ return findNode(QHashedStringRef(string.constData(), string.length(), string.hash()));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedCStringRef &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedV8String &string) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->equals(string))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const
+{
+ Q_ASSERT(string.symbolId() != 0);
+
+ QStringHashNode *node = data.numBuckets?data.buckets[string.hash() % data.numBuckets]:0;
+ while (node && !node->symbolEquals(string))
+ node = (*node->next);
+
+ if (node)
+ node->symbolId = string.symbolId();
+
+ return (Node *)node;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedCStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const ConstIterator &iter) const
+{
+ Node *n = iter.node();
+ if (n->isQString())
+ return value(QHashedStringRef((QChar *)n->strData->data(), n->length, n->hash));
+ else
+ return value(QHashedCStringRef(n->ckey, n->length, n->hash));
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedV8String &string) const
+{
+ Node *n = string.symbolId()?findSymbolNode(string):findNode(string);
+ return n?&n->value:0;
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedCStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const ConstIterator &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QString &key)
+{
+ QHashedStringRef cs(key);
+ Node *n = findNode(cs);
+ if (n) return n->value;
+ else return createNode(QHashedString(key, cs.hash()), T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedString &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedCStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+void QStringHash<T>::reserve(int n)
+{
+ if (nodePool || 0 == n)
+ return;
+
+ nodePool = new ReservedNodePool;
+ nodePool->count = n;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[n];
+
+ data.rehashToSize(n, iterateFirst(), iterateNext);
+}
+
+template<class T>
+QStringHash<T>::ConstIterator::ConstIterator()
+{
+}
+
+template<class T>
+QStringHash<T>::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d)
+: d(d)
+{
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator &QStringHash<T>::ConstIterator::operator++()
+{
+ d = QStringHash<T>::iterateNext(d);
+ return *this;
+}
+
+template<class T>
+bool QStringHash<T>::ConstIterator::operator==(const ConstIterator &o) const
+{
+ return d.n == o.d.n;
+}
+
+template<class T>
+bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const
+{
+ return d.n != o.d.n;
+}
+
+template<class T>
+QHashedString QStringHash<T>::ConstIterator::key() const
+{
+ Node *n = (Node *)d.n;
+ if (n->isQString()) {
+ return QHashedString(QString((QChar *)n->strData->data(), n->length), n->hash);
+ } else {
+ return QHashedString(QString::fromLatin1(n->ckey, n->length), n->hash);
+ }
+}
+template<class T>
+const T &QStringHash<T>::ConstIterator::value() const
+{
+ Node *n = (Node *)d.n;
+ return n->value;
+}
+
+template<class T>
+const T &QStringHash<T>::ConstIterator::operator*() const
+{
+ Node *n = (Node *)d.n;
+ return n->value;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::ConstIterator::node() const
+{
+ Node *n = (Node *)d.n;
+ return n;
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
+{
+ return ConstIterator(iterateFirst());
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
+{
+ return ConstIterator();
+}
+
+inline uint qHash(const QHashedString &string)
+{
+ return uint(string.hash());
+}
+
+inline uint qHash(const QHashedStringRef &string)
+{
+ return uint(string.hash());
+}
+
+QHashedString::QHashedString()
+: QString(), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string)
+: QString(string), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string, quint32 hash)
+: QString(string), m_hash(hash)
+{
+}
+
+QHashedString::QHashedString(const QHashedString &string)
+: QString(string), m_hash(string.m_hash)
+{
+}
+
+QHashedString &QHashedString::operator=(const QHashedString &string)
+{
+ static_cast<QString &>(*this) = string;
+ m_hash = string.m_hash;
+ return *this;
+}
+
+bool QHashedString::operator==(const QHashedString &string) const
+{
+ return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ static_cast<const QString &>(*this) == static_cast<const QString &>(string);
+}
+
+bool QHashedString::operator==(const QHashedStringRef &string) const
+{
+ return length() == string.m_length &&
+ (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ QHashedString::compare(constData(), string.m_data, string.m_length);
+}
+
+quint32 QHashedString::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+quint32 QHashedString::existingHash() const
+{
+ return m_hash;
+}
+
+bool QHashedString::isUpper(const QChar &qc)
+{
+ ushort c = qc.unicode();
+ // Optimize for _, a-z and A-Z.
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QHashedV8String::QHashedV8String()
+{
+}
+
+QHashedV8String::QHashedV8String(v8::Handle<v8::String> string)
+: m_hash(string->CompleteHash()), m_string(string)
+{
+ Q_ASSERT(!m_string.IsEmpty());
+}
+
+QHashedV8String::QHashedV8String(const QHashedV8String &string)
+: m_hash(string.m_hash), m_string(string.m_string)
+{
+}
+
+QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other)
+{
+ m_hash = other.m_hash;
+ m_string = other.m_string;
+ return *this;
+}
+
+bool QHashedV8String::operator==(const QHashedV8String &string)
+{
+ return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length &&
+ m_string.IsEmpty() == m_string.IsEmpty() &&
+ (m_string.IsEmpty() || m_string->StrictEquals(string.m_string));
+}
+
+quint32 QHashedV8String::hash() const
+{
+ return m_hash.hash;
+}
+
+int QHashedV8String::length() const
+{
+ return m_hash.length;
+}
+
+quint32 QHashedV8String::symbolId() const
+{
+ return m_hash.symbol_id;
+}
+
+v8::Handle<v8::String> QHashedV8String::string() const
+{
+ return m_string;
+}
+
+QString QHashedV8String::toString() const
+{
+ QString result;
+ result.reserve(m_hash.length);
+
+ for (int i = 0; i < m_hash.length; ++i)
+ result.append(m_string->GetCharacter(i));
+
+ return result;
+}
+
+QHashedStringRef::QHashedStringRef()
+: m_data(0), m_length(0), m_utf8length(-1), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QString &str)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QStringRef &str)
+: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_utf8length(0), m_hash(hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedString &string)
+: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
+: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length),
+ m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
+{
+ m_data = o.m_data;
+ m_length = o.m_length;
+ m_utf8length = o.m_utf8length;
+ m_hash = o.m_hash;
+ return *this;
+}
+
+bool QHashedStringRef::operator==(const QString &string) const
+{
+ return m_length == string.length() &&
+ QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedString &string) const
+{
+ return m_length == string.length() &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(string.m_data, m_data, m_length);
+}
+
+bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ QHashedString::compare(m_data, string.m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QString &string) const
+{
+ return m_length != string.length() ||
+ !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedString &string) const
+{
+ return m_length != string.length() ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ !QHashedString::compare(string.constData(), m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
+{
+ return m_length != string.m_length ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ QHashedString::compare(string.m_data, m_data, m_length);
+}
+
+bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
+{
+ return m_length != string.m_length ||
+ (m_hash != string.m_hash && m_hash && string.m_hash) ||
+ QHashedString::compare(m_data, string.m_data, m_length);
+}
+
+const QChar &QHashedStringRef::at(int index) const
+{
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+}
+
+const QChar *QHashedStringRef::constData() const
+{
+ return m_data;
+}
+
+bool QHashedStringRef::isEmpty() const
+{
+ return m_length == 0;
+}
+
+int QHashedStringRef::length() const
+{
+ return m_length;
+}
+
+int QHashedStringRef::utf8length() const
+{
+ if (m_utf8length < m_length)
+ computeUtf8Length();
+ return m_utf8length;
+}
+
+bool QHashedStringRef::startsWithUpper() const
+{
+ if (m_length < 1) return false;
+ return QHashedString::isUpper(m_data[0]);
+}
+
+quint32 QHashedStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+QHashedCStringRef::QHashedCStringRef()
+: m_data(0), m_length(0), m_hash(0)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const char *data, int length)
+: m_data(data), m_length(length), m_hash(0)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const char *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_hash(hash)
+{
+}
+
+QHashedCStringRef::QHashedCStringRef(const QHashedCStringRef &o)
+: m_data(o.m_data), m_length(o.m_length), m_hash(o.m_hash)
+{
+}
+
+quint32 QHashedCStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+const char *QHashedCStringRef::constData() const
+{
+ return m_data;
+}
+
+int QHashedCStringRef::length() const
+{
+ return m_length;
+}
+
+int QHashedCStringRef::utf16length() const
+{
+ return m_length;
+}
+
+void QHashedCStringRef::writeUtf16(QChar *output) const
+{
+ writeUtf16((uint16_t *)output);
+}
+
+void QHashedCStringRef::writeUtf16(uint16_t *output) const
+{
+ int l = m_length;
+ const char *d = m_data;
+ while (l--)
+ *output++ = *d++;
+}
+
+bool QHashedString::compare(const QChar *lhs, const char *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *l = (const quint16*)lhs;
+ while (length--)
+ if (*l++ != *rhs++) return false;
+ return true;
+}
+
+bool QHashedString::compare(const char *lhs, const char *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ return 0 == ::memcmp(lhs, rhs, length);
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHEDSTRING_P_H
diff --git a/src/qml/qml/ftw/qhashfield_p.h b/src/qml/qml/ftw/qhashfield_p.h
new file mode 100644
index 0000000000..46df9a176c
--- /dev/null
+++ b/src/qml/qml/ftw/qhashfield_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHFIELD_P_H
+#define QHASHFIELD_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
+
+// QHashField can be used for doing coarse grained set testing, in
+// cases where you do not expect the set to contain the item. For
+// example where you would write:
+// QSet<QString> strings;
+// for (int ii = 0; ii < mystrings.count(); ++ii) {
+// if (strings.contains(mystrings.at(ii)))
+// qFatal("Duplication!");
+// strings.insert(mystrings);
+// }
+// You may write:
+// QHashField strings;
+// for (int ii = 0; ii < mystrings.count(); ++ii) {
+// if (strings.testAndSet(qHash(mystrings.at(ii)))) {
+// // The string *might* be duplicated
+// for (int jj = 0; jj < ii; ++jj) {
+// if (mystrings.at(ii) == mystrings.at(jj))
+// qFatal("Duplication!");
+// }
+// }
+// }
+// For small lists of things, where the hash is cheap to calculate
+// and you don't expect duplication this will be much faster.
+class QHashField {
+public:
+ inline QHashField();
+
+ inline void clear();
+
+ inline bool test(quint32 hash);
+ inline bool testAndSet(quint32 hash);
+private:
+ quint32 m_field;
+};
+
+QHashField::QHashField()
+: m_field(0)
+{
+}
+
+void QHashField::clear()
+{
+ m_field = 0;
+}
+
+bool QHashField::test(quint32 hash)
+{
+ return m_field & (1 << (hash % 31));
+}
+
+bool QHashField::testAndSet(quint32 hash)
+{
+ quint32 mask = 1 << (hash % 31);
+ bool rv = m_field & mask;
+ m_field |= mask;
+ return rv;
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHFIELD_P_H
diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp
new file mode 100644
index 0000000000..5a1624f1f4
--- /dev/null
+++ b/src/qml/qml/ftw/qintrusivelist.cpp
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qintrusivelist_p.h"
+
+/*!
+\class QIntrusiveList
+\brief The QIntrusiveList class is a template class that provides a list of objects using static storage.
+\internal
+
+QIntrusiveList creates a linked list of objects. Adding and removing objects from the
+QIntrusiveList is a constant time operation and is very quick. The list performs no memory
+allocations, but does require the objects being added to the list to contain a QIntrusiveListNode
+instance for the list's use. Even so, for small lists QIntrusiveList uses less memory than Qt's
+other list classes.
+
+As QIntrusiveList uses storage inside the objects in the list, each object can only be in one
+list at a time. Objects are inserted by the insert() method. If the object is already
+in a list (including the one it is being inserted into) it is first removed, and then inserted
+at the head of the list. QIntrusiveList is a last-in-first-out list. That is, following an
+insert() the inserted object becomes the list's first() object.
+
+\code
+struct MyObject {
+ MyObject(int value) : value(value) {}
+
+ int value;
+ QIntrusiveListNode node;
+};
+typedef QIntrusiveList<MyObject, &MyObject::node> MyObjectList;
+
+void foo() {
+ MyObjectList list;
+
+ MyObject m0(0);
+ MyObject m1(1);
+ MyObject m2(2);
+
+ list.insert(&m0);
+ list.insert(&m1);
+ list.insert(&m2);
+
+ // QIntrusiveList is LIFO, so will print: 2... 1... 0...
+ for (MyObjectList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ qWarning() << iter->value;
+ }
+}
+\endcode
+*/
+
+
+/*!
+\fn QIntrusiveList::QIntrusiveList();
+
+Construct an empty list.
+*/
+
+/*!
+\fn QIntrusiveList::~QIntrusiveList();
+
+Destroy the list. All entries are removed.
+*/
+
+/*!
+\fn void QIntrusiveList::insert(N *object);
+
+Insert \a object into the list. If \a object is a member of this, or another list, it will be
+removed and inserted at the head of this list.
+*/
+
+/*!
+\fn void QIntrusiveList::remove(N *object);
+
+Remove \a object from the list. \a object must not be null.
+*/
+
+/*!
+\fn bool QIntrusiveList::contains(N *object) const
+
+Returns true if the list contains \a object; otherwise returns false.
+*/
+
+/*!
+\fn N *QIntrusiveList::first() const
+
+Returns the first entry in this list, or null if the list is empty.
+*/
+
+/*!
+\fn N *QIntrusiveList::next(N *current)
+
+Returns the next object after \a current, or null if \a current is the last object. \a current cannot be null.
+*/
+
+/*!
+\fn iterator QIntrusiveList::begin()
+
+Returns an STL-style interator pointing to the first item in the list.
+
+\sa end()
+*/
+
+/*!
+\fn iterator QIntrusiveList::end()
+
+Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
+
+\sa begin()
+*/
+
+/*!
+iterator &QInplacelist::iterator::erase()
+
+Remove the current object from the list, and return an iterator to the next element.
+*/
+
+
+/*!
+\fn QIntrusiveListNode::QIntrusiveListNode()
+
+Create a QIntrusiveListNode.
+*/
+
+/*!
+\fn QIntrusiveListNode::~QIntrusiveListNode()
+
+Destroy the QIntrusiveListNode. If the node is in a list, it is removed.
+*/
+
+/*!
+\fn void QIntrusiveListNode::remove()
+
+If in a list, remove this node otherwise do nothing.
+*/
+
+/*!
+\fn bool QIntrusiveListNode::isInList() const
+
+Returns true if this node is in a list, false otherwise.
+*/
+
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
new file mode 100644
index 0000000000..489b02d656
--- /dev/null
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINTRUSIVELIST_P_H
+#define QINTRUSIVELIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIntrusiveListNode;
+template<class N, QIntrusiveListNode N::*member>
+class QIntrusiveList
+{
+public:
+ inline QIntrusiveList();
+ inline ~QIntrusiveList();
+
+ inline bool isEmpty() const;
+ inline void insert(N *n);
+ inline void remove(N *n);
+ inline bool contains(N *) const;
+
+ class iterator {
+ public:
+ inline iterator();
+ inline iterator(N *value);
+
+ inline N *operator*() const;
+ inline N *operator->() const;
+ inline bool operator==(const iterator &other) const;
+ inline bool operator!=(const iterator &other) const;
+ inline iterator &operator++();
+
+ inline iterator &erase();
+
+ private:
+ N *_value;
+ };
+ typedef iterator Iterator;
+
+ inline N *first() const;
+ static inline N *next(N *current);
+
+ inline iterator begin();
+ inline iterator end();
+
+private:
+ static inline N *nodeToN(QIntrusiveListNode *node);
+
+ QIntrusiveListNode *__first;
+};
+
+class QIntrusiveListNode
+{
+public:
+ inline QIntrusiveListNode();
+ inline ~QIntrusiveListNode();
+
+ inline void remove();
+ inline bool isInList() const;
+
+ QIntrusiveListNode *_next;
+ QIntrusiveListNode**_prev;
+};
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator()
+: _value(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::iterator::iterator(N *value)
+: _value(value)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator*() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::iterator::operator->() const
+{
+ return _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
+{
+ return other._value == _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
+{
+ return other._value != _value;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
+{
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+{
+ N *old = _value;
+ _value = QIntrusiveList<N, member>::next(_value);
+ (old->*member).remove();
+ return *this;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::QIntrusiveList()
+: __first(0)
+{
+}
+
+template<class N, QIntrusiveListNode N::*member>
+QIntrusiveList<N, member>::~QIntrusiveList()
+{
+ while (__first) __first->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::isEmpty() const
+{
+ return __first == 0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::insert(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+void QIntrusiveList<N, member>::remove(N *n)
+{
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::contains(N *n) const
+{
+ QIntrusiveListNode *nnode = __first;
+ while (nnode) {
+ if (nodeToN(nnode) == n)
+ return true;
+ nnode = nnode->_next;
+ }
+ return false;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::first() const
+{
+ return __first?nodeToN(__first):0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::next(N *current)
+{
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ N *nextstruct = nextnode?nodeToN(nextnode):0;
+ return nextstruct;
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
+{
+ return __first?iterator(nodeToN(__first)):iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
+{
+ return iterator();
+}
+
+template<class N, QIntrusiveListNode N::*member>
+N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
+{
+ return (N *)((char *)node - ((char *)&(((N *)0)->*member) - (char *)0));
+}
+
+QIntrusiveListNode::QIntrusiveListNode()
+: _next(0), _prev(0)
+{
+}
+
+QIntrusiveListNode::~QIntrusiveListNode()
+{
+ remove();
+}
+
+void QIntrusiveListNode::remove()
+{
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = 0;
+ _next = 0;
+}
+
+bool QIntrusiveListNode::isInList() const
+{
+ return _prev != 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QINTRUSIVELIST_P_H
diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h
new file mode 100644
index 0000000000..960d84d5e7
--- /dev/null
+++ b/src/qml/qml/ftw/qlazilyallocated_p.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLAZILYALLOCATED_P_H
+#define QLAZILYALLOCATED_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 <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+class QLazilyAllocated {
+public:
+ inline QLazilyAllocated();
+ inline ~QLazilyAllocated();
+
+ inline bool isAllocated() const;
+
+ inline T *operator->() const;
+
+ inline T &value();
+ inline const T &value() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+private:
+ mutable QFlagPointer<T> d;
+};
+
+template<typename T>
+QLazilyAllocated<T>::QLazilyAllocated()
+{
+}
+
+template<typename T>
+QLazilyAllocated<T>::~QLazilyAllocated()
+{
+ delete *d;
+}
+
+template<typename T>
+bool QLazilyAllocated<T>::isAllocated() const
+{
+ return !d.isNull();
+}
+
+template<typename T>
+T &QLazilyAllocated<T>::value()
+{
+ if (d.isNull()) d = new T;
+ return *(*d);
+}
+
+template<typename T>
+const T &QLazilyAllocated<T>::value() const
+{
+ if (d.isNull()) d = new T;
+ return *(*d);
+}
+
+template<typename T>
+T *QLazilyAllocated<T>::operator->() const
+{
+ return *d;
+}
+
+template<typename T>
+bool QLazilyAllocated<T>::flag() const
+{
+ return d.flag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::setFlag()
+{
+ d.setFlag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::clearFlag()
+{
+ d.clearFlag();
+}
+
+template<typename T>
+void QLazilyAllocated<T>::setFlagValue(bool v)
+{
+ d.setFlagValue(v);
+}
+
+QT_END_NAMESPACE
+
+#endif // QLAZILYALLOCATED_P_H
diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h
new file mode 100644
index 0000000000..c96692667a
--- /dev/null
+++ b/src/qml/qml/ftw/qpodvector_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h
new file mode 100644
index 0000000000..7b0caf49bc
--- /dev/null
+++ b/src/qml/qml/ftw/qpointervaluepair_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPOINTERVALUEPAIR_P_H
+#define QPOINTERVALUEPAIR_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 <private/qflagpointer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// QPointerValuePair is intended to help reduce the memory consumption of a class.
+// In the common case, QPointerValuePair behaves like a pointer. In this mode, it
+// consumes the same memory as a regular pointer.
+// Additionally, QPointerValuePair can store an arbitrary value type in *addition*
+// to the pointer. In this case, it uses slightly more memory than the pointer and
+// value type combined.
+// Consequently, this class is most useful in cases where a pointer is always stored
+// and a value type is rarely stored.
+template<typename P, typename V>
+class QPointerValuePair {
+public:
+ inline QPointerValuePair();
+ inline QPointerValuePair(P *);
+ inline ~QPointerValuePair();
+
+ inline bool isNull() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QPointerValuePair<P, V> &operator=(P *);
+
+ inline P *operator->() const;
+ inline P *operator*() const;
+
+ inline bool hasValue() const;
+ inline V &value();
+ inline const V *constValue() const;
+
+private:
+ struct Value { P *pointer; V value; };
+ QBiPointer<P, Value> d;
+};
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::QPointerValuePair()
+{
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::QPointerValuePair(P *p)
+: d(p)
+{
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V>::~QPointerValuePair()
+{
+ if (d.isT2()) delete d.asT2();
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::isNull() const
+{
+ if (d.isT1()) return 0 == d.asT1();
+ else return d.asT2()->pointer == 0;
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::flag() const
+{
+ return d.flag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::setFlag()
+{
+ d.setFlag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::clearFlag()
+{
+ d.clearFlag();
+}
+
+template<typename P, typename V>
+void QPointerValuePair<P, V>::setFlagValue(bool v)
+{
+ d.setFlagValue(v);
+}
+
+template<typename P, typename V>
+QPointerValuePair<P, V> &QPointerValuePair<P, V>::operator=(P *o)
+{
+ if (d.isT1()) d = o;
+ else d.asT2()->pointer = o;
+ return *this;
+}
+
+template<typename P, typename V>
+P *QPointerValuePair<P, V>::operator->() const
+{
+ if (d.isT1()) return d.asT1();
+ else return d.asT2()->pointer;
+}
+
+template<typename P, typename V>
+P *QPointerValuePair<P, V>::operator*() const
+{
+ if (d.isT1()) return d.asT1();
+ else return d.asT2()->pointer;
+}
+
+template<typename P, typename V>
+bool QPointerValuePair<P, V>::hasValue() const
+{
+ return d.isT2();
+}
+
+template<typename P, typename V>
+V &QPointerValuePair<P, V>::value()
+{
+ if (d.isT1()) {
+ P *p = d.asT1();
+ Value *value = new Value;
+ value->pointer = p;
+ d = value;
+ }
+
+ return d.asT2()->value;
+}
+
+// Will return null if hasValue() == false
+template<typename P, typename V>
+const V *QPointerValuePair<P, V>::constValue() const
+{
+ if (d.isT2()) return &d.asT2()->value;
+ else return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QPOINTERVALUEPAIR_P_H
diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp
new file mode 100644
index 0000000000..6fd11d4b1e
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlpool.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpool_p.h"
+
+// #define POOL_DEBUG
+
+QT_BEGIN_NAMESPACE
+
+void QQmlPool::newpage()
+{
+#ifdef POOL_DEBUG
+ qWarning("QQmlPool: Allocating page");
+#endif
+
+ Page *page = (Page *)malloc(sizeof(Page));
+ page->header.next = _page;
+ page->header.free = page->memory;
+ _page = page;
+}
+
+void QQmlPool::clear()
+{
+#ifdef POOL_DEBUG
+ int count = 0;
+#endif
+
+ Class *c = _classList;
+ while (c) {
+ Class *n = c->_next;
+ c->_destroy(c);
+#ifdef POOL_DEBUG
+ ++count;
+#endif
+ c = n;
+ }
+
+#ifdef POOL_DEBUG
+ qWarning("QQmlPool: Destroyed %d objects", count);
+#endif
+
+ Page *p = _page;
+ while (p) {
+ Page *n = p->header.next;
+ free(p);
+ p = n;
+ }
+
+ _classList = 0;
+ _page = 0;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h
new file mode 100644
index 0000000000..e4fa03ce34
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlpool_p.h
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPOOL_P_H
+#define QQMLPOOL_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 <QtQml/qtqmlglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+// Exported for QtQuick1
+class Q_QML_EXPORT QQmlPool
+{
+public:
+ // The class has a destructor that needs to be called
+ class Class {
+ public:
+ inline QQmlPool *pool() const;
+
+ private:
+ void *operator new(size_t);
+ void *operator new(size_t, void *m) { return m; }
+ friend class QQmlPool;
+
+ QQmlPool *_pool;
+ Class *_next;
+ void (*_destroy)(Class *);
+ };
+
+ // The class is plain old data and no destructor needs to
+ // be called
+ class POD {
+ public:
+ inline QQmlPool *pool() const;
+
+ private:
+ void *operator new(size_t);
+ void *operator new(size_t, void *m) { return m; }
+ friend class QQmlPool;
+
+ QQmlPool *_pool;
+ };
+
+ inline QQmlPool();
+ inline ~QQmlPool();
+
+ void clear();
+
+ template<typename T>
+ inline T *New();
+ template<typename T>
+ inline T *NewRaw();
+ template<typename T>
+ inline T *NewRawArray(int length);
+
+ inline QString *NewString(const QString &);
+ inline QByteArray *NewByteArray(const QByteArray &);
+ inline QUrl *NewUrl(const QUrl &);
+
+ template<typename T>
+ struct List {
+ List() : m_length(0), m_data(0) {}
+ List(const List &o) : m_length(o.m_length), m_data(o.m_data) {}
+ List &operator=(const List &o) {
+ m_length = o.m_length;
+ m_data = o.m_data;
+ return *this;
+ }
+
+ int count() const {
+ return m_length;
+ }
+ int length() const {
+ return m_length;
+ }
+ const T &at(int index) const {
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+ };
+ T &operator[](int index) {
+ Q_ASSERT(index < m_length);
+ return m_data[index];
+ };
+ private:
+ friend class QQmlPool;
+ List(T *d, int l) : m_length(l), m_data(d) {}
+ int m_length;
+ T *m_data;
+ };
+
+ template<typename T>
+ inline List<T> NewRawList(int length);
+
+private:
+ struct StringClass : public QString, public Class {
+ };
+ struct ByteArrayClass : public QByteArray, public Class {
+ };
+ struct UrlClass : public QUrl, public Class {
+ };
+
+ inline void *allocate(int size);
+ void newpage();
+
+ template<typename T>
+ inline void initialize(POD *);
+ template<typename T>
+ inline void initialize(Class *);
+ template<typename T>
+ static void destroy(Class *c);
+
+ struct Page {
+ struct Header {
+ Page *next;
+ char *free;
+ } header;
+
+ static const int pageSize = 4 * 4096 - sizeof(Header);
+
+ char memory[pageSize];
+ };
+
+ Page *_page;
+ Class *_classList;
+};
+
+QQmlPool::QQmlPool()
+: _page(0), _classList(0)
+{
+}
+
+QQmlPool::~QQmlPool()
+{
+ clear();
+}
+
+template<typename T>
+T *QQmlPool::New()
+{
+ T *rv = new (allocate(sizeof(T))) T;
+ initialize<T>(rv);
+ rv->_pool = this;
+ return rv;
+}
+
+template<typename T>
+T *QQmlPool::NewRaw()
+{
+ return (T*)allocate(sizeof(T));
+}
+
+template<typename T>
+T *QQmlPool::NewRawArray(int length)
+{
+ return (T*)allocate(length * sizeof(T));
+}
+
+template<typename T>
+QQmlPool::List<T> QQmlPool::NewRawList(int length)
+{
+ return List<T>(NewRawArray<T>(length), length);
+}
+
+QString *QQmlPool::NewString(const QString &s)
+{
+ QString *rv = New<StringClass>();
+ *rv = s;
+ return rv;
+}
+
+QByteArray *QQmlPool::NewByteArray(const QByteArray &s)
+{
+ QByteArray *rv = New<ByteArrayClass>();
+ *rv = s;
+ return rv;
+}
+
+QUrl *QQmlPool::NewUrl(const QUrl &s)
+{
+ QUrl *rv = New<UrlClass>();
+ *rv = s;
+ return rv;
+}
+
+void *QQmlPool::allocate(int size)
+{
+ if (!_page || (_page->header.free + size) > (_page->memory + Page::pageSize))
+ newpage();
+
+ void *rv = _page->header.free;
+ _page->header.free += size + ((8 - size) & 7); // ensure 8 byte alignment;
+ return rv;
+}
+
+template<typename T>
+void QQmlPool::initialize(QQmlPool::POD *)
+{
+}
+
+template<typename T>
+void QQmlPool::initialize(QQmlPool::Class *c)
+{
+ c->_next = _classList;
+ c->_destroy = &destroy<T>;
+ _classList = c;
+}
+
+template<typename T>
+void QQmlPool::destroy(Class *c)
+{
+ static_cast<T *>(c)->~T();
+}
+
+QQmlPool *QQmlPool::Class::pool() const
+{
+ return _pool;
+}
+
+QQmlPool *QQmlPool::POD::pool() const
+{
+ return _pool;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPOOL_P_H
+
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
new file mode 100644
index 0000000000..497f4ecc0f
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLREFCOUNT_P_H
+#define QQMLREFCOUNT_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/qatomic.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlRefCount
+{
+public:
+ inline QQmlRefCount();
+ inline virtual ~QQmlRefCount();
+ inline void addref();
+ inline void release();
+
+protected:
+ inline virtual void destroy();
+
+private:
+ QAtomicInt refCount;
+};
+
+template<class T>
+class QQmlRefPointer
+{
+public:
+ inline QQmlRefPointer();
+ inline QQmlRefPointer(T *);
+ inline QQmlRefPointer(const QQmlRefPointer<T> &);
+ inline ~QQmlRefPointer();
+
+ inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
+ inline QQmlRefPointer<T> &operator=(T *);
+
+ inline bool isNull() const { return !o; }
+
+ inline T* operator->() const { return o; }
+ inline T& operator*() const { return *o; }
+ inline operator T*() const { return o; }
+ inline T* data() const { return o; }
+
+ inline QQmlRefPointer<T> &take(T *);
+
+private:
+ T *o;
+};
+
+QQmlRefCount::QQmlRefCount()
+: refCount(1)
+{
+}
+
+QQmlRefCount::~QQmlRefCount()
+{
+ Q_ASSERT(refCount.load() == 0);
+}
+
+void QQmlRefCount::addref()
+{
+ Q_ASSERT(refCount.load() > 0);
+ refCount.ref();
+}
+
+void QQmlRefCount::release()
+{
+ Q_ASSERT(refCount.load() > 0);
+ if (!refCount.deref())
+ destroy();
+}
+
+void QQmlRefCount::destroy()
+{
+ delete this;
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer()
+: o(0)
+{
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer(T *o)
+: o(o)
+{
+ if (o) o->addref();
+}
+
+template<class T>
+QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
+: o(other.o)
+{
+ if (o) o->addref();
+}
+
+template<class T>
+QQmlRefPointer<T>::~QQmlRefPointer()
+{
+ if (o) o->release();
+}
+
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
+{
+ if (other.o) other.o->addref();
+ if (o) o->release();
+ o = other.o;
+ return *this;
+}
+
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(T *other)
+{
+ if (other) other->addref();
+ if (o) o->release();
+ o = other;
+ return *this;
+}
+
+/*!
+Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
+of the callers reference of other.
+*/
+template<class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::take(T *other)
+{
+ if (o) o->release();
+ o = other;
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QQMLREFCOUNT_P_H
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
new file mode 100644
index 0000000000..423012b934
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlthread_p.h"
+
+#include <private/qfieldlist_p.h>
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlThreadPrivate : public QThread
+{
+public:
+ QQmlThreadPrivate(QQmlThread *);
+ QQmlThread *q;
+
+ virtual void run();
+
+ inline void lock() { _mutex.lock(); }
+ inline void unlock() { _mutex.unlock(); }
+ inline void wait() { _wait.wait(&_mutex); }
+ inline void wakeOne() { _wait.wakeOne(); }
+ inline void wakeAll() { _wait.wakeAll(); }
+
+ quint32 m_threadProcessing:1; // Set when the thread is processing messages
+ quint32 m_mainProcessing:1; // Set when the main thread is processing messages
+ quint32 m_shutdown:1; // Set by main thread to request a shutdown
+ quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+
+ typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
+ MessageList threadList;
+ MessageList mainList;
+
+ QQmlThread::Message *mainSync;
+
+ void triggerMainEvent();
+ void triggerThreadEvent();
+
+ void mainEvent();
+ void threadEvent();
+
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ struct MainObject : public QObject {
+ MainObject(QQmlThreadPrivate *p);
+ virtual bool event(QEvent *e);
+ QQmlThreadPrivate *p;
+ };
+ MainObject m_mainObject;
+
+ QMutex _mutex;
+ QWaitCondition _wait;
+};
+
+QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p)
+: p(p)
+{
+}
+
+// Trigger mainEvent in main thread. Must be called from thread.
+void QQmlThreadPrivate::triggerMainEvent()
+{
+ Q_ASSERT(q->isThisThread());
+ QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User));
+}
+
+// Trigger even in thread. Must be called from main thread.
+void QQmlThreadPrivate::triggerThreadEvent()
+{
+ Q_ASSERT(!q->isThisThread());
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+bool QQmlThreadPrivate::MainObject::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ p->mainEvent();
+ return QObject::event(e);
+}
+
+QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
+: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
+ m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
+{
+}
+
+bool QQmlThreadPrivate::event(QEvent *e)
+{
+ if (e->type() == QEvent::User)
+ threadEvent();
+ return QThread::event(e);
+}
+
+void QQmlThreadPrivate::run()
+{
+ lock();
+
+ wakeOne();
+
+ unlock();
+
+ q->startupThread();
+ exec();
+}
+
+void QQmlThreadPrivate::mainEvent()
+{
+ lock();
+
+ m_mainProcessing = true;
+
+ while (!mainList.isEmpty() || mainSync) {
+ bool isSync = mainSync != 0;
+ QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst();
+ unlock();
+
+ message->call(q);
+ delete message;
+
+ lock();
+
+ if (isSync) {
+ mainSync = 0;
+ wakeOne();
+ }
+ }
+
+ m_mainProcessing = false;
+
+ unlock();
+}
+
+void QQmlThreadPrivate::threadEvent()
+{
+ lock();
+
+ if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+ q->shutdownThread();
+ } else {
+ m_threadProcessing = true;
+
+ while (!threadList.isEmpty()) {
+ QQmlThread::Message *message = threadList.first();
+
+ unlock();
+
+ message->call(q);
+
+ lock();
+
+ delete threadList.takeFirst();
+ }
+
+ wakeOne();
+
+ m_threadProcessing = false;
+
+ unlock();
+ }
+}
+
+QQmlThread::QQmlThread()
+: d(new QQmlThreadPrivate(this))
+{
+ d->lock();
+ d->start();
+ d->wait();
+ d->unlock();
+ d->moveToThread(d);
+
+}
+
+QQmlThread::~QQmlThread()
+{
+ delete d;
+}
+
+void QQmlThread::shutdown()
+{
+ d->lock();
+ Q_ASSERT(!d->m_shutdown);
+ d->m_shutdown = true;
+ if (d->threadList.isEmpty() && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->wait();
+ d->unlock();
+ d->QThread::wait();
+}
+
+void QQmlThread::lock()
+{
+ d->lock();
+}
+
+void QQmlThread::unlock()
+{
+ d->unlock();
+}
+
+void QQmlThread::wakeOne()
+{
+ d->wakeOne();
+}
+
+void QQmlThread::wakeAll()
+{
+ d->wakeAll();
+}
+
+void QQmlThread::wait()
+{
+ d->wait();
+}
+
+bool QQmlThread::isThisThread() const
+{
+ return QThread::currentThread() == d;
+}
+
+QThread *QQmlThread::thread() const
+{
+ return const_cast<QThread *>(static_cast<const QThread *>(d));
+}
+
+// Called when the thread starts. Do startup stuff in here.
+void QQmlThread::startupThread()
+{
+}
+
+// Called when the thread shuts down. Do cleanup in here.
+void QQmlThread::shutdownThread()
+{
+}
+
+void QQmlThread::internalCallMethodInThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ Q_ASSERT(d->m_mainThreadWaiting == false);
+
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+
+ d->m_mainThreadWaiting = true;
+
+ do {
+ if (d->mainSync) {
+ QQmlThread::Message *message = d->mainSync;
+ unlock();
+ message->call(this);
+ delete message;
+ lock();
+ d->mainSync = 0;
+ wakeOne();
+ } else {
+ d->wait();
+ }
+ } while (d->mainSync || !d->threadList.isEmpty());
+
+ d->m_mainThreadWaiting = false;
+ d->unlock();
+}
+
+void QQmlThread::internalCallMethodInMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+
+ d->lock();
+
+ Q_ASSERT(d->mainSync == 0);
+ d->mainSync = message;
+
+ if (d->m_mainThreadWaiting) {
+ d->wakeOne();
+ } else if (d->m_mainProcessing) {
+ // Do nothing - it is already looping
+ } else {
+ d->triggerMainEvent();
+ }
+
+ while (d->mainSync && !d->m_shutdown)
+ d->wait();
+
+ d->unlock();
+}
+
+void QQmlThread::internalPostMethodToThread(Message *message)
+{
+ Q_ASSERT(!isThisThread());
+ d->lock();
+ bool wasEmpty = d->threadList.isEmpty();
+ d->threadList.append(message);
+ if (wasEmpty && d->m_threadProcessing == false)
+ d->triggerThreadEvent();
+ d->unlock();
+}
+
+void QQmlThread::internalPostMethodToMain(Message *message)
+{
+ Q_ASSERT(isThisThread());
+ d->lock();
+ bool wasEmpty = d->mainList.isEmpty();
+ d->mainList.append(message);
+ if (wasEmpty && d->m_mainProcessing == false)
+ d->triggerMainEvent();
+ d->unlock();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
new file mode 100644
index 0000000000..8a0ec6ceaa
--- /dev/null
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTHREAD_P_H
+#define QQMLTHREAD_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 <private/qintrusivelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+
+class QQmlThreadPrivate;
+class QQmlThread
+{
+public:
+ QQmlThread();
+ virtual ~QQmlThread();
+ void shutdown();
+
+ void lock();
+ void unlock();
+ void wakeOne();
+ void wakeAll();
+ void wait();
+
+ QThread *thread() const;
+ bool isThisThread() const;
+
+ // Synchronously invoke a method in the thread
+ template<class O>
+ inline void callMethodInThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Synchronously invoke a method in the main thread. If the main thread is
+ // blocked in a callMethodInThread() call, the call is made from within that
+ // call.
+ template<class O>
+ inline void callMethodInMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void callMethodInMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the thread.
+ template<class O>
+ inline void postMethodToThread(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToThread(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &);
+
+ // Asynchronously invoke a method in the main thread.
+ template<class O>
+ inline void postMethodToMain(void (O::*Member)());
+ template<typename T, class V, class O>
+ inline void postMethodToMain(void (O::*Member)(V), const T &);
+ template<typename T, typename T2, class V, class V2, class O>
+ inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &);
+
+protected:
+ virtual void startupThread();
+ virtual void shutdownThread();
+
+private:
+ friend class QQmlThreadPrivate;
+
+ struct Message {
+ Message() : next(0) {}
+ virtual ~Message() {}
+ Message *next;
+ virtual void call(QQmlThread *) = 0;
+ };
+ void internalCallMethodInThread(Message *);
+ void internalCallMethodInMain(Message *);
+ void internalPostMethodToThread(Message *);
+ void internalPostMethodToMain(Message *);
+ QQmlThreadPrivate *d;
+};
+
+template<class O>
+void QQmlThread::callMethodInThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::callMethodInMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalCallMethodInMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalCallMethodInMain(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::postMethodToThread(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToThread(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToThread(new I(Member, arg, arg2));
+}
+
+template<class O>
+void QQmlThread::postMethodToMain(void (O::*Member)())
+{
+ struct I : public Message {
+ void (O::*Member)();
+ I(void (O::*Member)()) : Member(Member) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)();
+ }
+ };
+ internalPostMethodToMain(new I(Member));
+}
+
+template<typename T, class V, class O>
+void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg)
+{
+ struct I : public Message {
+ void (O::*Member)(V);
+ T arg;
+ I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg));
+}
+
+template<typename T, typename T2, class V, class V2, class O>
+void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+{
+ struct I : public Message {
+ void (O::*Member)(V, V2);
+ T arg;
+ T2 arg2;
+ I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ virtual void call(QQmlThread *thread) {
+ O *me = static_cast<O *>(thread);
+ (me->*Member)(arg, arg2);
+ }
+ };
+ internalPostMethodToMain(new I(Member, arg, arg2));
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTHREAD_P_H
diff --git a/src/qml/qml/ftw/qqmltrace.cpp b/src/qml/qml/ftw/qqmltrace.cpp
new file mode 100644
index 0000000000..e044dc654f
--- /dev/null
+++ b/src/qml/qml/ftw/qqmltrace.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltrace_p.h"
+
+#ifdef QML_ENABLE_TRACE
+#include <stdio.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QML_ENABLE_TRACE
+
+QQmlTrace::Pool QQmlTrace::logPool;
+QQmlTrace::Entry *QQmlTrace::first = 0;
+QQmlTrace::Entry *QQmlTrace::last = 0;
+
+static qint64 toNsecs(QQmlTrace::TimeType time)
+{
+#ifdef Q_OS_MAC
+ static mach_timebase_info_data_t info = {0,0};
+ if (info.denom == 0)
+ mach_timebase_info(&info);
+ return time * info.numer / info.denom;
+#else
+ qint64 rv = time.tv_sec * 1000000000 + time.tv_nsec;
+ return rv;
+#endif
+}
+
+QQmlTrace::Pool::Pool()
+{
+ first = New<Entry>();
+ last = first;
+}
+
+QQmlTrace::Pool::~Pool()
+{
+ char buffer[128];
+ sprintf(buffer, "qml.%d.log", ::getpid());
+ FILE *out = fopen(buffer, "w");
+ if (!out) {
+ fprintf (stderr, "QML Log: Could not open %s\n", buffer);
+ return;
+ } else {
+ fprintf (stderr, "QML Log: Writing log to %s\n", buffer);
+ }
+
+ QQmlTrace::Entry *cur = QQmlTrace::first;
+ QByteArray indent;
+ int depth = -1;
+
+ qint64 firstTime = -1;
+
+ while (cur) {
+
+ switch (cur->type) {
+ case QQmlTrace::Entry::RangeStart: {
+ RangeStart *rs = static_cast<QQmlTrace::RangeStart *>(cur);
+
+ qint64 nsecs = toNsecs(rs->time);
+
+ if (firstTime == -1)
+ firstTime = nsecs;
+
+ nsecs -= firstTime;
+
+ depth++;
+ indent = QByteArray(depth * 4, ' ');
+ fprintf(out, "%s%s @%lld (%lld ns)\n", indent.constData(),
+ rs->description, nsecs, toNsecs(rs->end->time) - nsecs - firstTime);
+ } break;
+ case QQmlTrace::Entry::RangeEnd:
+ depth--;
+ indent = QByteArray(depth * 4, ' ');
+ break;
+ case QQmlTrace::Entry::Detail:
+ fprintf(out, "%s %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description);
+ break;
+ case QQmlTrace::Entry::IntDetail:
+ fprintf(out, "%s %s: %d\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ static_cast<QQmlTrace::IntDetail *>(cur)->value);
+ break;
+ case QQmlTrace::Entry::StringDetail: {
+ QByteArray vLatin1 = static_cast<QQmlTrace::StringDetail *>(cur)->value->toLatin1();
+ fprintf(out, "%s %s: %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ vLatin1.constData());
+ } break;
+ case QQmlTrace::Entry::UrlDetail: {
+ QByteArray vLatin1 = static_cast<QQmlTrace::UrlDetail *>(cur)->value->toString().toLatin1();
+ fprintf(out, "%s %s: %s\n", indent.constData(),
+ static_cast<QQmlTrace::Detail *>(cur)->description,
+ vLatin1.constData());
+ } break;
+ case QQmlTrace::Entry::Event: {
+ Event *ev = static_cast<QQmlTrace::Event *>(cur);
+ qint64 nsecs = toNsecs(ev->time) - firstTime;
+ fprintf(out, "%s + %s @%lld +%lld ns\n", indent.constData(),
+ ev->description, nsecs, nsecs - (toNsecs(ev->start->time) - firstTime));
+ } break;
+ case QQmlTrace::Entry::Null:
+ default:
+ break;
+ }
+ cur = cur->next;
+ }
+ fclose(out);
+}
+
+#endif
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/ftw/qqmltrace_p.h b/src/qml/qml/ftw/qqmltrace_p.h
new file mode 100644
index 0000000000..965baff3a3
--- /dev/null
+++ b/src/qml/qml/ftw/qqmltrace_p.h
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTRACE_P_H
+#define QQMLTRACE_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 <private/qqmlpool_p.h>
+
+// #define QML_ENABLE_TRACE
+
+#if defined(QML_ENABLE_TRACE) && defined(Q_OS_MAC)
+#include <mach/mach_time.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QQmlTrace
+{
+public:
+ inline QQmlTrace(const char *desc);
+ inline ~QQmlTrace();
+
+ inline void addDetail(const char *);
+ inline void addDetail(const char *, int);
+ inline void addDetail(const char *, const QString &);
+ inline void addDetail(const char *, const QUrl &);
+
+ inline void event(const char *desc);
+
+#ifdef QML_ENABLE_TRACE
+
+#ifdef Q_OS_MAC
+ typedef uint64_t TimeType;
+#else
+ typedef timespec TimeType;
+#endif
+
+ struct Entry : public QQmlPool::POD {
+ enum Type { Null, RangeStart, RangeEnd, Detail, IntDetail, StringDetail, UrlDetail, Event };
+ inline Entry();
+ inline Entry(Type);
+ Type type;
+ Entry *next;
+ };
+ struct RangeEnd : public Entry {
+ inline RangeEnd();
+ TimeType time;
+ };
+ struct RangeStart : public Entry {
+ inline RangeStart();
+ const char *description;
+ TimeType time;
+ QQmlTrace::RangeEnd *end;
+ };
+ struct Detail : public Entry {
+ inline Detail();
+ inline Detail(Type t);
+ const char *description;
+ };
+ struct IntDetail : public Detail {
+ inline IntDetail();
+ int value;
+ };
+ struct StringDetail : public Detail {
+ inline StringDetail();
+ QString *value;
+ };
+ struct UrlDetail : public Detail {
+ inline UrlDetail();
+ QUrl *value;
+ };
+ struct Event : public Entry {
+ inline Event();
+ const char *description;
+ TimeType time;
+ QQmlTrace::RangeStart *start;
+ };
+
+ struct Pool : public QQmlPool {
+ Pool();
+ ~Pool();
+ };
+
+ static Pool logPool;
+ static Entry *first;
+ static Entry *last;
+
+private:
+ RangeStart *start;
+
+ static TimeType gettime() {
+#ifdef Q_OS_MAC
+ return mach_absolute_time();
+#else
+ TimeType ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts;
+#endif
+ }
+#endif
+};
+
+#ifdef QML_ENABLE_TRACE
+QQmlTrace::Entry::Entry()
+: type(Null), next(0)
+{
+}
+
+QQmlTrace::Entry::Entry(Type type)
+: type(type), next(0)
+{
+ QQmlTrace::last->next = this;
+ QQmlTrace::last = this;
+}
+
+QQmlTrace::RangeEnd::RangeEnd()
+: QQmlTrace::Entry(QQmlTrace::Entry::RangeEnd),
+ time(gettime())
+{
+}
+
+QQmlTrace::RangeStart::RangeStart()
+: QQmlTrace::Entry(QQmlTrace::Entry::RangeStart),
+ description(0), time(gettime())
+{
+}
+
+QQmlTrace::Detail::Detail()
+: QQmlTrace::Entry(QQmlTrace::Entry::Detail),
+ description(0)
+{
+}
+
+QQmlTrace::Detail::Detail(Type type)
+: QQmlTrace::Entry(type), description(0)
+{
+}
+
+QQmlTrace::IntDetail::IntDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::IntDetail),
+ value(0)
+{
+}
+
+QQmlTrace::StringDetail::StringDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::StringDetail),
+ value(0)
+{
+}
+
+QQmlTrace::UrlDetail::UrlDetail()
+: QQmlTrace::Detail(QQmlTrace::Entry::UrlDetail),
+ value(0)
+{
+}
+
+QQmlTrace::Event::Event()
+: QQmlTrace::Entry(QQmlTrace::Entry::Event),
+ description(0), time(gettime()), start(0)
+{
+}
+#endif
+
+QQmlTrace::QQmlTrace(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ RangeStart *e = logPool.New<RangeStart>();
+ e->description = desc;
+ e->end = 0;
+ start = e;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+QQmlTrace::~QQmlTrace()
+{
+#ifdef QML_ENABLE_TRACE
+ RangeEnd *e = logPool.New<RangeEnd>();
+ start->end = e;
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ Detail *e = logPool.New<Detail>();
+ e->description = desc;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, int v)
+{
+#ifdef QML_ENABLE_TRACE
+ IntDetail *e = logPool.New<IntDetail>();
+ e->description = desc;
+ e->value = v;
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, const QString &v)
+{
+#ifdef QML_ENABLE_TRACE
+ StringDetail *e = logPool.New<StringDetail>();
+ e->description = desc;
+ e->value = logPool.NewString(v);
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::addDetail(const char *desc, const QUrl &v)
+{
+#ifdef QML_ENABLE_TRACE
+ UrlDetail *e = logPool.New<UrlDetail>();
+ e->description = desc;
+ e->value = logPool.NewUrl(v);
+#else
+ Q_UNUSED(desc);
+ Q_UNUSED(v);
+#endif
+}
+
+void QQmlTrace::event(const char *desc)
+{
+#ifdef QML_ENABLE_TRACE
+ Event *e = logPool.New<Event>();
+ e->start = start;
+ e->description = desc;
+#else
+ Q_UNUSED(desc);
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTRACE_P_H
diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h
new file mode 100644
index 0000000000..16886edf12
--- /dev/null
+++ b/src/qml/qml/ftw/qrecursionwatcher_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRECURSIONWATCHER_P_H
+#define QRECURSIONWATCHER_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 QRecursionNode;
+class QRecursionNode {
+public:
+ inline QRecursionNode();
+ bool *_r;
+};
+
+template<class T, QRecursionNode T::*Node>
+class QRecursionWatcher {
+public:
+ inline QRecursionWatcher(T *);
+ inline ~QRecursionWatcher();
+ inline bool hasRecursed() const;
+private:
+ T *_t;
+ bool _r;
+};
+
+QRecursionNode::QRecursionNode()
+: _r(0)
+{
+}
+
+template<class T, QRecursionNode T::*Node>
+QRecursionWatcher<T, Node>::QRecursionWatcher(T *t)
+: _t(t), _r(false)
+{
+ if ((_t->*Node)._r) *(_t->*Node)._r = true;
+ (_t->*Node)._r = &_r;
+}
+
+template<class T, QRecursionNode T::*Node>
+QRecursionWatcher<T, Node>::~QRecursionWatcher()
+{
+ if ((_t->*Node)._r == &_r) (_t->*Node)._r = 0;
+}
+
+template<class T, QRecursionNode T::*Node>
+bool QRecursionWatcher<T, Node>::hasRecursed() const
+{
+ return _r;
+}
+
+QT_END_NAMESPACE
+
+#endif // QRECURSIONWATCHER_P_H
diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h
new file mode 100644
index 0000000000..8d0f060ab3
--- /dev/null
+++ b/src/qml/qml/ftw/qrecyclepool_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRECYCLEPOOL_P_H
+#define QRECYCLEPOOL_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
+
+#define QRECYCLEPOOLCOOKIE 0x33218ADF
+
+template<typename T, int Step>
+class QRecyclePoolPrivate
+{
+public:
+ QRecyclePoolPrivate()
+ : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE),
+ currentPage(0), nextAllocated(0)
+ {
+ }
+
+ bool recyclePoolHold;
+ int outstandingItems;
+ quint32 cookie;
+
+ struct PoolType : public T {
+ union {
+ QRecyclePoolPrivate<T, Step> *pool;
+ PoolType *nextAllocated;
+ };
+ };
+
+ struct Page {
+ Page *nextPage;
+ unsigned int free;
+ union {
+ char array[Step * sizeof(PoolType)];
+ qint64 q_for_alignment_1;
+ double q_for_alignment_2;
+ };
+ };
+
+ Page *currentPage;
+ PoolType *nextAllocated;
+
+ inline T *allocate();
+ static inline void dispose(T *);
+ inline void releaseIfPossible();
+};
+
+template<typename T, int Step = 1024>
+class QRecyclePool
+{
+public:
+ inline QRecyclePool();
+ inline ~QRecyclePool();
+
+ inline T *New();
+ template<typename T1>
+ inline T *New(const T1 &);
+ template<typename T1>
+ inline T *New(T1 &);
+
+ static inline void Delete(T *);
+
+private:
+ QRecyclePoolPrivate<T, Step> *d;
+};
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::QRecyclePool()
+: d(new QRecyclePoolPrivate<T, Step>())
+{
+}
+
+template<typename T, int Step>
+QRecyclePool<T, Step>::~QRecyclePool()
+{
+ d->recyclePoolHold = false;
+ d->releaseIfPossible();
+}
+
+template<typename T, int Step>
+T *QRecyclePool<T, Step>::New()
+{
+ T *rv = d->allocate();
+ new (rv) T;
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(const T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+template<typename T1>
+T *QRecyclePool<T, Step>::New(T1 &a)
+{
+ T *rv = d->allocate();
+ new (rv) T(a);
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePool<T, Step>::Delete(T *t)
+{
+ t->~T();
+ QRecyclePoolPrivate<T, Step>::dispose(t);
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::releaseIfPossible()
+{
+ if (recyclePoolHold || outstandingItems)
+ return;
+
+ Page *p = currentPage;
+ while (p) {
+ Page *n = p->nextPage;
+ qFree(p);
+ p = n;
+ }
+
+ delete this;
+}
+
+template<typename T, int Step>
+T *QRecyclePoolPrivate<T, Step>::allocate()
+{
+ PoolType *rv = 0;
+ if (nextAllocated) {
+ rv = nextAllocated;
+ nextAllocated = rv->nextAllocated;
+ } else if (currentPage && currentPage->free) {
+ rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType));
+ currentPage->free--;
+ } else {
+ Page *p = (Page *)qMalloc(sizeof(Page));
+ p->nextPage = currentPage;
+ p->free = Step;
+ currentPage = p;
+
+ rv = (PoolType *)currentPage->array;
+ currentPage->free--;
+ }
+
+ rv->pool = this;
+ ++outstandingItems;
+ return rv;
+}
+
+template<typename T, int Step>
+void QRecyclePoolPrivate<T, Step>::dispose(T *t)
+{
+ PoolType *pt = static_cast<PoolType *>(t);
+ Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE);
+
+ QRecyclePoolPrivate<T, Step> *This = pt->pool;
+ pt->nextAllocated = This->nextAllocated;
+ This->nextAllocated = pt;
+ --This->outstandingItems;
+ This->releaseIfPossible();
+}
+
+QT_END_NAMESPACE
+
+#endif // QRECYCLEPOOL_P_H
diff --git a/src/qml/qml/parser/parser.pri b/src/qml/qml/parser/parser.pri
new file mode 100644
index 0000000000..6be85ba85a
--- /dev/null
+++ b/src/qml/qml/parser/parser.pri
@@ -0,0 +1,19 @@
+HEADERS += \
+ $$PWD/qqmljsast_p.h \
+ $$PWD/qqmljsastfwd_p.h \
+ $$PWD/qqmljsastvisitor_p.h \
+ $$PWD/qqmljsengine_p.h \
+ $$PWD/qqmljsgrammar_p.h \
+ $$PWD/qqmljslexer_p.h \
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qqmljsparser_p.h \
+ $$PWD/qqmljsglobal_p.h \
+ $$PWD/qqmljskeywords_p.h
+
+SOURCES += \
+ $$PWD/qqmljsast.cpp \
+ $$PWD/qqmljsastvisitor.cpp \
+ $$PWD/qqmljsengine_p.cpp \
+ $$PWD/qqmljsgrammar.cpp \
+ $$PWD/qqmljslexer.cpp \
+ $$PWD/qqmljsparser.cpp
diff --git a/src/qml/qml/parser/qqmljs.g b/src/qml/qml/parser/qqmljs.g
new file mode 100644
index 0000000000..746fcb24df
--- /dev/null
+++ b/src/qml/qml/parser/qqmljs.g
@@ -0,0 +1,3016 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+-- Contact: http://www.qt-project.org/
+--
+-- This file is part of the QtQml 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
+-- us via http://www.qt-project.org/.
+--
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser QQmlJSGrammar
+%decl qqmljsparser_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"
+
+%token T_ERROR
+
+--- 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) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtCore/QCoreApplication>
+
+#include <string.h>
+
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsmemorypool_p.h"
+
+./
+
+/:/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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 "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Parser: protected $table
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ 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;
+ };
+
+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 QStringRef &stringRef(int index)
+ { return string_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;
+ MemoryPool *pool;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+ QStringRef *string_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ QStringRef spell;
+ };
+
+ double yylval;
+ QStringRef yytokenspell;
+ 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 QQmlJS
+
+
+:/
+
+
+/.
+
+#include "qqmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QQmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+}
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ pool(engine->pool()),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ string_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ free(sym_stack);
+ free(state_stack);
+ free(location_stack);
+ free(string_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->tokenStartLine();
+ loc.startColumn = lexer->tokenStartColumn();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<QStringRef, 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 = new (pool) AST::UiQualifiedId(idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = new (pool) AST::UiQualifiedId(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->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yytokenspell = first_token->spell;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ stringRef(1) = yytokenspell;
+ 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 = new (pool) AST::UiProgram(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 = new (pool) AST::UiImportList(sym(1).UiImport);
+} break;
+./
+
+UiImportList: UiImportList UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiImportList(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 ;
+/.