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 <kai.koehne@nokia.com>
This commit is contained in:
Aurindam Jana
2012-03-19 15:58:47 +01:00
parent 66ed2b37ba
commit e412a93006
8 changed files with 106 additions and 18 deletions

View File

@@ -84,6 +84,7 @@ void QmlEngineDebugClient::decode(QDataStream &ds,
o.m_source.m_lineNumber = data.lineNumber; o.m_source.m_lineNumber = data.lineNumber;
o.m_source.m_columnNumber = data.columnNumber; o.m_source.m_columnNumber = data.columnNumber;
o.m_contextDebugId = data.contextId; o.m_contextDebugId = data.contextId;
o.m_needsMoreData = simple;
if (simple) if (simple)
return; return;

View File

@@ -132,8 +132,8 @@ typedef QList<QmlDebugEngineReference> QmlDebugEngineReferenceList;
class QmlDebugObjectReference class QmlDebugObjectReference
{ {
public: public:
QmlDebugObjectReference() : m_debugId(-1), m_contextDebugId(-1) {} QmlDebugObjectReference() : m_debugId(-1), m_contextDebugId(-1), m_needsMoreData(false) {}
QmlDebugObjectReference(int id) : m_debugId(id), m_contextDebugId(-1) {} QmlDebugObjectReference(int id) : m_debugId(id), m_contextDebugId(-1), m_needsMoreData(false) {}
int debugId() const { return m_debugId; } int debugId() const { return m_debugId; }
QString className() const { return m_className; } QString className() const { return m_className; }
@@ -142,10 +142,25 @@ public:
QmlDebugFileReference source() const { return m_source; } QmlDebugFileReference source() const { return m_source; }
int contextDebugId() const { return m_contextDebugId; } int contextDebugId() const { return m_contextDebugId; }
bool needsMoreData() const { return m_needsMoreData; }
QList<QmlDebugPropertyReference> properties() const { return m_properties; } QList<QmlDebugPropertyReference> properties() const { return m_properties; }
QList<QmlDebugObjectReference> children() const { return m_children; } QList<QmlDebugObjectReference> 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: private:
friend class QmlEngineDebugClient; friend class QmlEngineDebugClient;
int m_debugId; int m_debugId;
@@ -154,6 +169,7 @@ private:
QString m_name; QString m_name;
QmlDebugFileReference m_source; QmlDebugFileReference m_source;
int m_contextDebugId; int m_contextDebugId;
bool m_needsMoreData;
QList<QmlDebugPropertyReference> m_properties; QList<QmlDebugPropertyReference> m_properties;
QList<QmlDebugObjectReference> m_children; QList<QmlDebugObjectReference> m_children;
}; };

View File

@@ -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 QmlDebugObjectReference ClientProxy::objectReferenceForId(int debugId) const
{ {
foreach (const QmlDebugObjectReference& it, m_rootObjects) { 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( void ClientProxy::fetchContextObjectRecursive(
const QmlDebugContextReference& context) const QmlDebugContextReference& context)
{ {
@@ -492,7 +511,7 @@ void ClientProxy::fetchContextObjectRecursive(
log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString())); log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString()));
quint32 queryId = m_engineClient->queryObjectRecursive(obj); quint32 queryId = fetchContextObject(obj);
if (queryId) if (queryId)
m_objectTreeQueryIds << queryId; m_objectTreeQueryIds << queryId;
} }

View File

@@ -93,6 +93,9 @@ public:
Debugger::QmlAdapter *qmlAdapter() const; Debugger::QmlAdapter *qmlAdapter() const;
quint32 fetchContextObject(const QmlDebugObjectReference& obj);
void addObjectToTree(const QmlDebugObjectReference &obj);
signals: signals:
void objectTreeUpdated(); void objectTreeUpdated();
void connectionStatusMessage(const QString &text); void connectionStatusMessage(const QString &text);

View File

@@ -157,6 +157,7 @@ InspectorUi::InspectorUi(QObject *parent)
, m_debugQuery(0) , m_debugQuery(0)
, m_selectionCallbackExpected(false) , m_selectionCallbackExpected(false)
, m_cursorPositionChangedExternally(false) , m_cursorPositionChangedExternally(false)
, m_onCrumblePathClicked(false)
{ {
m_instance = this; m_instance = this;
m_toolBar = new QmlJsInspectorToolBar(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) void InspectorUi::onResult(quint32 queryId, const QVariant &result)
{ {
if (m_showObjectQueryId == queryId) {
m_showObjectQueryId = 0;
QmlDebugObjectReference obj = qvariant_cast<QmlDebugObjectReference>(result);
m_clientProxy->addObjectToTree(obj);
if (m_onCrumblePathClicked) {
m_onCrumblePathClicked = false;
showObject(obj);
}
return;
}
if (m_debugQuery != queryId) if (m_debugQuery != queryId)
return; return;
@@ -559,21 +571,29 @@ void InspectorUi::selectItems(const QList<QmlDebugObjectReference> &objectRefere
// select only the first valid element of the list // select only the first valid element of the list
m_clientProxy->removeAllObjectWatches(); m_clientProxy->removeAllObjectWatches();
m_clientProxy->addObjectWatch(debugId); //Check if the object is complete
QList <QmlDebugObjectReference> selectionList; if (objref.needsMoreData())
selectionList << objref; m_showObjectQueryId = m_clientProxy->fetchContextObject(objref);
m_propertyInspector->setCurrentObjects(selectionList); else
populateCrumblePath(objref); showObject(objref);
gotoObjectReferenceDefinition(objref);
Debugger::QmlAdapter *qmlAdapter = m_clientProxy->qmlAdapter();
if (qmlAdapter) {
qmlAdapter->setCurrentSelectedDebugInfo(debugId, displayName(objref));
}
break; break;
} }
} }
} }
void InspectorUi::showObject(const QmlDebugObjectReference &obj)
{
m_clientProxy->addObjectWatch(obj.debugId());
QList <QmlDebugObjectReference> 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 bool InspectorUi::isRoot(const QmlDebugObjectReference &obj) const
{ {
foreach (const QmlDebugObjectReference &rootObj, m_clientProxy->rootObjectReference()) foreach (const QmlDebugObjectReference &rootObj, m_clientProxy->rootObjectReference())
@@ -768,6 +788,7 @@ void InspectorUi::crumblePathElementClicked(const QVariant &data)
QList<int> debugIds; QList<int> debugIds;
debugIds << debugId; debugIds << debugId;
m_onCrumblePathClicked = true;
selectItems(debugIds); selectItems(debugIds);
m_clientProxy->setSelectedItemsByDebugId(debugIds); m_clientProxy->setSelectedItemsByDebugId(debugIds);
} }

View File

@@ -150,6 +150,8 @@ private:
void connectSignals(); void connectSignals();
void disconnectSignals(); void disconnectSignals();
void showObject(const QmlDebugObjectReference &obj);
private: private:
bool m_listeningToEditorManager; bool m_listeningToEditorManager;
QmlJsInspectorToolBar *m_toolBar; QmlJsInspectorToolBar *m_toolBar;
@@ -161,6 +163,7 @@ private:
ClientProxy *m_clientProxy; ClientProxy *m_clientProxy;
QObject *m_qmlEngine; QObject *m_qmlEngine;
quint32 m_debugQuery; quint32 m_debugQuery;
quint32 m_showObjectQueryId;
// Qml/JS integration // Qml/JS integration
QHash<QString, QmlJSLiveTextPreview *> m_textPreviews; QHash<QString, QmlJSLiveTextPreview *> m_textPreviews;
@@ -172,6 +175,7 @@ private:
static InspectorUi *m_instance; static InspectorUi *m_instance;
bool m_selectionCallbackExpected; bool m_selectionCallbackExpected;
bool m_cursorPositionChangedExternally; bool m_cursorPositionChangedExternally;
bool m_onCrumblePathClicked;
}; };
} // Internal } // Internal

View File

@@ -178,6 +178,8 @@ QmlJSLiveTextPreview::QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc,
, m_initialDoc(initDoc) , m_initialDoc(initDoc)
, m_applyChangesToQmlInspector(true) , m_applyChangesToQmlInspector(true)
, m_clientProxy(clientProxy) , m_clientProxy(clientProxy)
, m_nodeForOffset(0)
, m_updateNodeForOffset(false)
{ {
Q_ASSERT(doc->fileName() == initDoc->fileName()); Q_ASSERT(doc->fileName() == initDoc->fileName());
m_filename = doc->fileName(); m_filename = doc->fileName();
@@ -200,18 +202,33 @@ void QmlJSLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
} }
QList<int> QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const QList<int> QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset)
{ {
QList<int> result; QList<int> result;
QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds); QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds);
QmlJS::AST::UiObjectMember *possibleNode = 0;
while(iter.hasNext()) { while(iter.hasNext()) {
iter.next(); iter.next();
QmlJS::AST::UiObjectMember *member = iter.key(); QmlJS::AST::UiObjectMember *member = iter.key();
if (member->firstSourceLocation().offset == offset) { quint32 startOffset = member->firstSourceLocation().offset;
result = iter.value(); quint32 endOffset = member->lastSourceLocation().offset;
break; 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; return result;
} }
@@ -220,6 +237,8 @@ void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QStr
if (m_editors.isEmpty() || !m_previousDoc || !m_clientProxy) if (m_editors.isEmpty() || !m_previousDoc || !m_clientProxy)
return; return;
m_updateNodeForOffset = false;
m_lastOffsets = offsets;
QmlDebugObjectReference objectRefUnderCursor; QmlDebugObjectReference objectRefUnderCursor;
objectRefUnderCursor = m_clientProxy.data()->objectReferenceForId(wordAtCursor); objectRefUnderCursor = m_clientProxy.data()->objectReferenceForId(wordAtCursor);
@@ -338,6 +357,8 @@ void QmlJSLiveTextPreview::updateDebugIds()
m_debugIds[it2.key()] += it2.value(); m_debugIds[it2.key()] += it2.value();
} }
} }
if (m_updateNodeForOffset)
changeSelectedElements(m_lastOffsets, QString());
} }

View File

@@ -101,7 +101,7 @@ private slots:
private: private:
static QmlJS::ModelManagerInterface *modelManager(); static QmlJS::ModelManagerInterface *modelManager();
QList<int> objectReferencesForOffset(quint32 offset) const; QList<int> objectReferencesForOffset(quint32 offset);
QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding); QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding);
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, const QString &elementName, void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, const QString &elementName,
unsigned line, unsigned column); unsigned line, unsigned column);
@@ -120,6 +120,9 @@ private:
bool m_applyChangesToQmlInspector; bool m_applyChangesToQmlInspector;
QmlJS::Document::Ptr m_docWithUnappliedChanges; QmlJS::Document::Ptr m_docWithUnappliedChanges;
QWeakPointer<ClientProxy> m_clientProxy; QWeakPointer<ClientProxy> m_clientProxy;
QList<int> m_lastOffsets;
QmlJS::AST::UiObjectMember *m_nodeForOffset;
bool m_updateNodeForOffset;
}; };