Mark tst_qquickimage as insignificant
[profile/ivi/qtdeclarative.git] / src / qml / debugger / qqmlenginedebugservice.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlenginedebugservice_p.h"
43
44 #include "qqmldebugstatesdelegate_p.h"
45 #include <private/qqmlboundsignal_p.h>
46 #include <qqmlengine.h>
47 #include <private/qqmlmetatype_p.h>
48 #include <qqmlproperty.h>
49 #include <private/qqmlproperty_p.h>
50 #include <private/qqmlbinding_p.h>
51 #include <private/qqmlcontext_p.h>
52 #include <private/qqmlwatcher_p.h>
53 #include <private/qqmlvaluetype_p.h>
54 #include <private/qqmlvmemetaobject_p.h>
55 #include <private/qqmlexpression_p.h>
56
57 #include <QtCore/qdebug.h>
58 #include <QtCore/qmetaobject.h>
59
60 QT_BEGIN_NAMESPACE
61
62 Q_GLOBAL_STATIC(QQmlEngineDebugService, qmlEngineDebugService)
63
64 QQmlEngineDebugService *QQmlEngineDebugService::instance()
65 {
66     return qmlEngineDebugService();
67 }
68
69 QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent)
70     : QQmlDebugService(QStringLiteral("QmlDebugger"), 1, parent),
71       m_watch(new QQmlWatcher(this)),
72       m_statesDelegate(0)
73 {
74     QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
75                      this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
76
77     registerService();
78 }
79
80 QQmlEngineDebugService::~QQmlEngineDebugService()
81 {
82     delete m_statesDelegate;
83 }
84
85 QDataStream &operator<<(QDataStream &ds, 
86                         const QQmlEngineDebugService::QQmlObjectData &data)
87 {
88     ds << data.url << data.lineNumber << data.columnNumber << data.idString
89        << data.objectName << data.objectType << data.objectId << data.contextId;
90     return ds;
91 }
92
93 QDataStream &operator>>(QDataStream &ds, 
94                         QQmlEngineDebugService::QQmlObjectData &data)
95 {
96     ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
97        >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
98     return ds;
99 }
100
101 QDataStream &operator<<(QDataStream &ds, 
102                         const QQmlEngineDebugService::QQmlObjectProperty &data)
103 {
104     ds << (int)data.type << data.name << data.value << data.valueTypeName
105        << data.binding << data.hasNotifySignal;
106     return ds;
107 }
108
109 QDataStream &operator>>(QDataStream &ds,  
110                         QQmlEngineDebugService::QQmlObjectProperty &data)
111 {
112     int type;
113     ds >> type >> data.name >> data.value >> data.valueTypeName
114        >> data.binding >> data.hasNotifySignal;
115     data.type = (QQmlEngineDebugService::QQmlObjectProperty::Type)type;
116     return ds;
117 }
118
119 static inline bool isSignalPropertyName(const QString &signalName)
120 {
121     // see QmlCompiler::isSignalPropertyName
122     return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
123             signalName.at(2).isLetter() && signalName.at(2).isUpper();
124 }
125
126 static bool hasValidSignal(QObject *object, const QString &propertyName)
127 {
128     if (!isSignalPropertyName(propertyName))
129         return false;
130
131     QString signalName = propertyName.mid(2);
132     signalName[0] = signalName.at(0).toLower();
133
134     int sigIdx = QQmlPropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
135
136     if (sigIdx == -1)
137         return false;
138
139     return true;
140 }
141
142 QQmlEngineDebugService::QQmlObjectProperty
143 QQmlEngineDebugService::propertyData(QObject *obj, int propIdx)
144 {
145     QQmlObjectProperty rv;
146
147     QMetaProperty prop = obj->metaObject()->property(propIdx);
148
149     rv.type = QQmlObjectProperty::Unknown;
150     rv.valueTypeName = QString::fromUtf8(prop.typeName());
151     rv.name = QString::fromUtf8(prop.name());
152     rv.hasNotifySignal = prop.hasNotifySignal();
153     QQmlAbstractBinding *binding =
154             QQmlPropertyPrivate::binding(QQmlProperty(obj, rv.name));
155     if (binding)
156         rv.binding = binding->expression();
157
158     if (QQmlValueTypeFactory::isValueType(prop.userType())) {
159         rv.type = QQmlObjectProperty::Basic;
160     } else if (QQmlMetaType::isQObject(prop.userType()))  {
161         rv.type = QQmlObjectProperty::Object;
162     } else if (QQmlMetaType::isList(prop.userType())) {
163         rv.type = QQmlObjectProperty::List;
164     }
165
166     QVariant value;
167     if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) {
168         value = prop.read(obj);
169     }
170     rv.value = valueContents(value);
171
172     return rv;
173 }
174
175 QVariant QQmlEngineDebugService::valueContents(const QVariant &value) const
176 {
177     int userType = value.userType();
178
179     //QObject * is not streamable.
180     //Convert all such instances to a String value
181
182     if (value.type() == QVariant::List) {
183         QVariantList contents;
184         QVariantList list = value.toList();
185         int count = list.size();
186         for (int i = 0; i < count; i++)
187             contents << valueContents(list.at(i));
188         return contents;
189     }
190
191     if (value.type() == QVariant::Map) {
192         QVariantMap contents;
193         QMapIterator<QString, QVariant> i(value.toMap());
194          while (i.hasNext()) {
195              i.next();
196              contents.insert(i.key(), valueContents(i.value()));
197          }
198         return contents;
199     }
200
201     if (QQmlValueTypeFactory::isValueType(userType))
202         return value;
203
204     if (QQmlMetaType::isQObject(userType)) {
205         QObject *o = QQmlMetaType::toQObject(value);
206         if (o) {
207             QString name = o->objectName();
208             if (name.isEmpty())
209                 name = QStringLiteral("<unnamed object>");
210             return name;
211         }
212     }
213
214     return QString(QStringLiteral("<unknown value>"));
215 }
216
217 void QQmlEngineDebugService::buildObjectDump(QDataStream &message, 
218                                                      QObject *object, bool recur, bool dumpProperties)
219 {
220     message << objectData(object);
221
222     QObjectList children = object->children();
223     
224     int childrenCount = children.count();
225     for (int ii = 0; ii < children.count(); ++ii) {
226         if (qobject_cast<QQmlContext*>(children[ii]) || QQmlBoundSignal::cast(children[ii]))
227             --childrenCount;
228     }
229
230     message << childrenCount << recur;
231
232     QList<QQmlObjectProperty> fakeProperties;
233
234     for (int ii = 0; ii < children.count(); ++ii) {
235         QObject *child = children.at(ii);
236         if (qobject_cast<QQmlContext*>(child))
237             continue;
238         QQmlBoundSignal *signal = QQmlBoundSignal::cast(child);
239         if (signal) {
240             if (!dumpProperties)
241                 continue;
242             QQmlObjectProperty prop;
243             prop.type = QQmlObjectProperty::SignalProperty;
244             prop.hasNotifySignal = false;
245             QQmlExpression *expr = signal->expression();
246             if (expr) {
247                 prop.value = expr->expression();
248                 QObject *scope = expr->scopeObject();
249                 if (scope) {
250                     QString methodName = QString::fromLatin1(scope->metaObject()->method(signal->index()).name());
251                     if (!methodName.isEmpty()) {
252                         prop.name = QLatin1String("on") + methodName[0].toUpper()
253                                 + methodName.mid(1);
254                     }
255                 }
256             }
257             fakeProperties << prop;
258         } else {
259             if (recur)
260                 buildObjectDump(message, child, recur, dumpProperties);
261             else
262                 message << objectData(child);
263         }
264     }
265
266     if (!dumpProperties) {
267         message << 0;
268         return;
269     }
270
271     QList<int> propertyIndexes;
272     for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) {
273         if (object->metaObject()->property(ii).isScriptable())
274             propertyIndexes << ii;
275     }
276
277     message << propertyIndexes.size() + fakeProperties.count();
278
279     for (int ii = 0; ii < propertyIndexes.size(); ++ii)
280         message << propertyData(object, propertyIndexes.at(ii));
281
282     for (int ii = 0; ii < fakeProperties.count(); ++ii)
283         message << fakeProperties[ii];
284 }
285
286 void QQmlEngineDebugService::prepareDeferredObjects(QObject *obj)
287 {
288     qmlExecuteDeferred(obj);
289
290     QObjectList children = obj->children();
291     for (int ii = 0; ii < children.count(); ++ii) {
292         QObject *child = children.at(ii);
293         prepareDeferredObjects(child);
294     }
295
296 }
297
298 void QQmlEngineDebugService::buildObjectList(QDataStream &message,
299                                              QQmlContext *ctxt,
300                                              const QList<QPointer<QObject> > &instances)
301 {
302     QQmlContextData *p = QQmlContextData::get(ctxt);
303
304     QString ctxtName = ctxt->objectName();
305     int ctxtId = QQmlDebugService::idForObject(ctxt);
306
307     message << ctxtName << ctxtId;
308
309     int count = 0;
310
311     QQmlContextData *child = p->childContexts;
312     while (child) {
313         ++count;
314         child = child->nextChild;
315     }
316
317     message << count;
318
319     child = p->childContexts;
320     while (child) {
321         buildObjectList(message, child->asQQmlContext(), instances);
322         child = child->nextChild;
323     }
324
325     count = 0;
326     for (int ii = 0; ii < instances.count(); ++ii) {
327         QQmlData *data = QQmlData::get(instances.at(ii));
328         if (data->context == p)
329             count ++;
330     }
331     message << count;
332
333     for (int ii = 0; ii < instances.count(); ++ii) {
334         QQmlData *data = QQmlData::get(instances.at(ii));
335         if (data->context == p)
336             message << objectData(instances.at(ii));
337     }
338 }
339
340 void QQmlEngineDebugService::buildStatesList(bool cleanList,
341                                              const QList<QPointer<QObject> > &instances)
342 {
343     if (m_statesDelegate)
344         m_statesDelegate->buildStatesList(cleanList, instances);
345 }
346
347 QQmlEngineDebugService::QQmlObjectData
348 QQmlEngineDebugService::objectData(QObject *object)
349 {
350     QQmlData *ddata = QQmlData::get(object);
351     QQmlObjectData rv;
352     if (ddata && ddata->outerContext) {
353         rv.url = ddata->outerContext->url;
354         rv.lineNumber = ddata->lineNumber;
355         rv.columnNumber = ddata->columnNumber;
356     } else {
357         rv.lineNumber = -1;
358         rv.columnNumber = -1;
359     }
360
361     QQmlContext *context = qmlContext(object);
362     if (context) {
363         QQmlContextData *cdata = QQmlContextData::get(context);
364         if (cdata)
365             rv.idString = cdata->findObjectId(object);
366     }
367
368     rv.objectName = object->objectName();
369     rv.objectId = QQmlDebugService::idForObject(object);
370     rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
371
372     QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
373     if (type) {
374         QString typeName = type->qmlTypeName();
375         int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
376         rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
377     } else {
378         rv.objectType = QString::fromUtf8(object->metaObject()->className());
379         int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
380         if (marker != -1)
381             rv.objectType = rv.objectType.left(marker);
382     }
383
384     return rv;
385 }
386
387 void QQmlEngineDebugService::messageReceived(const QByteArray &message)
388 {
389     QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
390 }
391
392 void QQmlEngineDebugService::processMessage(const QByteArray &message)
393 {
394     QDataStream ds(message);
395
396     QByteArray type;
397     int queryId;
398     ds >> type >> queryId;
399
400     if (type == "LIST_ENGINES") {
401         QByteArray reply;
402         QDataStream rs(&reply, QIODevice::WriteOnly);
403         rs << QByteArray("LIST_ENGINES_R");
404         rs << queryId << m_engines.count();
405
406         for (int ii = 0; ii < m_engines.count(); ++ii) {
407             QQmlEngine *engine = m_engines.at(ii);
408
409             QString engineName = engine->objectName();
410             int engineId = QQmlDebugService::idForObject(engine);
411
412             rs << engineName << engineId;
413         }
414
415         sendMessage(reply);
416     } else if (type == "LIST_OBJECTS") {
417         int engineId = -1;
418         ds >> engineId;
419
420         QQmlEngine *engine =
421                 qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId));
422
423         QByteArray reply;
424         QDataStream rs(&reply, QIODevice::WriteOnly);
425         rs << QByteArray("LIST_OBJECTS_R") << queryId;
426
427         if (engine) {
428             QQmlContext *rootContext = engine->rootContext();
429             // Clean deleted objects
430             QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(rootContext);
431             for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
432                 if (!ctxtPriv->instances.at(ii)) {
433                     ctxtPriv->instances.removeAt(ii);
434                     --ii;
435                 }
436             }
437             buildObjectList(rs, rootContext, ctxtPriv->instances);
438             buildStatesList(true, ctxtPriv->instances);
439         }
440
441         sendMessage(reply);
442     } else if (type == "FETCH_OBJECT") {
443         int objectId;
444         bool recurse;
445         bool dumpProperties = true;
446
447         ds >> objectId >> recurse >> dumpProperties;
448
449         QObject *object = QQmlDebugService::objectForId(objectId);
450
451         QByteArray reply;
452         QDataStream rs(&reply, QIODevice::WriteOnly);
453         rs << QByteArray("FETCH_OBJECT_R") << queryId;
454
455         if (object) {
456             if (recurse)
457                 prepareDeferredObjects(object);
458             buildObjectDump(rs, object, recurse, dumpProperties);
459         }
460
461         sendMessage(reply);
462     } else if (type == "WATCH_OBJECT") {
463         int objectId;
464
465         ds >> objectId;
466         bool ok = m_watch->addWatch(queryId, objectId);
467
468         QByteArray reply;
469         QDataStream rs(&reply, QIODevice::WriteOnly);
470         rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
471
472         sendMessage(reply);
473     } else if (type == "WATCH_PROPERTY") {
474         int objectId;
475         QByteArray property;
476
477         ds >> objectId >> property;
478         bool ok = m_watch->addWatch(queryId, objectId, property);
479
480         QByteArray reply;
481         QDataStream rs(&reply, QIODevice::WriteOnly);
482         rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
483
484         sendMessage(reply);
485     } else if (type == "WATCH_EXPR_OBJECT") {
486         int debugId;
487         QString expr;
488
489         ds >> debugId >> expr;
490         bool ok = m_watch->addWatch(queryId, debugId, expr);
491
492         QByteArray reply;
493         QDataStream rs(&reply, QIODevice::WriteOnly);
494         rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
495         sendMessage(reply);
496     } else if (type == "NO_WATCH") {
497         bool ok = m_watch->removeWatch(queryId);
498
499         QByteArray reply;
500         QDataStream rs(&reply, QIODevice::WriteOnly);
501         rs << QByteArray("NO_WATCH_R") << queryId << ok;
502         sendMessage(reply);
503     } else if (type == "EVAL_EXPRESSION") {
504         int objectId;
505         QString expr;
506
507         ds >> objectId >> expr;
508
509         QObject *object = QQmlDebugService::objectForId(objectId);
510         QQmlContext *context = qmlContext(object);
511         QVariant result;
512         if (object && context) {
513             QQmlExpression exprObj(context, object, expr);
514             bool undefined = false;
515             QVariant value = exprObj.evaluate(&undefined);
516             if (undefined)
517                 result = QString(QStringLiteral("<undefined>"));
518             else
519                 result = valueContents(value);
520         } else {
521             result = QString(QStringLiteral("<unknown context>"));
522         }
523
524         QByteArray reply;
525         QDataStream rs(&reply, QIODevice::WriteOnly);
526         rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
527
528         sendMessage(reply);
529     } else if (type == "SET_BINDING") {
530         int objectId;
531         QString propertyName;
532         QVariant expr;
533         bool isLiteralValue;
534         QString filename;
535         int line;
536         ds >> objectId >> propertyName >> expr >> isLiteralValue >>
537               filename >> line;
538         bool ok = setBinding(objectId, propertyName, expr, isLiteralValue,
539                              filename, line);
540
541         QByteArray reply;
542         QDataStream rs(&reply, QIODevice::WriteOnly);
543         rs << QByteArray("SET_BINDING_R") << queryId << ok;
544
545         sendMessage(reply);
546     } else if (type == "RESET_BINDING") {
547         int objectId;
548         QString propertyName;
549         ds >> objectId >> propertyName;
550         bool ok = resetBinding(objectId, propertyName);
551
552         QByteArray reply;
553         QDataStream rs(&reply, QIODevice::WriteOnly);
554         rs << QByteArray("RESET_BINDING_R") << queryId << ok;
555
556         sendMessage(reply);
557     } else if (type == "SET_METHOD_BODY") {
558         int objectId;
559         QString methodName;
560         QString methodBody;
561         ds >> objectId >> methodName >> methodBody;
562         bool ok = setMethodBody(objectId, methodName, methodBody);
563
564         QByteArray reply;
565         QDataStream rs(&reply, QIODevice::WriteOnly);
566         rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok;
567
568         sendMessage(reply);
569     }
570 }
571
572 bool QQmlEngineDebugService::setBinding(int objectId,
573                                                 const QString &propertyName,
574                                                 const QVariant &expression,
575                                                 bool isLiteralValue,
576                                                 QString filename,
577                                                 int line,
578                                                 int column)
579 {
580     bool ok = true;
581     QObject *object = objectForId(objectId);
582     QQmlContext *context = qmlContext(object);
583
584     if (object && context) {
585         QQmlProperty property(object, propertyName, context);
586         if (property.isValid()) {
587
588             bool inBaseState = true;
589             if (m_statesDelegate) {
590                 m_statesDelegate->updateBinding(context, property, expression, isLiteralValue,
591                                                 filename, line, column, &inBaseState);
592             }
593
594             if (inBaseState) {
595                 if (isLiteralValue) {
596                     property.write(expression);
597                 } else if (hasValidSignal(object, propertyName)) {
598                     QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString());
599                     QQmlPropertyPrivate::setSignalExpression(property, qmlExpression);
600                     qmlExpression->setSourceLocation(filename, line, column);
601                 } else if (property.isProperty()) {
602                     QQmlBinding *binding = new QQmlBinding(expression.toString(), false, object, QQmlContextData::get(context), filename, line, column);;
603                     binding->setTarget(property);
604                     QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, binding);
605                     if (oldBinding)
606                         oldBinding->destroy();
607                     binding->update();
608                 } else {
609                     ok = false;
610                     qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
611                 }
612             }
613
614         } else {
615             // not a valid property
616             if (m_statesDelegate)
617                 ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue);
618             if (!ok)
619                 qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
620         }
621     }
622     return ok;
623 }
624
625 bool QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName)
626 {
627     QObject *object = objectForId(objectId);
628     QQmlContext *context = qmlContext(object);
629
630     if (object && context) {
631         if (object->property(propertyName.toLatin1()).isValid()) {
632             QQmlProperty property(object, propertyName);
633             QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(property);
634             if (oldBinding) {
635                 QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::setBinding(property, 0);
636                 if (oldBinding)
637                     oldBinding->destroy();
638             }
639             if (property.isResettable()) {
640                 // Note: this will reset the property in any case, without regard to states
641                 // Right now almost no QQuickItem has reset methods for its properties (with the
642                 // notable exception of QQuickAnchors), so this is not a big issue
643                 // later on, setBinding does take states into account
644                 property.reset();
645             } else {
646                 // overwrite with default value
647                 if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) {
648                     if (QObject *emptyObject = objType->create()) {
649                         if (emptyObject->property(propertyName.toLatin1()).isValid()) {
650                             QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read();
651                             if (defaultValue.isValid()) {
652                                 setBinding(objectId, propertyName, defaultValue, true);
653                             }
654                         }
655                         delete emptyObject;
656                     }
657                 }
658             }
659         } else if (hasValidSignal(object, propertyName)) {
660             QQmlProperty property(object, propertyName, context);
661             QQmlPropertyPrivate::setSignalExpression(property, 0);
662         } else {
663             if (m_statesDelegate)
664                 m_statesDelegate->resetBindingForInvalidProperty(object, propertyName);
665         }
666     }
667     return true;
668 }
669
670 bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
671 {
672     QObject *object = objectForId(objectId);
673     QQmlContext *context = qmlContext(object);
674     if (!object || !context || !context->engine())
675         return false;
676     QQmlContextData *contextData = QQmlContextData::get(context);
677     if (!contextData)
678         return false;
679
680     QQmlPropertyData dummy;
681     QQmlPropertyData *prop =
682             QQmlPropertyCache::property(context->engine(), object, method, dummy);
683
684     if (!prop || !prop->isVMEFunction())
685         return false;
686
687     QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
688     QList<QByteArray> paramNames = metaMethod.parameterNames();
689
690     QString paramStr;
691     for (int ii = 0; ii < paramNames.count(); ++ii) {
692         if (ii != 0) paramStr.append(QLatin1Char(','));
693         paramStr.append(QString::fromUtf8(paramNames.at(ii)));
694     }
695
696     QString jsfunction = QLatin1String("(function ") + method + QLatin1Char('(') + paramStr +
697             QLatin1String(") {");
698     jsfunction += body;
699     jsfunction += QLatin1String("\n})");
700
701     QQmlVMEMetaObject *vmeMetaObject =
702             static_cast<QQmlVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
703     Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
704
705     int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
706     vmeMetaObject->setVmeMethod(prop->coreIndex, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber));
707     return true;
708 }
709
710 void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
711 {
712     QByteArray reply;
713     QDataStream rs(&reply, QIODevice::WriteOnly);
714
715     rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
716
717     sendMessage(reply);
718 }
719
720 void QQmlEngineDebugService::addEngine(QQmlEngine *engine)
721 {
722     Q_ASSERT(engine);
723     Q_ASSERT(!m_engines.contains(engine));
724
725     m_engines.append(engine);
726 }
727
728 void QQmlEngineDebugService::remEngine(QQmlEngine *engine)
729 {
730     Q_ASSERT(engine);
731     Q_ASSERT(m_engines.contains(engine));
732
733     m_engines.removeAll(engine);
734 }
735
736 void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object)
737 {
738     Q_ASSERT(engine);
739     Q_ASSERT(m_engines.contains(engine));
740
741     int engineId = QQmlDebugService::idForObject(engine);
742     int objectId = QQmlDebugService::idForObject(object);
743
744     QByteArray reply;
745     QDataStream rs(&reply, QIODevice::WriteOnly);
746
747     //unique queryId -1
748     rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId;
749     sendMessage(reply);
750 }
751
752 void QQmlEngineDebugService::setStatesDelegate(QQmlDebugStatesDelegate *delegate)
753 {
754     m_statesDelegate = delegate;
755 }
756
757 QT_END_NAMESPACE