src/declarative/qml/qdeclarativeenginedebug.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- 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 <QtCore/qdebug.h>
 #include <QtCore/qmetaobject.h>
@@ -59,7 +61,7 @@
 QList<QDeclarativeEngine *> 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<QByteArray> 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<QDeclarativeVMEMetaObject*>(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;