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