From e412a93006261ce6ae89b3cce1204fed41098b86 Mon Sep 17 00:00:00 2001 From: Aurindam Jana Date: Mon, 19 Mar 2012 15:58:47 +0100 Subject: [PATCH] QmlJSInspector: Query Objects Iteratively Currently all objects are recursively fetched when the root context is retrieved. This patch fetches objects on demand. Change-Id: Idf5c621ec38869dd5a676116bc4df528d7bb2fda Reviewed-by: Kai Koehne --- .../qmljsdebugclient/qmlenginedebugclient.cpp | 1 + .../qmljsdebugclient/qmlenginedebugclient.h | 20 ++++++++- .../qmljsinspector/qmljsclientproxy.cpp | 21 +++++++++- src/plugins/qmljsinspector/qmljsclientproxy.h | 3 ++ src/plugins/qmljsinspector/qmljsinspector.cpp | 41 ++++++++++++++----- src/plugins/qmljsinspector/qmljsinspector.h | 4 ++ .../qmljsinspector/qmljslivetextpreview.cpp | 29 +++++++++++-- .../qmljsinspector/qmljslivetextpreview.h | 5 ++- 8 files changed, 106 insertions(+), 18 deletions(-) diff --git a/src/libs/qmljsdebugclient/qmlenginedebugclient.cpp b/src/libs/qmljsdebugclient/qmlenginedebugclient.cpp index 3bf9858fbf2..9c58db74478 100644 --- a/src/libs/qmljsdebugclient/qmlenginedebugclient.cpp +++ b/src/libs/qmljsdebugclient/qmlenginedebugclient.cpp @@ -84,6 +84,7 @@ void QmlEngineDebugClient::decode(QDataStream &ds, o.m_source.m_lineNumber = data.lineNumber; o.m_source.m_columnNumber = data.columnNumber; o.m_contextDebugId = data.contextId; + o.m_needsMoreData = simple; if (simple) return; diff --git a/src/libs/qmljsdebugclient/qmlenginedebugclient.h b/src/libs/qmljsdebugclient/qmlenginedebugclient.h index b1a29e3b6b0..ce1dd722788 100644 --- a/src/libs/qmljsdebugclient/qmlenginedebugclient.h +++ b/src/libs/qmljsdebugclient/qmlenginedebugclient.h @@ -132,8 +132,8 @@ typedef QList QmlDebugEngineReferenceList; class QmlDebugObjectReference { public: - QmlDebugObjectReference() : m_debugId(-1), m_contextDebugId(-1) {} - QmlDebugObjectReference(int id) : m_debugId(id), m_contextDebugId(-1) {} + QmlDebugObjectReference() : m_debugId(-1), m_contextDebugId(-1), m_needsMoreData(false) {} + QmlDebugObjectReference(int id) : m_debugId(id), m_contextDebugId(-1), m_needsMoreData(false) {} int debugId() const { return m_debugId; } QString className() const { return m_className; } @@ -142,10 +142,25 @@ public: QmlDebugFileReference source() const { return m_source; } int contextDebugId() const { return m_contextDebugId; } + bool needsMoreData() const { return m_needsMoreData; } QList properties() const { return m_properties; } QList children() const { return m_children; } + bool insertObjectInTree(const QmlDebugObjectReference &obj) + { + for (int i = 0; i < m_children.count(); i++) { + if (m_children[i].debugId() == obj.debugId()) { + m_children.replace(i, obj); + return true; + } else { + if (m_children[i].insertObjectInTree(obj)) + return true; + } + } + return false; + } + private: friend class QmlEngineDebugClient; int m_debugId; @@ -154,6 +169,7 @@ private: QString m_name; QmlDebugFileReference m_source; int m_contextDebugId; + bool m_needsMoreData; QList m_properties; QList m_children; }; diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.cpp b/src/plugins/qmljsinspector/qmljsclientproxy.cpp index 490012341b5..83126d8809a 100644 --- a/src/plugins/qmljsinspector/qmljsclientproxy.cpp +++ b/src/plugins/qmljsinspector/qmljsclientproxy.cpp @@ -202,6 +202,18 @@ void ClientProxy::setSelectedItemsByObjectId( } } +void ClientProxy::addObjectToTree(const QmlDebugObjectReference &obj) +{ + int count = m_rootObjects.count(); + for (int i = 0; i < count; i++) { + if (m_rootObjects[i].insertObjectInTree(obj)) { + buildDebugIdHashRecursive(obj); + emit objectTreeUpdated(); + break; + } + } +} + QmlDebugObjectReference ClientProxy::objectReferenceForId(int debugId) const { foreach (const QmlDebugObjectReference& it, m_rootObjects) { @@ -482,6 +494,13 @@ void ClientProxy::contextChanged(const QVariant &value) } } +quint32 ClientProxy::fetchContextObject(const QmlDebugObjectReference& obj) +{ + log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString())); + + return m_engineClient->queryObject(obj); +} + void ClientProxy::fetchContextObjectRecursive( const QmlDebugContextReference& context) { @@ -492,7 +511,7 @@ void ClientProxy::fetchContextObjectRecursive( log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString())); - quint32 queryId = m_engineClient->queryObjectRecursive(obj); + quint32 queryId = fetchContextObject(obj); if (queryId) m_objectTreeQueryIds << queryId; } diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.h b/src/plugins/qmljsinspector/qmljsclientproxy.h index c893bb44c2d..4ae0bd6e406 100644 --- a/src/plugins/qmljsinspector/qmljsclientproxy.h +++ b/src/plugins/qmljsinspector/qmljsclientproxy.h @@ -93,6 +93,9 @@ public: Debugger::QmlAdapter *qmlAdapter() const; + quint32 fetchContextObject(const QmlDebugObjectReference& obj); + void addObjectToTree(const QmlDebugObjectReference &obj); + signals: void objectTreeUpdated(); void connectionStatusMessage(const QString &text); diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp index 73a1cfb9c49..9fef93c421a 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.cpp +++ b/src/plugins/qmljsinspector/qmljsinspector.cpp @@ -157,6 +157,7 @@ InspectorUi::InspectorUi(QObject *parent) , m_debugQuery(0) , m_selectionCallbackExpected(false) , m_cursorPositionChangedExternally(false) + , m_onCrumblePathClicked(false) { m_instance = this; m_toolBar = new QmlJsInspectorToolBar(this); @@ -281,6 +282,17 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE void InspectorUi::onResult(quint32 queryId, const QVariant &result) { + if (m_showObjectQueryId == queryId) { + m_showObjectQueryId = 0; + QmlDebugObjectReference obj = qvariant_cast(result); + m_clientProxy->addObjectToTree(obj); + if (m_onCrumblePathClicked) { + m_onCrumblePathClicked = false; + showObject(obj); + } + return; + } + if (m_debugQuery != queryId) return; @@ -559,21 +571,29 @@ void InspectorUi::selectItems(const QList &objectRefere // select only the first valid element of the list m_clientProxy->removeAllObjectWatches(); - m_clientProxy->addObjectWatch(debugId); - QList selectionList; - selectionList << objref; - m_propertyInspector->setCurrentObjects(selectionList); - populateCrumblePath(objref); - gotoObjectReferenceDefinition(objref); - Debugger::QmlAdapter *qmlAdapter = m_clientProxy->qmlAdapter(); - if (qmlAdapter) { - qmlAdapter->setCurrentSelectedDebugInfo(debugId, displayName(objref)); - } + //Check if the object is complete + if (objref.needsMoreData()) + m_showObjectQueryId = m_clientProxy->fetchContextObject(objref); + else + showObject(objref); break; } } } +void InspectorUi::showObject(const QmlDebugObjectReference &obj) +{ + m_clientProxy->addObjectWatch(obj.debugId()); + QList selectionList; + selectionList << obj; + m_propertyInspector->setCurrentObjects(selectionList); + populateCrumblePath(obj); + gotoObjectReferenceDefinition(obj); + Debugger::QmlAdapter *qmlAdapter = m_clientProxy->qmlAdapter(); + if (qmlAdapter) + qmlAdapter->setCurrentSelectedDebugInfo(obj.debugId(), displayName(obj)); +} + bool InspectorUi::isRoot(const QmlDebugObjectReference &obj) const { foreach (const QmlDebugObjectReference &rootObj, m_clientProxy->rootObjectReference()) @@ -768,6 +788,7 @@ void InspectorUi::crumblePathElementClicked(const QVariant &data) QList debugIds; debugIds << debugId; + m_onCrumblePathClicked = true; selectItems(debugIds); m_clientProxy->setSelectedItemsByDebugId(debugIds); } diff --git a/src/plugins/qmljsinspector/qmljsinspector.h b/src/plugins/qmljsinspector/qmljsinspector.h index 7514bd9a009..37d72e1cdf1 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.h +++ b/src/plugins/qmljsinspector/qmljsinspector.h @@ -150,6 +150,8 @@ private: void connectSignals(); void disconnectSignals(); + void showObject(const QmlDebugObjectReference &obj); + private: bool m_listeningToEditorManager; QmlJsInspectorToolBar *m_toolBar; @@ -161,6 +163,7 @@ private: ClientProxy *m_clientProxy; QObject *m_qmlEngine; quint32 m_debugQuery; + quint32 m_showObjectQueryId; // Qml/JS integration QHash m_textPreviews; @@ -172,6 +175,7 @@ private: static InspectorUi *m_instance; bool m_selectionCallbackExpected; bool m_cursorPositionChangedExternally; + bool m_onCrumblePathClicked; }; } // Internal diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index 07ec76ad915..0496e30b485 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -178,6 +178,8 @@ QmlJSLiveTextPreview::QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc, , m_initialDoc(initDoc) , m_applyChangesToQmlInspector(true) , m_clientProxy(clientProxy) + , m_nodeForOffset(0) + , m_updateNodeForOffset(false) { Q_ASSERT(doc->fileName() == initDoc->fileName()); m_filename = doc->fileName(); @@ -200,18 +202,33 @@ void QmlJSLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc) } -QList QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const +QList QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) { QList result; QHashIterator > iter(m_debugIds); + QmlJS::AST::UiObjectMember *possibleNode = 0; while(iter.hasNext()) { iter.next(); QmlJS::AST::UiObjectMember *member = iter.key(); - if (member->firstSourceLocation().offset == offset) { - result = iter.value(); - break; + quint32 startOffset = member->firstSourceLocation().offset; + quint32 endOffset = member->lastSourceLocation().offset; + if (startOffset <= offset && offset <= endOffset) { + if (!possibleNode) + possibleNode = member; + if (possibleNode->firstSourceLocation().offset <= startOffset && + endOffset <= possibleNode->lastSourceLocation().offset) + possibleNode = member; } } + if (possibleNode) { + if (possibleNode != m_nodeForOffset) { + //We have found a better match, set flag so that we can + //query again to check if this is the best match for the offset + m_updateNodeForOffset = true; + m_nodeForOffset = possibleNode; + } + result = m_debugIds.value(possibleNode); + } return result; } @@ -220,6 +237,8 @@ void QmlJSLiveTextPreview::changeSelectedElements(QList offsets, const QStr if (m_editors.isEmpty() || !m_previousDoc || !m_clientProxy) return; + m_updateNodeForOffset = false; + m_lastOffsets = offsets; QmlDebugObjectReference objectRefUnderCursor; objectRefUnderCursor = m_clientProxy.data()->objectReferenceForId(wordAtCursor); @@ -338,6 +357,8 @@ void QmlJSLiveTextPreview::updateDebugIds() m_debugIds[it2.key()] += it2.value(); } } + if (m_updateNodeForOffset) + changeSelectedElements(m_lastOffsets, QString()); } diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.h b/src/plugins/qmljsinspector/qmljslivetextpreview.h index 50691593262..6ada1e56ade 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.h +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.h @@ -101,7 +101,7 @@ private slots: private: static QmlJS::ModelManagerInterface *modelManager(); - QList objectReferencesForOffset(quint32 offset) const; + QList objectReferencesForOffset(quint32 offset); QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding); void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, const QString &elementName, unsigned line, unsigned column); @@ -120,6 +120,9 @@ private: bool m_applyChangesToQmlInspector; QmlJS::Document::Ptr m_docWithUnappliedChanges; QWeakPointer m_clientProxy; + QList m_lastOffsets; + QmlJS::AST::UiObjectMember *m_nodeForOffset; + bool m_updateNodeForOffset; };