diff -r 5dc02b23752f -r 3e2da88830cd src/declarative/qml/qdeclarativeenginedebug.cpp --- a/src/declarative/qml/qdeclarativeenginedebug.cpp Tue Jul 06 15:10:48 2010 +0300 +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp Wed Aug 18 10:37:55 2010 +0300 @@ -50,6 +50,8 @@ #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativewatcher_p.h" #include "private/qdeclarativevaluetype_p.h" +#include "private/qdeclarativevmemetaobject_p.h" +#include "private/qdeclarativeexpression_p.h" #include #include @@ -59,7 +61,7 @@ QList QDeclarativeEngineDebugServer::m_engines; QDeclarativeEngineDebugServer::QDeclarativeEngineDebugServer(QObject *parent) : QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent), - m_watch(new QDeclarativeWatcher(this)) + m_watch(new QDeclarativeWatcher(this)) { QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)), this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant))); @@ -99,6 +101,29 @@ return ds; } +static inline bool isSignalPropertyName(const QString &signalName) +{ + // see QmlCompiler::isSignalPropertyName + return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) && + signalName.at(2).isLetter() && signalName.at(2).isUpper(); +} + +static bool hasValidSignal(QObject *object, const QString &propertyName) +{ + if (!isSignalPropertyName(propertyName)) + return false; + + QString signalName = propertyName.mid(2); + signalName[0] = signalName.at(0).toLower(); + + int sigIdx = QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex(); + + if (sigIdx == -1) + return false; + + return true; +} + QDeclarativeEngineDebugServer::QDeclarativeObjectProperty QDeclarativeEngineDebugServer::propertyData(QObject *obj, int propIdx) { @@ -396,7 +421,6 @@ QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok; - sendMessage(reply); } else if (type == "NO_WATCH") { int queryId; @@ -430,9 +454,120 @@ rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; sendMessage(reply); + } else if (type == "SET_BINDING") { + int objectId; + QString propertyName; + QVariant expr; + bool isLiteralValue; + ds >> objectId >> propertyName >> expr >> isLiteralValue; + setBinding(objectId, propertyName, expr, isLiteralValue); + } else if (type == "RESET_BINDING") { + int objectId; + QString propertyName; + ds >> objectId >> propertyName; + resetBinding(objectId, propertyName); + } else if (type == "SET_METHOD_BODY") { + int objectId; + QString methodName; + QString methodBody; + ds >> objectId >> methodName >> methodBody; + setMethodBody(objectId, methodName, methodBody); } } +void QDeclarativeEngineDebugServer::setBinding(int objectId, + const QString &propertyName, + const QVariant &expression, + bool isLiteralValue) +{ + QObject *object = objectForId(objectId); + QDeclarativeContext *context = qmlContext(object); + + if (object && context) { + + if (isLiteralValue) { + QDeclarativeProperty literalProperty(object, propertyName, context); + literalProperty.write(expression); + } else { + if (hasValidSignal(object, propertyName)) { + QDeclarativeProperty property(object, propertyName); + QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString()); + QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression); + } else { + QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context); + QDeclarativeProperty property(object, propertyName, context); + binding->setTarget(property); + binding->setNotifyOnValueChanged(true); + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding); + if (oldBinding) + oldBinding->destroy(); + binding->update(); + } + } + } +} + +void QDeclarativeEngineDebugServer::resetBinding(int objectId, const QString &propertyName) +{ + QObject *object = objectForId(objectId); + QDeclarativeContext *context = qmlContext(object); + + if (object && context) { + if (object->property(propertyName.toLatin1()).isValid()) { + QDeclarativeProperty property(object, propertyName); + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(property); + if (oldBinding) { + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, 0); + if (oldBinding) + oldBinding->destroy(); + } else { + if (property.isResettable()) { + property.reset(); + } + } + } + } +} + +void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &method, const QString &body) +{ + QObject *object = objectForId(objectId); + QDeclarativeContext *context = qmlContext(object); + if (!object || !context || !context->engine()) + return; + QDeclarativeContextData *contextData = QDeclarativeContextData::get(context); + if (!contextData) + return; + + QDeclarativePropertyCache::Data dummy; + QDeclarativePropertyCache::Data *prop = + QDeclarativePropertyCache::property(context->engine(), object, method, dummy); + + if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction)) + return; + + QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex); + QList paramNames = metaMethod.parameterNames(); + + QString paramStr; + for (int ii = 0; ii < paramNames.count(); ++ii) { + if (ii != 0) paramStr.append(QLatin1String(",")); + paramStr.append(QString::fromUtf8(paramNames.at(ii))); + } + + QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr + + QLatin1String(") {"); + jsfunction += body; + jsfunction += QLatin1String("\n})"); + + QDeclarativeVMEMetaObject *vmeMetaObject = + static_cast(QObjectPrivate::get(object)->metaObject); + Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this + + int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); + vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0)); +} + void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) { QByteArray reply;