forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user