[844] | 1 | /****************************************************************************
|
---|
| 2 | **
|
---|
| 3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
| 4 | ** All rights reserved.
|
---|
| 5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
| 6 | **
|
---|
| 7 | ** This file is part of the QtDeclarative module of the Qt Toolkit.
|
---|
| 8 | **
|
---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
| 10 | ** Commercial Usage
|
---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
| 14 | ** a written agreement between you and Nokia.
|
---|
| 15 | **
|
---|
| 16 | ** GNU Lesser General Public License Usage
|
---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
| 18 | ** General Public License version 2.1 as published by the Free Software
|
---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
| 20 | ** packaging of this file. Please review the following information to
|
---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
| 23 | **
|
---|
| 24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
| 25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
| 26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
| 27 | **
|
---|
| 28 | ** GNU General Public License Usage
|
---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
| 32 | ** packaging of this file. Please review the following information to
|
---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
| 35 | **
|
---|
| 36 | ** If you have questions regarding the use of this file, please contact
|
---|
| 37 | ** Nokia at qt-info@nokia.com.
|
---|
| 38 | ** $QT_END_LICENSE$
|
---|
| 39 | **
|
---|
| 40 | ****************************************************************************/
|
---|
| 41 |
|
---|
| 42 | #include "private/qdeclarativeenginedebug_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 |
|
---|
| 56 | #include <QtCore/qdebug.h>
|
---|
| 57 | #include <QtCore/qmetaobject.h>
|
---|
| 58 |
|
---|
| 59 | QT_BEGIN_NAMESPACE
|
---|
| 60 |
|
---|
| 61 | Q_GLOBAL_STATIC(QDeclarativeEngineDebugServer, qmlEngineDebugServer);
|
---|
| 62 |
|
---|
| 63 | QDeclarativeEngineDebugServer *QDeclarativeEngineDebugServer::instance()
|
---|
| 64 | {
|
---|
| 65 | return qmlEngineDebugServer();
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | QDeclarativeEngineDebugServer::QDeclarativeEngineDebugServer(QObject *parent)
|
---|
| 69 | : QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent),
|
---|
| 70 | m_watch(new QDeclarativeWatcher(this))
|
---|
| 71 | {
|
---|
| 72 | QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
|
---|
| 73 | this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | QDataStream &operator<<(QDataStream &ds,
|
---|
| 77 | const QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
|
---|
| 78 | {
|
---|
| 79 | ds << data.url << data.lineNumber << data.columnNumber << data.idString
|
---|
| 80 | << data.objectName << data.objectType << data.objectId << data.contextId;
|
---|
| 81 | return ds;
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 | QDataStream &operator>>(QDataStream &ds,
|
---|
| 85 | QDeclarativeEngineDebugServer::QDeclarativeObjectData &data)
|
---|
| 86 | {
|
---|
| 87 | ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
|
---|
| 88 | >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
|
---|
| 89 | return ds;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | QDataStream &operator<<(QDataStream &ds,
|
---|
| 93 | const QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
|
---|
| 94 | {
|
---|
| 95 | ds << (int)data.type << data.name << data.value << data.valueTypeName
|
---|
| 96 | << data.binding << data.hasNotifySignal;
|
---|
| 97 | return ds;
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | QDataStream &operator>>(QDataStream &ds,
|
---|
| 101 | QDeclarativeEngineDebugServer::QDeclarativeObjectProperty &data)
|
---|
| 102 | {
|
---|
| 103 | int type;
|
---|
| 104 | ds >> type >> data.name >> data.value >> data.valueTypeName
|
---|
| 105 | >> data.binding >> data.hasNotifySignal;
|
---|
| 106 | data.type = (QDeclarativeEngineDebugServer::QDeclarativeObjectProperty::Type)type;
|
---|
| 107 | return ds;
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | static inline bool isSignalPropertyName(const QString &signalName)
|
---|
| 111 | {
|
---|
| 112 | // see QmlCompiler::isSignalPropertyName
|
---|
| 113 | return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
|
---|
| 114 | signalName.at(2).isLetter() && signalName.at(2).isUpper();
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | static bool hasValidSignal(QObject *object, const QString &propertyName)
|
---|
| 118 | {
|
---|
| 119 | if (!isSignalPropertyName(propertyName))
|
---|
| 120 | return false;
|
---|
| 121 |
|
---|
| 122 | QString signalName = propertyName.mid(2);
|
---|
| 123 | signalName[0] = signalName.at(0).toLower();
|
---|
| 124 |
|
---|
| 125 | int sigIdx = QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
|
---|
| 126 |
|
---|
| 127 | if (sigIdx == -1)
|
---|
| 128 | return false;
|
---|
| 129 |
|
---|
| 130 | return true;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | QDeclarativeEngineDebugServer::QDeclarativeObjectProperty
|
---|
| 134 | QDeclarativeEngineDebugServer::propertyData(QObject *obj, int propIdx)
|
---|
| 135 | {
|
---|
| 136 | QDeclarativeObjectProperty rv;
|
---|
| 137 |
|
---|
| 138 | QMetaProperty prop = obj->metaObject()->property(propIdx);
|
---|
| 139 |
|
---|
| 140 | rv.type = QDeclarativeObjectProperty::Unknown;
|
---|
| 141 | rv.valueTypeName = QString::fromUtf8(prop.typeName());
|
---|
| 142 | rv.name = QString::fromUtf8(prop.name());
|
---|
| 143 | rv.hasNotifySignal = prop.hasNotifySignal();
|
---|
| 144 | QDeclarativeAbstractBinding *binding =
|
---|
| 145 | QDeclarativePropertyPrivate::binding(QDeclarativeProperty(obj, rv.name));
|
---|
| 146 | if (binding)
|
---|
| 147 | rv.binding = binding->expression();
|
---|
| 148 |
|
---|
| 149 | QVariant value;
|
---|
| 150 | if (prop.userType() != 0) {
|
---|
| 151 | value = prop.read(obj);
|
---|
| 152 | }
|
---|
| 153 | rv.value = valueContents(value);
|
---|
| 154 |
|
---|
| 155 | if (QDeclarativeValueTypeFactory::isValueType(prop.userType())) {
|
---|
| 156 | rv.type = QDeclarativeObjectProperty::Basic;
|
---|
| 157 | } else if (QDeclarativeMetaType::isQObject(prop.userType())) {
|
---|
| 158 | rv.type = QDeclarativeObjectProperty::Object;
|
---|
| 159 | } else if (QDeclarativeMetaType::isList(prop.userType())) {
|
---|
| 160 | rv.type = QDeclarativeObjectProperty::List;
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | return rv;
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | QVariant QDeclarativeEngineDebugServer::valueContents(const QVariant &value) const
|
---|
| 167 | {
|
---|
| 168 | int userType = value.userType();
|
---|
| 169 | if (QDeclarativeValueTypeFactory::isValueType(userType))
|
---|
| 170 | return value;
|
---|
| 171 |
|
---|
| 172 | /*
|
---|
| 173 | if (QDeclarativeMetaType::isList(userType)) {
|
---|
| 174 | int count = QDeclarativeMetaType::listCount(value);
|
---|
| 175 | QVariantList contents;
|
---|
| 176 | for (int i=0; i<count; i++)
|
---|
| 177 | contents << valueContents(QDeclarativeMetaType::listAt(value, i));
|
---|
| 178 | return contents;
|
---|
| 179 | } else */
|
---|
| 180 | if (QDeclarativeMetaType::isQObject(userType)) {
|
---|
| 181 | QObject *o = QDeclarativeMetaType::toQObject(value);
|
---|
| 182 | if (o) {
|
---|
| 183 | QString name = o->objectName();
|
---|
| 184 | if (name.isEmpty())
|
---|
| 185 | name = QLatin1String("<unnamed object>");
|
---|
| 186 | return name;
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | return QLatin1String("<unknown value>");
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message,
|
---|
| 194 | QObject *object, bool recur, bool dumpProperties)
|
---|
| 195 | {
|
---|
| 196 | message << objectData(object);
|
---|
| 197 |
|
---|
| 198 | // Some children aren't added to an object until particular properties are read
|
---|
| 199 | // - e.g. child state objects aren't added until the 'states' property is read -
|
---|
| 200 | // but this should only affect internal objects that aren't shown by the
|
---|
| 201 | // debugger anyway.
|
---|
| 202 |
|
---|
| 203 | QObjectList children = object->children();
|
---|
| 204 |
|
---|
| 205 | int childrenCount = children.count();
|
---|
| 206 | for (int ii = 0; ii < children.count(); ++ii) {
|
---|
| 207 | if (qobject_cast<QDeclarativeContext*>(children[ii]) || QDeclarativeBoundSignal::cast(children[ii]))
|
---|
| 208 | --childrenCount;
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | message << childrenCount << recur;
|
---|
| 212 |
|
---|
| 213 | QList<QDeclarativeObjectProperty> fakeProperties;
|
---|
| 214 |
|
---|
| 215 | for (int ii = 0; ii < children.count(); ++ii) {
|
---|
| 216 | QObject *child = children.at(ii);
|
---|
| 217 | if (qobject_cast<QDeclarativeContext*>(child))
|
---|
| 218 | continue;
|
---|
| 219 | QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
|
---|
| 220 | if (signal) {
|
---|
| 221 | if (!dumpProperties)
|
---|
| 222 | continue;
|
---|
| 223 | QDeclarativeObjectProperty prop;
|
---|
| 224 | prop.type = QDeclarativeObjectProperty::SignalProperty;
|
---|
| 225 | prop.hasNotifySignal = false;
|
---|
| 226 | QDeclarativeExpression *expr = signal->expression();
|
---|
| 227 | if (expr) {
|
---|
| 228 | prop.value = expr->expression();
|
---|
| 229 | QObject *scope = expr->scopeObject();
|
---|
| 230 | if (scope) {
|
---|
| 231 | QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature());
|
---|
| 232 | int lparen = sig.indexOf(QLatin1Char('('));
|
---|
| 233 | if (lparen >= 0) {
|
---|
| 234 | QString methodName = sig.mid(0, lparen);
|
---|
| 235 | prop.name = QLatin1String("on") + methodName[0].toUpper()
|
---|
| 236 | + methodName.mid(1);
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 | }
|
---|
| 240 | fakeProperties << prop;
|
---|
| 241 | } else {
|
---|
| 242 | if (recur)
|
---|
| 243 | buildObjectDump(message, child, recur, dumpProperties);
|
---|
| 244 | else
|
---|
| 245 | message << objectData(child);
|
---|
| 246 | }
|
---|
| 247 | }
|
---|
| 248 |
|
---|
| 249 | if (!dumpProperties) {
|
---|
| 250 | message << 0;
|
---|
| 251 | return;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | message << (object->metaObject()->propertyCount() + fakeProperties.count());
|
---|
| 255 |
|
---|
| 256 | for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii)
|
---|
| 257 | message << propertyData(object, ii);
|
---|
| 258 |
|
---|
| 259 | for (int ii = 0; ii < fakeProperties.count(); ++ii)
|
---|
| 260 | message << fakeProperties[ii];
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, QDeclarativeContext *ctxt)
|
---|
| 264 | {
|
---|
| 265 | QDeclarativeContextData *p = QDeclarativeContextData::get(ctxt);
|
---|
| 266 |
|
---|
| 267 | QString ctxtName = ctxt->objectName();
|
---|
| 268 | int ctxtId = QDeclarativeDebugService::idForObject(ctxt);
|
---|
| 269 |
|
---|
| 270 | message << ctxtName << ctxtId;
|
---|
| 271 |
|
---|
| 272 | int count = 0;
|
---|
| 273 |
|
---|
| 274 | QDeclarativeContextData *child = p->childContexts;
|
---|
| 275 | while (child) {
|
---|
| 276 | ++count;
|
---|
| 277 | child = child->nextChild;
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 | message << count;
|
---|
| 281 |
|
---|
| 282 | child = p->childContexts;
|
---|
| 283 | while (child) {
|
---|
| 284 | buildObjectList(message, child->asQDeclarativeContext());
|
---|
| 285 | child = child->nextChild;
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | // Clean deleted objects
|
---|
| 289 | QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
|
---|
| 290 | for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
|
---|
| 291 | if (!ctxtPriv->instances.at(ii)) {
|
---|
| 292 | ctxtPriv->instances.removeAt(ii);
|
---|
| 293 | --ii;
|
---|
| 294 | }
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | message << ctxtPriv->instances.count();
|
---|
| 298 | for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
|
---|
| 299 | message << objectData(ctxtPriv->instances.at(ii));
|
---|
| 300 | }
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | QDeclarativeEngineDebugServer::QDeclarativeObjectData
|
---|
| 304 | QDeclarativeEngineDebugServer::objectData(QObject *object)
|
---|
| 305 | {
|
---|
| 306 | QDeclarativeData *ddata = QDeclarativeData::get(object);
|
---|
| 307 | QDeclarativeObjectData rv;
|
---|
| 308 | if (ddata && ddata->outerContext) {
|
---|
| 309 | rv.url = ddata->outerContext->url;
|
---|
| 310 | rv.lineNumber = ddata->lineNumber;
|
---|
| 311 | rv.columnNumber = ddata->columnNumber;
|
---|
| 312 | } else {
|
---|
| 313 | rv.lineNumber = -1;
|
---|
| 314 | rv.columnNumber = -1;
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | QDeclarativeContext *context = qmlContext(object);
|
---|
| 318 | if (context) {
|
---|
| 319 | QDeclarativeContextData *cdata = QDeclarativeContextData::get(context);
|
---|
| 320 | if (cdata)
|
---|
| 321 | rv.idString = cdata->findObjectId(object);
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | rv.objectName = object->objectName();
|
---|
| 325 | rv.objectId = QDeclarativeDebugService::idForObject(object);
|
---|
| 326 | rv.contextId = QDeclarativeDebugService::idForObject(qmlContext(object));
|
---|
| 327 |
|
---|
| 328 | QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
|
---|
| 329 | if (type) {
|
---|
| 330 | QString typeName = QLatin1String(type->qmlTypeName());
|
---|
| 331 | int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
|
---|
| 332 | rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
|
---|
| 333 | } else {
|
---|
| 334 | rv.objectType = QString::fromUtf8(object->metaObject()->className());
|
---|
| 335 | int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
|
---|
| 336 | if (marker != -1)
|
---|
| 337 | rv.objectType = rv.objectType.left(marker);
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | return rv;
|
---|
| 341 | }
|
---|
| 342 |
|
---|
| 343 | void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
|
---|
| 344 | {
|
---|
| 345 | QDataStream ds(message);
|
---|
| 346 |
|
---|
| 347 | QByteArray type;
|
---|
| 348 | ds >> type;
|
---|
| 349 |
|
---|
| 350 | if (type == "LIST_ENGINES") {
|
---|
| 351 | int queryId;
|
---|
| 352 | ds >> queryId;
|
---|
| 353 |
|
---|
| 354 | QByteArray reply;
|
---|
| 355 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 356 | rs << QByteArray("LIST_ENGINES_R");
|
---|
| 357 | rs << queryId << m_engines.count();
|
---|
| 358 |
|
---|
| 359 | for (int ii = 0; ii < m_engines.count(); ++ii) {
|
---|
| 360 | QDeclarativeEngine *engine = m_engines.at(ii);
|
---|
| 361 |
|
---|
| 362 | QString engineName = engine->objectName();
|
---|
| 363 | int engineId = QDeclarativeDebugService::idForObject(engine);
|
---|
| 364 |
|
---|
| 365 | rs << engineName << engineId;
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | sendMessage(reply);
|
---|
| 369 | } else if (type == "LIST_OBJECTS") {
|
---|
| 370 | int queryId;
|
---|
| 371 | int engineId = -1;
|
---|
| 372 | ds >> queryId >> engineId;
|
---|
| 373 |
|
---|
| 374 | QDeclarativeEngine *engine =
|
---|
| 375 | qobject_cast<QDeclarativeEngine *>(QDeclarativeDebugService::objectForId(engineId));
|
---|
| 376 |
|
---|
| 377 | QByteArray reply;
|
---|
| 378 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 379 | rs << QByteArray("LIST_OBJECTS_R") << queryId;
|
---|
| 380 |
|
---|
| 381 | if (engine)
|
---|
| 382 | buildObjectList(rs, engine->rootContext());
|
---|
| 383 |
|
---|
| 384 | sendMessage(reply);
|
---|
| 385 | } else if (type == "FETCH_OBJECT") {
|
---|
| 386 | int queryId;
|
---|
| 387 | int objectId;
|
---|
| 388 | bool recurse;
|
---|
| 389 | bool dumpProperties = true;
|
---|
| 390 |
|
---|
| 391 | ds >> queryId >> objectId >> recurse >> dumpProperties;
|
---|
| 392 |
|
---|
| 393 | QObject *object = QDeclarativeDebugService::objectForId(objectId);
|
---|
| 394 |
|
---|
| 395 | QByteArray reply;
|
---|
| 396 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 397 | rs << QByteArray("FETCH_OBJECT_R") << queryId;
|
---|
| 398 |
|
---|
| 399 | if (object)
|
---|
| 400 | buildObjectDump(rs, object, recurse, dumpProperties);
|
---|
| 401 |
|
---|
| 402 | sendMessage(reply);
|
---|
| 403 | } else if (type == "WATCH_OBJECT") {
|
---|
| 404 | int queryId;
|
---|
| 405 | int objectId;
|
---|
| 406 |
|
---|
| 407 | ds >> queryId >> objectId;
|
---|
| 408 | bool ok = m_watch->addWatch(queryId, objectId);
|
---|
| 409 |
|
---|
| 410 | QByteArray reply;
|
---|
| 411 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 412 | rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
|
---|
| 413 |
|
---|
| 414 | sendMessage(reply);
|
---|
| 415 | } else if (type == "WATCH_PROPERTY") {
|
---|
| 416 | int queryId;
|
---|
| 417 | int objectId;
|
---|
| 418 | QByteArray property;
|
---|
| 419 |
|
---|
| 420 | ds >> queryId >> objectId >> property;
|
---|
| 421 | bool ok = m_watch->addWatch(queryId, objectId, property);
|
---|
| 422 |
|
---|
| 423 | QByteArray reply;
|
---|
| 424 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 425 | rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
|
---|
| 426 |
|
---|
| 427 | sendMessage(reply);
|
---|
| 428 | } else if (type == "WATCH_EXPR_OBJECT") {
|
---|
| 429 | int queryId;
|
---|
| 430 | int debugId;
|
---|
| 431 | QString expr;
|
---|
| 432 |
|
---|
| 433 | ds >> queryId >> debugId >> expr;
|
---|
| 434 | bool ok = m_watch->addWatch(queryId, debugId, expr);
|
---|
| 435 |
|
---|
| 436 | QByteArray reply;
|
---|
| 437 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 438 | rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
|
---|
| 439 | sendMessage(reply);
|
---|
| 440 | } else if (type == "NO_WATCH") {
|
---|
| 441 | int queryId;
|
---|
| 442 |
|
---|
| 443 | ds >> queryId;
|
---|
| 444 | m_watch->removeWatch(queryId);
|
---|
| 445 | } else if (type == "EVAL_EXPRESSION") {
|
---|
| 446 | int queryId;
|
---|
| 447 | int objectId;
|
---|
| 448 | QString expr;
|
---|
| 449 |
|
---|
| 450 | ds >> queryId >> objectId >> expr;
|
---|
| 451 |
|
---|
| 452 | QObject *object = QDeclarativeDebugService::objectForId(objectId);
|
---|
| 453 | QDeclarativeContext *context = qmlContext(object);
|
---|
| 454 | QVariant result;
|
---|
| 455 | if (object && context) {
|
---|
| 456 | QDeclarativeExpression exprObj(context, object, expr);
|
---|
| 457 | bool undefined = false;
|
---|
| 458 | QVariant value = exprObj.evaluate(&undefined);
|
---|
| 459 | if (undefined)
|
---|
| 460 | result = QLatin1String("<undefined>");
|
---|
| 461 | else
|
---|
| 462 | result = valueContents(value);
|
---|
| 463 | } else {
|
---|
| 464 | result = QLatin1String("<unknown context>");
|
---|
| 465 | }
|
---|
| 466 |
|
---|
| 467 | QByteArray reply;
|
---|
| 468 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 469 | rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
|
---|
| 470 |
|
---|
| 471 | sendMessage(reply);
|
---|
| 472 | } else if (type == "SET_BINDING") {
|
---|
| 473 | int objectId;
|
---|
| 474 | QString propertyName;
|
---|
| 475 | QVariant expr;
|
---|
| 476 | bool isLiteralValue;
|
---|
| 477 | ds >> objectId >> propertyName >> expr >> isLiteralValue;
|
---|
| 478 | setBinding(objectId, propertyName, expr, isLiteralValue);
|
---|
| 479 | } else if (type == "RESET_BINDING") {
|
---|
| 480 | int objectId;
|
---|
| 481 | QString propertyName;
|
---|
| 482 | ds >> objectId >> propertyName;
|
---|
| 483 | resetBinding(objectId, propertyName);
|
---|
| 484 | } else if (type == "SET_METHOD_BODY") {
|
---|
| 485 | int objectId;
|
---|
| 486 | QString methodName;
|
---|
| 487 | QString methodBody;
|
---|
| 488 | ds >> objectId >> methodName >> methodBody;
|
---|
| 489 | setMethodBody(objectId, methodName, methodBody);
|
---|
| 490 | }
|
---|
| 491 | }
|
---|
| 492 |
|
---|
| 493 | void QDeclarativeEngineDebugServer::setBinding(int objectId,
|
---|
| 494 | const QString &propertyName,
|
---|
| 495 | const QVariant &expression,
|
---|
| 496 | bool isLiteralValue)
|
---|
| 497 | {
|
---|
| 498 | QObject *object = objectForId(objectId);
|
---|
| 499 | QDeclarativeContext *context = qmlContext(object);
|
---|
| 500 |
|
---|
| 501 | if (object && context) {
|
---|
| 502 |
|
---|
| 503 | QDeclarativeProperty property(object, propertyName, context);
|
---|
| 504 | if (isLiteralValue) {
|
---|
| 505 | property.write(expression);
|
---|
| 506 | } else if (hasValidSignal(object, propertyName)) {
|
---|
| 507 | QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString());
|
---|
| 508 | QDeclarativeExpression *oldExpression = QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression);
|
---|
| 509 | declarativeExpression->setSourceLocation(oldExpression->sourceFile(), oldExpression->lineNumber());
|
---|
| 510 | } else if (property.isProperty()) {
|
---|
| 511 | QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context);
|
---|
| 512 | binding->setTarget(property);
|
---|
| 513 | binding->setNotifyOnValueChanged(true);
|
---|
| 514 | QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding);
|
---|
| 515 | if (oldBinding)
|
---|
| 516 | oldBinding->destroy();
|
---|
| 517 | binding->update();
|
---|
| 518 | } else {
|
---|
| 519 | qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object;
|
---|
| 520 | }
|
---|
| 521 | }
|
---|
| 522 | }
|
---|
| 523 |
|
---|
| 524 | void QDeclarativeEngineDebugServer::resetBinding(int objectId, const QString &propertyName)
|
---|
| 525 | {
|
---|
| 526 | QObject *object = objectForId(objectId);
|
---|
| 527 | QDeclarativeContext *context = qmlContext(object);
|
---|
| 528 |
|
---|
| 529 | if (object && context) {
|
---|
| 530 | if (object->property(propertyName.toLatin1()).isValid()) {
|
---|
| 531 | QDeclarativeProperty property(object, propertyName);
|
---|
| 532 | QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(property);
|
---|
| 533 | if (oldBinding) {
|
---|
| 534 | QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, 0);
|
---|
| 535 | if (oldBinding)
|
---|
| 536 | oldBinding->destroy();
|
---|
| 537 | } else {
|
---|
| 538 | if (property.isResettable()) {
|
---|
| 539 | property.reset();
|
---|
| 540 | }
|
---|
| 541 | }
|
---|
| 542 | }
|
---|
| 543 | }
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 | void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &method, const QString &body)
|
---|
| 547 | {
|
---|
| 548 | QObject *object = objectForId(objectId);
|
---|
| 549 | QDeclarativeContext *context = qmlContext(object);
|
---|
| 550 | if (!object || !context || !context->engine())
|
---|
| 551 | return;
|
---|
| 552 | QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
|
---|
| 553 | if (!contextData)
|
---|
| 554 | return;
|
---|
| 555 |
|
---|
| 556 | QDeclarativePropertyCache::Data dummy;
|
---|
| 557 | QDeclarativePropertyCache::Data *prop =
|
---|
| 558 | QDeclarativePropertyCache::property(context->engine(), object, method, dummy);
|
---|
| 559 |
|
---|
| 560 | if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction))
|
---|
| 561 | return;
|
---|
| 562 |
|
---|
| 563 | QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
|
---|
| 564 | QList<QByteArray> paramNames = metaMethod.parameterNames();
|
---|
| 565 |
|
---|
| 566 | QString paramStr;
|
---|
| 567 | for (int ii = 0; ii < paramNames.count(); ++ii) {
|
---|
| 568 | if (ii != 0) paramStr.append(QLatin1String(","));
|
---|
| 569 | paramStr.append(QString::fromUtf8(paramNames.at(ii)));
|
---|
| 570 | }
|
---|
| 571 |
|
---|
| 572 | QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr +
|
---|
| 573 | QLatin1String(") {");
|
---|
| 574 | jsfunction += body;
|
---|
| 575 | jsfunction += QLatin1String("\n})");
|
---|
| 576 |
|
---|
| 577 | QDeclarativeVMEMetaObject *vmeMetaObject =
|
---|
| 578 | static_cast<QDeclarativeVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
|
---|
| 579 | Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
|
---|
| 580 |
|
---|
| 581 | int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
|
---|
| 582 | vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0));
|
---|
| 583 | }
|
---|
| 584 |
|
---|
| 585 | void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
|
---|
| 586 | {
|
---|
| 587 | QByteArray reply;
|
---|
| 588 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 589 |
|
---|
| 590 | rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
|
---|
| 591 |
|
---|
| 592 | sendMessage(reply);
|
---|
| 593 | }
|
---|
| 594 |
|
---|
| 595 | void QDeclarativeEngineDebugServer::addEngine(QDeclarativeEngine *engine)
|
---|
| 596 | {
|
---|
| 597 | Q_ASSERT(engine);
|
---|
| 598 | Q_ASSERT(!m_engines.contains(engine));
|
---|
| 599 |
|
---|
| 600 | m_engines.append(engine);
|
---|
| 601 | }
|
---|
| 602 |
|
---|
| 603 | void QDeclarativeEngineDebugServer::remEngine(QDeclarativeEngine *engine)
|
---|
| 604 | {
|
---|
| 605 | Q_ASSERT(engine);
|
---|
| 606 | Q_ASSERT(m_engines.contains(engine));
|
---|
| 607 |
|
---|
| 608 | m_engines.removeAll(engine);
|
---|
| 609 | }
|
---|
| 610 |
|
---|
| 611 | void QDeclarativeEngineDebugServer::objectCreated(QDeclarativeEngine *engine, QObject *object)
|
---|
| 612 | {
|
---|
| 613 | Q_ASSERT(engine);
|
---|
| 614 | Q_ASSERT(m_engines.contains(engine));
|
---|
| 615 |
|
---|
| 616 | int engineId = QDeclarativeDebugService::idForObject(engine);
|
---|
| 617 | int objectId = QDeclarativeDebugService::idForObject(object);
|
---|
| 618 |
|
---|
| 619 | QByteArray reply;
|
---|
| 620 | QDataStream rs(&reply, QIODevice::WriteOnly);
|
---|
| 621 |
|
---|
| 622 | rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
|
---|
| 623 | sendMessage(reply);
|
---|
| 624 | }
|
---|
| 625 |
|
---|
| 626 | QT_END_NAMESPACE
|
---|