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_columnNumber = data.columnNumber;
|
||||
o.m_contextDebugId = data.contextId;
|
||||
o.m_needsMoreData = simple;
|
||||
|
||||
if (simple)
|
||||
return;
|
||||
|
@@ -132,8 +132,8 @@ typedef QList<QmlDebugEngineReference> 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<QmlDebugPropertyReference> properties() const { return m_properties; }
|
||||
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:
|
||||
friend class QmlEngineDebugClient;
|
||||
int m_debugId;
|
||||
@@ -154,6 +169,7 @@ private:
|
||||
QString m_name;
|
||||
QmlDebugFileReference m_source;
|
||||
int m_contextDebugId;
|
||||
bool m_needsMoreData;
|
||||
QList<QmlDebugPropertyReference> m_properties;
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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<QmlDebugObjectReference>(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<QmlDebugObjectReference> &objectRefere
|
||||
// select only the first valid element of the list
|
||||
|
||||
m_clientProxy->removeAllObjectWatches();
|
||||
m_clientProxy->addObjectWatch(debugId);
|
||||
QList <QmlDebugObjectReference> 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 <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
|
||||
{
|
||||
foreach (const QmlDebugObjectReference &rootObj, m_clientProxy->rootObjectReference())
|
||||
@@ -768,6 +788,7 @@ void InspectorUi::crumblePathElementClicked(const QVariant &data)
|
||||
QList<int> debugIds;
|
||||
debugIds << debugId;
|
||||
|
||||
m_onCrumblePathClicked = true;
|
||||
selectItems(debugIds);
|
||||
m_clientProxy->setSelectedItemsByDebugId(debugIds);
|
||||
}
|
||||
|
@@ -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<QString, QmlJSLiveTextPreview *> m_textPreviews;
|
||||
@@ -172,6 +175,7 @@ private:
|
||||
static InspectorUi *m_instance;
|
||||
bool m_selectionCallbackExpected;
|
||||
bool m_cursorPositionChangedExternally;
|
||||
bool m_onCrumblePathClicked;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
|
@@ -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<int> QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const
|
||||
QList<int> QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset)
|
||||
{
|
||||
QList<int> result;
|
||||
QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > 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<int> 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());
|
||||
}
|
||||
|
||||
|
||||
|
@@ -101,7 +101,7 @@ private slots:
|
||||
|
||||
private:
|
||||
static QmlJS::ModelManagerInterface *modelManager();
|
||||
QList<int> objectReferencesForOffset(quint32 offset) const;
|
||||
QList<int> 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<ClientProxy> m_clientProxy;
|
||||
QList<int> m_lastOffsets;
|
||||
QmlJS::AST::UiObjectMember *m_nodeForOffset;
|
||||
bool m_updateNodeForOffset;
|
||||
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user