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