From 3c7528d57275d4ee05ad9a9c11786e3ef1fc8edf Mon Sep 17 00:00:00 2001
From: Olivier Goffart <olivier.goffart@nokia.com>
Date: Wed, 21 Jul 2010 13:04:06 +0200
Subject: [PATCH] QmlJsDelta: refactor to split the stuff specific to the QML
 Live Preview out

---
 src/plugins/qmljsinspector/qmljsdelta.cpp     | 209 ++----------------
 src/plugins/qmljsinspector/qmljsdelta.h       |  36 +--
 .../qmljsinspector/qmljslivetextpreview.cpp   | 141 +++++++++++-
 3 files changed, 166 insertions(+), 220 deletions(-)

diff --git a/src/plugins/qmljsinspector/qmljsdelta.cpp b/src/plugins/qmljsinspector/qmljsdelta.cpp
index cf3a69fa940..22918aa90e3 100644
--- a/src/plugins/qmljsinspector/qmljsdelta.cpp
+++ b/src/plugins/qmljsinspector/qmljsdelta.cpp
@@ -315,9 +315,6 @@ static QHash<QString, UiObjectMember*> extractProperties(UiObjectDefinition *obj
 
 void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const QList<QDeclarativeDebugObjectReference > &debugReferences, const Document::Ptr &doc)
 {
-    if (doNotSendChanges)
-        return;
-
     if (!member || !parentMember)
         return;
 
@@ -341,8 +338,7 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q
                          + QLatin1Char(':') + QString::number(uiObjectDef->firstSourceLocation().startLine-importList.count());
         foreach(const QDeclarativeDebugObjectReference &ref, debugReferences) {
             if (ref.debugId() != -1) {
-                _referenceRefreshRequired = true;
-                ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
+                createObject(qmlText, ref, importList, filename);
             }
         }
         newObjects += member;
@@ -354,9 +350,6 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol
                    UiObjectDefinition* newObject, const QmlJS::Document::Ptr& newDoc,
                    const QList< QDeclarativeDebugObjectReference >& debugReferences)
 {
-    if (doNotSendChanges)
-        return;
-
     Q_ASSERT (oldObject && newObject);
     QSet<QString> presentBinding;
 
@@ -391,18 +384,15 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol
         }
     }
 
-    if (doNotSendChanges)
-        return;
-
     //reset property that are not present in the new object.
     for (QHash<QString, UiObjectMember *>::const_iterator it2 = oldProperties.constBegin();
          it2 != oldProperties.constEnd(); ++it2) {
 
         if (!newProperties.contains(it2.key())) {
-            if (UiScriptBinding *previousScript = cast<UiScriptBinding *>(*it2)) {
+            if (cast<UiScriptBinding *>(*it2)) {
                 foreach (const QDeclarativeDebugObjectReference &ref, debugReferences) {
                     if (ref.debugId() != -1)
-                        ClientProxy::instance()->resetBindingForObject(ref.debugId(), it2.key()); // ### remove
+                        resetBindingForObject(ref.debugId(), it2.key());
                 }
             }
         }
@@ -413,7 +403,7 @@ void Delta::remove(const QList< QDeclarativeDebugObjectReference >& debugReferen
 {
     foreach (const QDeclarativeDebugObjectReference &ref, debugReferences) {
         if (ref.debugId() != -1)
-            ClientProxy::instance()->destroyQmlObject(ref.debugId()); // ### remove
+            removeObject(ref.debugId());
     }
 }
 
@@ -426,7 +416,6 @@ Delta::DebugIdMap Delta::operator()(const Document::Ptr &doc1, const Document::P
     QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > newDebuggIds;
 
     Map M = Mapping(doc1, doc2);
-    _referenceRefreshRequired = false;
 
     BuildParentHash parents2;
     doc2->qmlProgram()->accept(&parents2);
@@ -486,186 +475,28 @@ Delta::DebugIdMap Delta::operator()(const Document::Ptr &doc1, const Document::P
     return newDebuggIds;
 }
 
-static bool isLiteralValue(ExpressionNode *expr)
-{
-    if (cast<NumericLiteral*>(expr))
-        return true;
-    else if (cast<StringLiteral*>(expr))
-        return true;
-    else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
-        return isLiteralValue(plusExpr->expression);
-    else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
-        return isLiteralValue(minusExpr->expression);
-    else if (cast<TrueLiteral*>(expr))
-        return true;
-    else if (cast<FalseLiteral*>(expr))
-        return true;
-    else
-        return false;
-}
-
-static inline bool isLiteralValue(UiScriptBinding *script)
-{
-    if (!script || !script->statement)
-        return false;
-
-    ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement);
-    if (exprStmt)
-        return isLiteralValue(exprStmt->expression);
-    else
-        return false;
-}
-
-static inline QString stripQuotes(const QString &str)
-{
-    if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
-            || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
-        return str.mid(1, str.length() - 2);
-
-    return str;
-}
-
-static inline QString deEscape(const QString &value)
-{
-    QString result = value;
-
-    result.replace(QLatin1String("\\\\"), QLatin1String("\\"));
-    result.replace(QLatin1String("\\\""), QLatin1String("\""));
-    result.replace(QLatin1String("\\\t"), QLatin1String("\t"));
-    result.replace(QLatin1String("\\\r"), QLatin1String("\\\r"));
-    result.replace(QLatin1String("\\\n"), QLatin1String("\n"));
-
-    return result;
-}
-
-static QString cleanExpression(const QString &expression, UiScriptBinding *scriptBinding)
-{
-    QString trimmedExpression = expression.trimmed();
-
-    if (ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement)) {
-        if (expStatement->semicolonToken.isValid())
-            trimmedExpression.chop(1);
-    }
-
-    return deEscape(stripQuotes(trimmedExpression));
-}
-
-static QVariant castToLiteral(const QString &expression, UiScriptBinding *scriptBinding)
-{
-    const QString cleanedValue = cleanExpression(expression, scriptBinding);
-    QVariant castedExpression;
-
-    ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement);
-
-    switch(expStatement->expression->kind) {
-    case Node::Kind_NumericLiteral:
-    case Node::Kind_UnaryPlusExpression:
-    case Node::Kind_UnaryMinusExpression:
-        castedExpression = QVariant(cleanedValue).toReal();
-        break;
-    case Node::Kind_StringLiteral:
-        castedExpression = QVariant(cleanedValue).toString();
-        break;
-    case Node::Kind_TrueLiteral:
-    case Node::Kind_FalseLiteral:
-        castedExpression = QVariant(cleanedValue).toBool();
-        break;
-    default:
-        castedExpression = cleanedValue;
-        break;
-    }
-
-    return castedExpression;
-}
-
-void Delta::updateMethodBody(const QDeclarativeDebugObjectReference &objectReference,
-                               UiScriptBinding *scriptBinding,
-                               const QString &methodName,
-                               const QString &methodBody)
-{
-    Change change;
-    change.script = scriptBinding;
-    change.ref = objectReference;
-    change.isLiteral = false;
-    _changes.append(change);
-
-    ClientProxy::instance()->setMethodBodyForObject(objectReference.debugId(), methodName, methodBody); // ### remove
-}
-
-void Delta::updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference,
-                                UiScriptBinding *scriptBinding,
-                                const QString &propertyName,
-                                const QString &scriptCode)
-{
-    if (doNotSendChanges)
-        return;
-    QVariant expr = scriptCode;
-
-    const bool isLiteral = isLiteralValue(scriptBinding);
-    if (isLiteral)
-        expr = castToLiteral(scriptCode, scriptBinding);
-
-    Change change;
-    change.script = scriptBinding;
-    change.ref = objectReference;
-    change.isLiteral = isLiteral;
-    _changes.append(change);
-
-    ClientProxy::instance()->setBindingForObject(objectReference.debugId(), propertyName, expr, isLiteral); // ### remove
-}
-
-bool Delta::compare(UiQualifiedId *id, UiQualifiedId *other)
-{
-    if (id == other)
-        return true;
-
-    else if (id && other) {
-        if (id->name && other->name) {
-            if (id->name->asString() == other->name->asString())
-                return compare(id->next, other->next);
-        }
-    }
-
-    return false;
-}
-
-bool Delta::compare(UiSourceElement *source, UiSourceElement *other)
-{
-    if (source == other)
-        return true;
-
-    else if (source && other) {
-        if (source->sourceElement && other->sourceElement) {
-            FunctionDeclaration *decl = cast<FunctionDeclaration*>(source->sourceElement);
-            FunctionDeclaration *otherDecl = cast<FunctionDeclaration*>(other->sourceElement);
-            if (decl && otherDecl
-                && decl->name && otherDecl->name
-                && decl->name->asString() == otherDecl->name->asString())
-            {
-                    return true;
-            }
-        }
-    }
-
-    return false;
-}
-
 Document::Ptr Delta::document() const
 {
-    return _doc;
+    return m_currentDoc;
 }
 
 Document::Ptr Delta::previousDocument() const
 {
-    return _previousDoc;
+    return m_previousDoc;
 }
 
-QList<Delta::Change> Delta::changes() const
-{
-    return _changes;
-}
+void QmlJSInspector::Internal::Delta::createObject(const QString &, const QDeclarativeDebugObjectReference &,
+                                                   const QStringList &, const QString&)
+{}
+void QmlJSInspector::Internal::Delta::removeObject(int)
+{}
+void QmlJSInspector::Internal::Delta::resetBindingForObject(int, const QString &)
+{}
+void QmlJSInspector::Internal::Delta::updateMethodBody(const QDeclarativeDebugObjectReference &,
+                                                       UiScriptBinding *, const QString &, const QString &)
+{}
+
+void QmlJSInspector::Internal::Delta::updateScriptBinding(const QDeclarativeDebugObjectReference &,
+                                                          UiScriptBinding *, const QString &, const QString &)
+{}
 
-bool Delta::referenceRefreshRequired() const
-{
-    return _referenceRefreshRequired;
-}
diff --git a/src/plugins/qmljsinspector/qmljsdelta.h b/src/plugins/qmljsinspector/qmljsdelta.h
index 7033b506916..4354e0da815 100644
--- a/src/plugins/qmljsinspector/qmljsdelta.h
+++ b/src/plugins/qmljsinspector/qmljsdelta.h
@@ -46,34 +46,15 @@ namespace Internal {
 class Delta
 {
 public:
-    Delta() : doNotSendChanges(false) {}
-
-    bool doNotSendChanges;
     QSet<UiObjectMember *> newObjects;
 
-    struct Change {
-        Change(): script(0), isLiteral(false) {}
-
-        QmlJS::AST::UiScriptBinding *script;
-        bool isLiteral;
-        QDeclarativeDebugObjectReference ref;
-    };
-
     typedef QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > DebugIdMap;
     DebugIdMap operator()(const QmlJS::Document::Ptr &doc1, const QmlJS::Document::Ptr &doc2, const DebugIdMap &debugIds);
 
-    QList<Change> changes() const;
 
     QmlJS::Document::Ptr document() const;
     QmlJS::Document::Ptr previousDocument() const;
 
-public:
-    bool referenceRefreshRequired() const;
-    static bool compare(UiSourceElement *source, UiSourceElement *other);
-    static bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other);
-    static QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object);
-
-
 private:
     void insert(UiObjectMember *member, UiObjectMember *parentMember,
                 const QList<QDeclarativeDebugObjectReference> &debugReferences, const Document::Ptr &doc);
@@ -82,22 +63,23 @@ private:
                 const QList<QDeclarativeDebugObjectReference >& debugReferences);
     void remove(const QList< QDeclarativeDebugObjectReference > &debugReferences);
 
-    void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference,
+protected:
+    virtual void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference,
                              QmlJS::AST::UiScriptBinding *scriptBinding,
                              const QString &propertyName,
                              const QString &scriptCode);
-    void updateMethodBody(const QDeclarativeDebugObjectReference &objectReference,
+    virtual void updateMethodBody(const QDeclarativeDebugObjectReference &objectReference,
                             UiScriptBinding *scriptBinding,
                             const QString &methodName,
                             const QString &methodBody);
-
+    virtual void resetBindingForObject(int debugId, const QString &propertyName);
+    virtual void removeObject(int debugId);
+    virtual void createObject(const QString &qmlText, const QDeclarativeDebugObjectReference &ref,
+                         const QStringList &importList, const QString &filename);
 
 private:
-    QmlJS::Document::Ptr _doc;
-    QmlJS::Document::Ptr _previousDoc;
-    QList<Change> _changes;
-    QUrl _url;
-    bool _referenceRefreshRequired;
+    QmlJS::Document::Ptr m_currentDoc;
+    QmlJS::Document::Ptr m_previousDoc;
 };
 
 } // namespace Internal
diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
index 176c4cfb2a8..db71a515f0d 100644
--- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
+++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
@@ -269,7 +269,6 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference
         m_debugIds = visitor.result;
         if (doc != m_previousDoc) {
             Delta delta;
-            delta.doNotSendChanges = true;
             m_debugIds = delta(doc, m_previousDoc, m_debugIds);
         }
     }
@@ -301,7 +300,6 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference
         Delta::DebugIdMap debugIds = visitor.result;
         if (doc != m_previousDoc) {
             Delta delta;
-            delta.doNotSendChanges = true;
             debugIds = delta(doc, m_previousDoc, debugIds);
         }
         for(Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin();
@@ -311,6 +309,141 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference
     }
 }
 
+
+class UpdateObserver : public Delta {
+private:
+    static inline QString stripQuotes(const QString &str)
+    {
+        if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
+                || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
+            return str.mid(1, str.length() - 2);
+
+        return str;
+    }
+
+    static inline QString deEscape(const QString &value)
+    {
+        QString result = value;
+
+        result.replace(QLatin1String("\\\\"), QLatin1String("\\"));
+        result.replace(QLatin1String("\\\""), QLatin1String("\""));
+        result.replace(QLatin1String("\\\t"), QLatin1String("\t"));
+        result.replace(QLatin1String("\\\r"), QLatin1String("\\\r"));
+        result.replace(QLatin1String("\\\n"), QLatin1String("\n"));
+
+        return result;
+    }
+
+    static QString cleanExpression(const QString &expression, UiScriptBinding *scriptBinding)
+    {
+        QString trimmedExpression = expression.trimmed();
+
+        if (ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement)) {
+            if (expStatement->semicolonToken.isValid())
+                trimmedExpression.chop(1);
+        }
+
+        return deEscape(stripQuotes(trimmedExpression));
+    }
+
+    static bool isLiteralValue(ExpressionNode *expr)
+    {
+        if (cast<NumericLiteral*>(expr))
+            return true;
+        else if (cast<StringLiteral*>(expr))
+            return true;
+        else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
+            return isLiteralValue(plusExpr->expression);
+        else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
+            return isLiteralValue(minusExpr->expression);
+        else if (cast<TrueLiteral*>(expr))
+            return true;
+        else if (cast<FalseLiteral*>(expr))
+            return true;
+        else
+            return false;
+    }
+
+    static inline bool isLiteralValue(UiScriptBinding *script)
+    {
+        if (!script || !script->statement)
+            return false;
+
+        ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement);
+        if (exprStmt)
+            return isLiteralValue(exprStmt->expression);
+        else
+            return false;
+    }
+
+    static QVariant castToLiteral(const QString &expression, UiScriptBinding *scriptBinding)
+    {
+        const QString cleanedValue = cleanExpression(expression, scriptBinding);
+        QVariant castedExpression;
+
+        ExpressionStatement *expStatement = cast<ExpressionStatement*>(scriptBinding->statement);
+
+        switch(expStatement->expression->kind) {
+            case Node::Kind_NumericLiteral:
+            case Node::Kind_UnaryPlusExpression:
+            case Node::Kind_UnaryMinusExpression:
+                castedExpression = QVariant(cleanedValue).toReal();
+                break;
+            case Node::Kind_StringLiteral:
+                castedExpression = QVariant(cleanedValue).toString();
+                break;
+            case Node::Kind_TrueLiteral:
+            case Node::Kind_FalseLiteral:
+                castedExpression = QVariant(cleanedValue).toBool();
+                break;
+            default:
+                castedExpression = cleanedValue;
+                break;
+        }
+
+        return castedExpression;
+    }
+
+protected:
+    virtual void updateMethodBody(const QDeclarativeDebugObjectReference& objectReference,
+                                  UiScriptBinding* scriptBinding, const QString& methodName, const QString& methodBody)
+    {
+        Q_UNUSED(scriptBinding);
+        ClientProxy::instance()->setMethodBodyForObject(objectReference.debugId(), methodName, methodBody);
+    }
+
+    virtual void updateScriptBinding(const QDeclarativeDebugObjectReference& objectReference,
+                                     UiScriptBinding* scriptBinding, const QString& propertyName, const QString& scriptCode)
+    {
+        QVariant expr = scriptCode;
+        const bool isLiteral = isLiteralValue(scriptBinding);
+        if (isLiteral)
+            expr = castToLiteral(scriptCode, scriptBinding);
+        ClientProxy::instance()->setBindingForObject(objectReference.debugId(), propertyName, expr, isLiteral);
+    }
+
+    virtual void resetBindingForObject(int debugId, const QString &propertyName)
+    {
+        ClientProxy::instance()->resetBindingForObject(debugId, propertyName);
+    }
+
+    virtual void removeObject(int debugId)
+    {
+        ClientProxy::instance()->destroyQmlObject(debugId);
+    }
+
+    virtual void createObject(const QString& qmlText, const QDeclarativeDebugObjectReference& ref,
+                         const QStringList& importList, const QString& filename)
+    {
+        referenceRefreshRequired = true;
+        ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
+    }
+
+public:
+    UpdateObserver() : referenceRefreshRequired(false) {}
+    bool referenceRefreshRequired;
+};
+
 void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
 {
     if (doc->fileName() != m_previousDoc->fileName())
@@ -325,10 +458,10 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
     if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
         && doc->qmlProgram() && m_previousDoc->qmlProgram())
     {
-        Delta delta;
+        UpdateObserver delta;
         m_debugIds = delta(m_previousDoc, doc, m_debugIds);
 
-        if (delta.referenceRefreshRequired())
+        if (delta.referenceRefreshRequired)
             ClientProxy::instance()->refreshObjectTree();
 
         m_previousDoc = doc;
-- 
GitLab