From 1ce574f19efd5a5661a849940bb1df3770478a1b Mon Sep 17 00:00:00 2001
From: Olivier Goffart <olivier.goffart@nokia.com>
Date: Mon, 19 Jul 2010 15:10:36 +0200
Subject: [PATCH] Qml Live Preview: Match debug Id for new created objects.

---
 src/plugins/qmljsinspector/qmljsdelta.cpp     |  8 ++-
 src/plugins/qmljsinspector/qmljsdelta.h       |  1 +
 src/plugins/qmljsinspector/qmljsinspector.cpp |  2 +
 .../qmljsinspector/qmljslivetextpreview.cpp   | 68 +++++++++++++++++--
 .../qmljsinspector/qmljslivetextpreview.h     |  1 +
 .../qml/qmlobserver/editor/qmltoolbar.cpp     |  1 +
 6 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/src/plugins/qmljsinspector/qmljsdelta.cpp b/src/plugins/qmljsinspector/qmljsdelta.cpp
index 18cbc70e2c8..4c9c514b6d4 100644
--- a/src/plugins/qmljsinspector/qmljsdelta.cpp
+++ b/src/plugins/qmljsinspector/qmljsdelta.cpp
@@ -290,7 +290,8 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q
     if (UiObjectDefinition* uiObjectDef = cast<UiObjectDefinition *>(member)) {
         unsigned begin = uiObjectDef->firstSourceLocation().begin();
         unsigned end = uiObjectDef->lastSourceLocation().end();
-        QString qmlText = doc->source().mid(begin, end - begin);
+        QString qmlText = QString(uiObjectDef->firstSourceLocation().startColumn - 1, QLatin1Char(' '));
+        qmlText += doc->source().midRef(begin, end - begin);
         QStringList importList;
         for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
             if (!it->import)
@@ -301,12 +302,15 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q
             importList << doc->source().mid(importBegin, importEnd - importBegin);
         }
 
+        QString filename = doc->fileName() + QLatin1Char('_') + QString::number(doc->editorRevision())
+                         + 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, doc->fileName());
+                ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
             }
         }
+        newObjects += member;
     }
 }
 
diff --git a/src/plugins/qmljsinspector/qmljsdelta.h b/src/plugins/qmljsinspector/qmljsdelta.h
index c03769bccd0..7033b506916 100644
--- a/src/plugins/qmljsinspector/qmljsdelta.h
+++ b/src/plugins/qmljsinspector/qmljsdelta.h
@@ -49,6 +49,7 @@ public:
     Delta() : doNotSendChanges(false) {}
 
     bool doNotSendChanges;
+    QSet<UiObjectMember *> newObjects;
 
     struct Change {
         Change(): script(0), isLiteral(false) {}
diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp
index 5a464f58e7d..f1a76c3556f 100644
--- a/src/plugins/qmljsinspector/qmljsinspector.cpp
+++ b/src/plugins/qmljsinspector/qmljsinspector.cpp
@@ -251,6 +251,8 @@ void Inspector::createPreviewForEditor(Core::IEditor *newEditor)
     if (newEditor && newEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
         QString filename = newEditor->file()->fileName();
         QmlJS::Document::Ptr doc = modelManager()->snapshot().document(filename);
+        if (!doc || !doc->qmlProgram())
+            return;
 
         if (m_textPreviews.contains(filename)) {
             m_textPreviews.value(filename)->associateEditor(newEditor);
diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
index fc61e949ebe..0bdc0f12687 100644
--- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
+++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
@@ -29,23 +29,51 @@ namespace Internal {
 class MapObjectWithDebugReference : public Visitor
 {
     public:
+        MapObjectWithDebugReference() : activated(0) {}
         virtual void endVisit(UiObjectDefinition *ast) ;
         virtual void endVisit(UiObjectBinding *ast) ;
+        virtual bool visit(UiObjectDefinition *ast) ;
+        virtual bool visit(UiObjectBinding *ast) ;
 
         QDeclarativeDebugObjectReference root;
         QString filename;
         QHash<UiObjectMember *, QList<QDeclarativeDebugObjectReference> > result;
+        QSet<QmlJS::AST::UiObjectMember *> lookupObjects;
+        Document::Ptr doc;
     private:
+        int activated;
         void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast);
 };
 
+bool MapObjectWithDebugReference::visit(UiObjectDefinition* ast)
+{
+    if (lookupObjects.contains(ast))
+        activated++;
+    return true;
+}
+
+bool MapObjectWithDebugReference::visit(UiObjectBinding* ast)
+{
+    if (lookupObjects.contains(ast))
+        activated++;
+    return true;
+}
+
 void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast)
 {
-    processRecursive(root, ast);
+    if (lookupObjects.isEmpty() || activated)
+        processRecursive(root, ast);
+
+    if (lookupObjects.contains(ast))
+        activated--;
 }
 void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast)
 {
-    processRecursive(root, ast);
+    if (lookupObjects.isEmpty() || activated)
+        processRecursive(root, ast);
+
+    if (lookupObjects.contains(ast))
+        activated--;
 }
 
 void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast)
@@ -54,8 +82,16 @@ void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObject
     // the QDeclarativeDebugObjectReference by filename/loc in a fist pass
 
     SourceLocation loc = ast->firstSourceLocation();
-    if (object.source().lineNumber() == int(loc.startLine) && object.source().columnNumber() == int(loc.startColumn) && object.source().url().toLocalFile() == filename) {
-        result[ast] += object;
+    if (object.source().columnNumber() == int(loc.startColumn)) {
+        QString objectFileName = object.source().url().toLocalFile();
+        if (object.source().lineNumber() == int(loc.startLine) && objectFileName == filename) {
+            result[ast] += object;
+        } else if (doc && objectFileName.startsWith(filename + QLatin1Char('_') + QString::number(doc->editorRevision()) + QLatin1Char(':'))) {
+            bool ok;
+            int line = objectFileName.mid(objectFileName.lastIndexOf(':') + 1).toInt(&ok);
+            if (ok && int(loc.startLine) == line + object.source().lineNumber() - 1)
+                result[ast] += object;
+        }
     }
 
     foreach (const QDeclarativeDebugObjectReference &it, object.children()) {
@@ -214,6 +250,28 @@ void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference
         if (!r.isEmpty())
             m_debugIds[root] += r;
     }
+
+    // Map the node of the later created objects.
+    for(QHash<Document::Ptr,QSet<UiObjectMember*> >::const_iterator it = m_createdObjects.constBegin();
+        it != m_createdObjects.constEnd(); ++it) {
+
+        const QmlJS::Document::Ptr &doc = it.key();
+        MapObjectWithDebugReference visitor;
+        visitor.root = rootReference;
+        visitor.filename = doc->fileName();
+        visitor.lookupObjects = it.value();
+        visitor.doc = doc;
+        doc->qmlProgram()->accept(&visitor);
+
+        Delta::DebugIdMap debugIds = visitor.result;
+        Delta delta;
+        delta.doNotSendChanges = true;
+        debugIds = delta(doc, m_previousDoc, debugIds);
+        for(Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin();
+            it2 != debugIds.constEnd(); ++it2) {
+            m_debugIds[it2.key()] += it2.value();
+        }
+    }
 }
 
 void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
@@ -237,6 +295,8 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
             ClientProxy::instance()->refreshObjectTree();
 
         m_previousDoc = doc;
+        if (!delta.newObjects.isEmpty())
+            m_createdObjects[doc] += delta.newObjects;
     }
 }
 
diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.h b/src/plugins/qmljsinspector/qmljslivetextpreview.h
index 82651aa327c..1f2410a7be6 100644
--- a/src/plugins/qmljsinspector/qmljslivetextpreview.h
+++ b/src/plugins/qmljsinspector/qmljslivetextpreview.h
@@ -56,6 +56,7 @@ private:
 
 private:
     QHash<QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference> > m_debugIds;
+    QHash<QmlJS::Document::Ptr, QSet<QmlJS::AST::UiObjectMember *> > m_createdObjects;
 
     QmlJS::Document::Ptr m_previousDoc;
     QmlJS::Document::Ptr m_initialDoc; //the document that was loaded by the server
diff --git a/src/tools/qml/qmlobserver/editor/qmltoolbar.cpp b/src/tools/qml/qmlobserver/editor/qmltoolbar.cpp
index 06ba69f7c50..333616289c0 100644
--- a/src/tools/qml/qmlobserver/editor/qmltoolbar.cpp
+++ b/src/tools/qml/qmlobserver/editor/qmltoolbar.cpp
@@ -12,6 +12,7 @@ namespace QmlViewer {
 QmlToolbar::QmlToolbar(QWidget *parent) :
     QToolBar(parent),
     m_emitSignals(true),
+    m_isRunning(false),
     ui(new Ui)
 {
     ui->designmode = new QAction(QIcon(":/qml/images/designmode.png"), tr("Design Mode"), this);
-- 
GitLab