forked from qt-creator/qt-creator
Debugger: Add multi-engine support for QML inspector
The engines are listed as virtual root items for their contents. This way, when we need an engineID we can walk up the tree of watch items and the last valid one will be the engine. Fixes: QTCREATORBUG-21486 Change-Id: Ib110457dc65523c1e2b75aa073f6cd399bbc9532 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -1040,7 +1040,9 @@ void QmlEngine::executeDebuggerCommand(const QString &command)
|
||||
if (d->unpausedEvaluate) {
|
||||
d->evaluate(command, contextId, CB(d->handleExecuteDebuggerCommand));
|
||||
} else {
|
||||
quint32 queryId = d->inspectorAgent.queryExpressionResult(contextId, command);
|
||||
quint32 queryId = d->inspectorAgent.queryExpressionResult(
|
||||
contextId, command,
|
||||
d->inspectorAgent.engineId(watchHandler()->watchItem(currentIndex)));
|
||||
if (queryId) {
|
||||
d->queryIds.append(queryId);
|
||||
} else {
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Internal {
|
||||
|
||||
Q_LOGGING_CATEGORY(qmlInspectorLog, "qtc.dbg.qmlinspector", QtWarningMsg)
|
||||
|
||||
|
||||
/*!
|
||||
* DebuggerAgent updates the watchhandler with the object tree data.
|
||||
*/
|
||||
@@ -110,13 +111,21 @@ QmlInspectorAgent::QmlInspectorAgent(QmlEngine *engine, QmlDebugConnection *conn
|
||||
this, &QmlInspectorAgent::onShowAppOnTopChanged);
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::queryExpressionResult(int debugId, const QString &expression)
|
||||
int QmlInspectorAgent::engineId(const WatchItem *data) const
|
||||
{
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << debugId << expression
|
||||
<< m_engine.debugId() << ')';
|
||||
int id = -1;
|
||||
for (; data; data = data->parent())
|
||||
id = data->id >= 0 ? data->id : id;
|
||||
return id;
|
||||
}
|
||||
|
||||
return m_engineClient->queryExpressionResult(debugId, expression,
|
||||
m_engine.debugId());
|
||||
quint32 QmlInspectorAgent::queryExpressionResult(int debugId, const QString &expression,
|
||||
int engineId)
|
||||
{
|
||||
qCDebug(qmlInspectorLog)
|
||||
<< __FUNCTION__ << '(' << debugId << expression << engineId << ')';
|
||||
|
||||
return m_engineClient->queryExpressionResult(debugId, expression, engineId);
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::assignValue(const WatchItem *data,
|
||||
@@ -127,11 +136,11 @@ void QmlInspectorAgent::assignValue(const WatchItem *data,
|
||||
if (data->id != WatchItem::InvalidId) {
|
||||
QString val(valueV.toString());
|
||||
QString expression = QString("%1 = %2;").arg(expr).arg(val);
|
||||
queryExpressionResult(data->id, expression);
|
||||
queryExpressionResult(data->id, expression, engineId(data));
|
||||
}
|
||||
}
|
||||
|
||||
static int parentIdForIname(const QString &iname)
|
||||
static int parentIdForIname(const QString &iname, int engineId)
|
||||
{
|
||||
// Extract the parent id
|
||||
int lastIndex = iname.lastIndexOf('.');
|
||||
@@ -139,7 +148,7 @@ static int parentIdForIname(const QString &iname)
|
||||
int parentId = WatchItem::InvalidId;
|
||||
if (secondLastIndex != WatchItem::InvalidId)
|
||||
parentId = iname.mid(secondLastIndex + 1, lastIndex - secondLastIndex - 1).toInt();
|
||||
return parentId;
|
||||
return parentId >= 0 ? parentId : engineId;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::updateWatchData(const WatchItem &data)
|
||||
@@ -184,7 +193,6 @@ void QmlInspectorAgent::selectObjectsInTree(const QList<int> &debugIds)
|
||||
m_objectsToSelect.append(debugId);
|
||||
fetchObject(debugId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::addObjectWatch(int objectDebugId)
|
||||
@@ -257,15 +265,29 @@ void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value,
|
||||
m_engineQueryId = 0;
|
||||
QList<EngineReference> engines = qvariant_cast<QList<EngineReference> >(value);
|
||||
QTC_ASSERT(engines.count(), return);
|
||||
// only care about first engine atm
|
||||
m_engine = engines.at(0);
|
||||
m_engines = engines;
|
||||
queryEngineContext();
|
||||
} else if (queryId == m_rootContextQueryId) {
|
||||
m_rootContextQueryId = 0;
|
||||
clearObjectTree();
|
||||
updateObjectTree(qvariant_cast<ContextReference>(value));
|
||||
} else {
|
||||
m_qmlEngine->expressionEvaluated(queryId, value);
|
||||
int index = m_rootContextQueryIds.indexOf(queryId);
|
||||
if (index < 0) {
|
||||
m_qmlEngine->expressionEvaluated(queryId, value);
|
||||
} else {
|
||||
Q_ASSERT(index < m_engines.length());
|
||||
const int engineId = m_engines.at(index).debugId();
|
||||
m_rootContexts.insert(engineId, qvariant_cast<ContextReference>(value));
|
||||
if (m_rootContexts.size() == m_engines.size()) {
|
||||
clearObjectTree();
|
||||
for (const auto &engine : m_engines) {
|
||||
QString name = engine.name();
|
||||
if (name.isEmpty())
|
||||
name = QString::fromLatin1("Engine %1").arg(engine.debugId());
|
||||
verifyAndInsertObjectInTree(ObjectReference(engine.debugId(), name));
|
||||
updateObjectTree(m_rootContexts[engine.debugId()], engine.debugId());
|
||||
}
|
||||
m_rootContextQueryIds.clear();
|
||||
m_rootContexts.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << "done";
|
||||
@@ -277,11 +299,12 @@ void QmlInspectorAgent::newObject(int engineId, int /*objectId*/, int /*parentId
|
||||
|
||||
log(LogReceive, "OBJECT_CREATED");
|
||||
|
||||
if (m_engine.debugId() != engineId)
|
||||
return;
|
||||
|
||||
// TODO: FIX THIS for qt 5.x (Needs update in the qt side)
|
||||
m_delayQueryTimer.start();
|
||||
for (const auto &engine : qAsConst(m_engines)) {
|
||||
if (engine.debugId() == engineId) {
|
||||
m_delayQueryTimer.start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sortChildrenIfNecessary(WatchItem *propertiesWatch)
|
||||
@@ -365,8 +388,8 @@ void QmlInspectorAgent::queryEngineContext()
|
||||
|
||||
log(LogSend, "LIST_OBJECTS");
|
||||
|
||||
m_rootContextQueryId
|
||||
= m_engineClient->queryRootContexts(m_engine);
|
||||
for (const auto &engine : qAsConst(m_engines))
|
||||
m_rootContextQueryIds.append(m_engineClient->queryRootContexts(engine));
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::fetchObject(int debugId)
|
||||
@@ -383,21 +406,21 @@ void QmlInspectorAgent::fetchObject(int debugId)
|
||||
m_objectTreeQueryIds << queryId;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::updateObjectTree(const ContextReference &context)
|
||||
void QmlInspectorAgent::updateObjectTree(const ContextReference &context, int engineId)
|
||||
{
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << context << ')';
|
||||
|
||||
if (!isConnected() || !boolSetting(ShowQmlObjectTree))
|
||||
return;
|
||||
|
||||
foreach (const ObjectReference & obj, context.objects())
|
||||
verifyAndInsertObjectInTree(obj);
|
||||
for (const ObjectReference &obj : context.objects())
|
||||
verifyAndInsertObjectInTree(obj, engineId);
|
||||
|
||||
foreach (const ContextReference &child, context.contexts())
|
||||
updateObjectTree(child);
|
||||
for (const ContextReference &child : context.contexts())
|
||||
updateObjectTree(child, engineId);
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::verifyAndInsertObjectInTree(const ObjectReference &object)
|
||||
void QmlInspectorAgent::verifyAndInsertObjectInTree(const ObjectReference &object, int engineId)
|
||||
{
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << object << ')';
|
||||
|
||||
@@ -412,44 +435,47 @@ void QmlInspectorAgent::verifyAndInsertObjectInTree(const ObjectReference &objec
|
||||
// fetch parents till we find a previously expanded parent.
|
||||
|
||||
WatchHandler *handler = m_qmlEngine->watchHandler();
|
||||
const int parentId = object.parentId();
|
||||
const int parentId = object.parentId() >= 0 ? object.parentId() : engineId;
|
||||
const int objectDebugId = object.debugId();
|
||||
if (m_debugIdToIname.contains(parentId)) {
|
||||
QString parentIname = m_debugIdToIname.value(parentId);
|
||||
if (parentId != WatchItem::InvalidId && !handler->isExpandedIName(parentIname)) {
|
||||
m_objectStack.push(object);
|
||||
m_objectStack.push(QPair<ObjectReference, int>(object, engineId));
|
||||
handler->fetchMore(parentIname);
|
||||
return; // recursive
|
||||
}
|
||||
insertObjectInTree(object);
|
||||
insertObjectInTree(object, engineId);
|
||||
|
||||
} else {
|
||||
m_objectStack.push(object);
|
||||
m_objectStack.push(QPair<ObjectReference, int>(object, engineId));
|
||||
fetchObject(parentId);
|
||||
return; // recursive
|
||||
}
|
||||
if (!m_objectStack.isEmpty()) {
|
||||
const ObjectReference &top = m_objectStack.top();
|
||||
const auto &top = m_objectStack.top();
|
||||
// We want to expand only a particular branch and not the whole tree. Hence, we do not
|
||||
// expand siblings.
|
||||
if (object.children().contains(top)) {
|
||||
// expand siblings. If this is the engine, we add add root objects with the same engine ID
|
||||
// as children.
|
||||
if (object.children().contains(top.first) ||
|
||||
(top.first.parentId() < 0 && object.debugId() == top.second)) {
|
||||
QString objectIname = m_debugIdToIname.value(objectDebugId);
|
||||
if (!handler->isExpandedIName(objectIname)) {
|
||||
handler->fetchMore(objectIname);
|
||||
} else {
|
||||
verifyAndInsertObjectInTree(m_objectStack.pop());
|
||||
verifyAndInsertObjectInTree(top.first, top.second);
|
||||
m_objectStack.pop();
|
||||
return; // recursive
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::insertObjectInTree(const ObjectReference &object)
|
||||
void QmlInspectorAgent::insertObjectInTree(const ObjectReference &object, int engineId)
|
||||
{
|
||||
qCDebug(qmlInspectorLog) << __FUNCTION__ << '(' << object << ')';
|
||||
|
||||
const int objectDebugId = object.debugId();
|
||||
const int parentId = parentIdForIname(m_debugIdToIname.value(objectDebugId));
|
||||
const int parentId = parentIdForIname(m_debugIdToIname.value(objectDebugId), engineId);
|
||||
|
||||
QElapsedTimer timeElapsed;
|
||||
|
||||
|
||||
@@ -54,11 +54,12 @@ class QmlInspectorAgent : public QObject
|
||||
public:
|
||||
QmlInspectorAgent(QmlEngine *engine, QmlDebug::QmlDebugConnection *connection);
|
||||
|
||||
quint32 queryExpressionResult(int debugId, const QString &expression);
|
||||
quint32 queryExpressionResult(int debugId, const QString &expression, int engineId);
|
||||
void assignValue(const WatchItem *data, const QString &expression, const QVariant &valueV);
|
||||
void updateWatchData(const WatchItem &data);
|
||||
void watchDataSelected(int id);
|
||||
void enableTools(bool enable);
|
||||
int engineId(const WatchItem *item) const;
|
||||
|
||||
private:
|
||||
void selectObjectsInTree(const QList<int> &debugIds);
|
||||
@@ -73,9 +74,9 @@ private:
|
||||
void onValueChanged(int debugId, const QByteArray &propertyName, const QVariant &value);
|
||||
|
||||
void queryEngineContext();
|
||||
void updateObjectTree(const QmlDebug::ContextReference &context);
|
||||
void verifyAndInsertObjectInTree(const QmlDebug::ObjectReference &object);
|
||||
void insertObjectInTree(const QmlDebug::ObjectReference &result);
|
||||
void updateObjectTree(const QmlDebug::ContextReference &contexts, int engineId = -1);
|
||||
void verifyAndInsertObjectInTree(const QmlDebug::ObjectReference &object, int engineId = -1);
|
||||
void insertObjectInTree(const QmlDebug::ObjectReference &result, int engineId = -1);
|
||||
|
||||
void buildDebugIdHashRecursive(const QmlDebug::ObjectReference &ref);
|
||||
void addWatchData(const QmlDebug::ObjectReference &obj,
|
||||
@@ -106,13 +107,15 @@ private:
|
||||
QmlDebug::QmlToolsClient *m_toolsClient = nullptr;
|
||||
|
||||
quint32 m_engineQueryId = 0;
|
||||
quint32 m_rootContextQueryId = 0;
|
||||
|
||||
QList<quint32> m_rootContextQueryIds;
|
||||
QHash<int, QmlDebug::ContextReference> m_rootContexts;
|
||||
|
||||
QList<int> m_objectsToSelect;
|
||||
|
||||
QList<quint32> m_objectTreeQueryIds;
|
||||
QStack<QmlDebug::ObjectReference> m_objectStack;
|
||||
QmlDebug::EngineReference m_engine;
|
||||
QStack<QPair<QmlDebug::ObjectReference, int>> m_objectStack;
|
||||
QList<QmlDebug::EngineReference> m_engines;
|
||||
QHash<int, QString> m_debugIdToIname;
|
||||
QHash<int, QmlDebug::FileReference> m_debugIdLocations;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user