Commit e412a930 authored by Aurindam Jana's avatar Aurindam Jana
Browse files

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: default avatarKai Koehne <kai.koehne@nokia.com>
parent 66ed2b37
......@@ -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,17 +202,32 @@ 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;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment