From 023deff47467f0966c21e8f1929b703f0be8c145 Mon Sep 17 00:00:00 2001 From: Aurindam Jana Date: Mon, 14 May 2012 23:26:23 +0200 Subject: [PATCH] QmlJSInspectorAgent: Refactor code Try to use the watchHandler for referring to the object tree instead of caching the object tree locally. Change-Id: I68624771ef49d50f2cf0d6d580b1b34d57483178 Reviewed-by: Christiaan Janssen --- src/libs/qmldebug/baseenginedebugclient.cpp | 16 +- src/libs/qmldebug/baseenginedebugclient.h | 13 +- .../debugger/qml/qmlinspectoradapter.cpp | 75 +-- .../debugger/qml/qmlinspectoradapter.h | 2 +- .../debugger/qml/qmlinspectoragent.cpp | 517 ++++++++---------- src/plugins/debugger/qml/qmlinspectoragent.h | 45 +- .../debugger/qml/qmllivetextpreview.cpp | 29 +- 7 files changed, 274 insertions(+), 423 deletions(-) diff --git a/src/libs/qmldebug/baseenginedebugclient.cpp b/src/libs/qmldebug/baseenginedebugclient.cpp index 1339caf4182..b53fe96ff30 100644 --- a/src/libs/qmldebug/baseenginedebugclient.cpp +++ b/src/libs/qmldebug/baseenginedebugclient.cpp @@ -286,14 +286,14 @@ quint32 BaseEngineDebugClient::addWatch(const ObjectReference &object, return id; } -quint32 BaseEngineDebugClient::addWatch(const ObjectReference &object) +quint32 BaseEngineDebugClient::addWatch(int objectId) { quint32 id = 0; if (status() == Enabled) { id = getId(); QByteArray message; QDataStream ds(&message, QIODevice::WriteOnly); - ds << QByteArray("WATCH_OBJECT") << id << object.m_debugId; + ds << QByteArray("WATCH_OBJECT") << id << objectId; sendMessage(message); } return id; @@ -341,28 +341,28 @@ quint32 BaseEngineDebugClient::queryRootContexts(const EngineReference &engine) return id; } -quint32 BaseEngineDebugClient::queryObject(const ObjectReference &object) +quint32 BaseEngineDebugClient::queryObject(int objectId) { quint32 id = 0; - if (status() == Enabled && object.m_debugId != -1) { + if (status() == Enabled && objectId != -1) { id = getId(); QByteArray message; QDataStream ds(&message, QIODevice::WriteOnly); - ds << QByteArray("FETCH_OBJECT") << id << object.m_debugId << false << + ds << QByteArray("FETCH_OBJECT") << id << objectId << false << true; sendMessage(message); } return id; } -quint32 BaseEngineDebugClient::queryObjectRecursive(const ObjectReference &object) +quint32 BaseEngineDebugClient::queryObjectRecursive(int objectId) { quint32 id = 0; - if (status() == Enabled && object.m_debugId != -1) { + if (status() == Enabled && objectId != -1) { id = getId(); QByteArray message; QDataStream ds(&message, QIODevice::WriteOnly); - ds << QByteArray("FETCH_OBJECT") << id << object.m_debugId << true << + ds << QByteArray("FETCH_OBJECT") << id << objectId << true << true; sendMessage(message); } diff --git a/src/libs/qmldebug/baseenginedebugclient.h b/src/libs/qmldebug/baseenginedebugclient.h index ae898822c55..741ff8cfae8 100644 --- a/src/libs/qmldebug/baseenginedebugclient.h +++ b/src/libs/qmldebug/baseenginedebugclient.h @@ -56,15 +56,15 @@ public: quint32 addWatch(const PropertyReference &property); quint32 addWatch(const ContextReference &context, const QString &id); quint32 addWatch(const ObjectReference &object, const QString &expr); - quint32 addWatch(const ObjectReference &object); + quint32 addWatch(int objectId); quint32 addWatch(const FileReference &file); void removeWatch(quint32 watch); quint32 queryAvailableEngines(); quint32 queryRootContexts(const EngineReference &context); - quint32 queryObject(const ObjectReference &object); - quint32 queryObjectRecursive(const ObjectReference &object); + quint32 queryObject(int objectId); + quint32 queryObjectRecursive(int objectId); quint32 queryExpressionResult(int objectDebugId, const QString &expr, int engineId = -1); virtual quint32 setBindingForObject(int objectDebugId, const QString &propertyName, @@ -104,6 +104,12 @@ class FileReference { public: FileReference() : m_lineNumber(-1), m_columnNumber(-1) {} + FileReference(const QUrl &url, int line, int column) + : m_url(url), + m_lineNumber(line), + m_columnNumber(column) + { + } QUrl url() const { return m_url; } int lineNumber() const { return m_lineNumber; } @@ -142,6 +148,7 @@ public: QString className() const { return m_className; } QString idString() const { return m_idString; } QString name() const { return m_name; } + bool isValid() const { return m_debugId != -1; } FileReference source() const { return m_source; } int contextDebugId() const { return m_contextDebugId; } diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.cpp b/src/plugins/debugger/qml/qmlinspectoradapter.cpp index d1644befa50..3c5b0144191 100644 --- a/src/plugins/debugger/qml/qmlinspectoradapter.cpp +++ b/src/plugins/debugger/qml/qmlinspectoradapter.cpp @@ -274,27 +274,14 @@ void QmlInspectorAdapter::engineClientStatusChanged(QmlDebug::ClientStatus statu void QmlInspectorAdapter::selectObjectsFromEditor(const QList &debugIds) { - int debugId = debugIds.first(); - if (m_selectionCallbackExpected) { m_selectionCallbackExpected = false; return; } m_cursorPositionChangedExternally = true; - - ObjectReference clientRef - = agent()->objectForId(debugId); - - // if children haven't been loaded yet do so first, the editor - // might actually be interested in the children! - if (clientRef.debugId() != debugId - || clientRef.needsMoreData()) { - m_targetToSync = ToolTarget; - m_debugIdToSelect = debugId; - agent()->fetchObject(debugId); - } else { - selectObject(clientRef, ToolTarget); - } + m_targetToSync = ToolTarget; + m_debugIdToSelect = debugIds.first(); + selectObject(ObjectReference(m_debugIdToSelect), ToolTarget); } void QmlInspectorAdapter::selectObjectsFromToolsClient(const QList &debugIds) @@ -302,18 +289,9 @@ void QmlInspectorAdapter::selectObjectsFromToolsClient(const QList &debugId if (debugIds.isEmpty()) return; - int debugId = debugIds.first(); - - ObjectReference clientRef - = agent()->objectForId(debugId); - - if (clientRef.debugId() != debugId) { - m_targetToSync = EditorTarget; - m_debugIdToSelect = debugId; - agent()->fetchObject(debugId); - } else { - selectObject(clientRef, EditorTarget); - } + m_targetToSync = EditorTarget; + m_debugIdToSelect = debugIds.first(); + selectObject(ObjectReference(m_debugIdToSelect), EditorTarget); } void QmlInspectorAdapter::onObjectFetched(const ObjectReference &ref) @@ -520,8 +498,7 @@ void QmlInspectorAdapter::gotoObjectReferenceDefinition( m_selectionCallbackExpected = true; if (textEditor) { - ObjectReference ref = objectReferenceForLocation(fileName); - if (ref.debugId() != obj.debugId()) { + if (objectIdForLocation(fileName) != obj.debugId()) { m_selectionCallbackExpected = true; editorManager->addCurrentPositionToNavigationHistory(); textEditor->gotoLine(source.lineNumber()); @@ -530,7 +507,7 @@ void QmlInspectorAdapter::gotoObjectReferenceDefinition( } } -ObjectReference QmlInspectorAdapter::objectReferenceForLocation( +int QmlInspectorAdapter::objectIdForLocation( const QString &fileName, int cursorPosition) const { Core::IEditor *editor = Core::EditorManager::openEditor(fileName); @@ -552,41 +529,13 @@ ObjectReference QmlInspectorAdapter::objectReferenceForLocation( = semanticInfo.declaringMemberNoProperties(cursorPosition)) { if (QmlJS::AST::UiObjectMember *objMember = node->uiObjectMemberCast()) { - return agent()->objectForLocation( + return agent()->objectIdForLocation( objMember->firstSourceLocation().startLine, objMember->firstSourceLocation().startColumn); } } } - return ObjectReference(); -} - -inline QString displayName(const ObjectReference &obj) -{ - // special! state names - if (obj.className() == "State") { - foreach (const PropertyReference &prop, obj.properties()) { - if (prop.name() == "name") - return prop.value().toString(); - } - } - - // has id? - if (!obj.idString().isEmpty()) - return obj.idString(); - - // return the simplified class name then - QString objTypeName = obj.className(); - QStringList declarativeStrings; - declarativeStrings << QLatin1String("QDeclarative") - << QLatin1String("QQml"); - foreach (const QString &str, declarativeStrings) { - if (objTypeName.startsWith(str)) { - objTypeName = objTypeName.mid(str.length()).section('_', 0, 0); - break; - } - } - return QString("<%1>").arg(objTypeName); + return -1; } void QmlInspectorAdapter::selectObject(const ObjectReference &obj, @@ -602,7 +551,7 @@ void QmlInspectorAdapter::selectObject(const ObjectReference &obj, agent()->selectObjectInTree(obj.debugId()); m_currentSelectedDebugId = obj.debugId(); - m_currentSelectedDebugName = displayName(obj); + m_currentSelectedDebugName = agent()->displayName(obj.debugId()); emit selectionChanged(); } @@ -648,7 +597,7 @@ void QmlInspectorAdapter::onReloaded() void QmlInspectorAdapter::onDestroyedObject() { - m_agent->refreshObjectTree(); + m_agent->queryEngineContext(); } } // namespace Internal diff --git a/src/plugins/debugger/qml/qmlinspectoradapter.h b/src/plugins/debugger/qml/qmlinspectoradapter.h index fe9c093c671..f8b282c7ef0 100644 --- a/src/plugins/debugger/qml/qmlinspectoradapter.h +++ b/src/plugins/debugger/qml/qmlinspectoradapter.h @@ -107,7 +107,7 @@ private: void showConnectionStatusMessage(const QString &message); void gotoObjectReferenceDefinition(const QmlDebug::ObjectReference &obj); - QmlDebug::ObjectReference objectReferenceForLocation( + int objectIdForLocation( const QString &fileName, int cursorPosition = -1) const; enum SelectionTarget { NoTarget, ToolTarget, EditorTarget }; diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index d2c2793be25..492fc5b7b2f 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -57,7 +57,7 @@ enum { */ QmlInspectorAgent::QmlInspectorAgent(DebuggerEngine *engine, QObject *parent) : QObject(parent) - , m_engine(engine) + , m_debuggerEngine(engine) , m_engineClient(0) , m_engineQueryId(0) , m_rootContextQueryId(0) @@ -65,26 +65,9 @@ QmlInspectorAgent::QmlInspectorAgent(DebuggerEngine *engine, QObject *parent) { connect(debuggerCore()->action(ShowQmlObjectTree), SIGNAL(valueChanged(QVariant)), SLOT(updateStatus())); -} - -void QmlInspectorAgent::refreshObjectTree() -{ - if (debug) - qDebug() << __FUNCTION__ << "()"; - - if (!m_rootContextQueryId) { - m_objectTreeQueryIds.clear(); - queryEngineContext(m_engines.value(0).debugId()); - } -} - -void QmlInspectorAgent::fetchObject(int debugId) -{ - if (debug) - qDebug() << __FUNCTION__ << "(" << debugId << ")"; - - m_fetchCurrentObjectsQueryIds - << fetchContextObject(ObjectReference(debugId)); + m_delayQueryTimer.setSingleShot(true); + m_delayQueryTimer.setInterval(500); + connect(&m_delayQueryTimer, SIGNAL(timeout()), SLOT(queryEngineContext())); } quint32 QmlInspectorAgent::queryExpressionResult(int debugId, @@ -92,10 +75,10 @@ quint32 QmlInspectorAgent::queryExpressionResult(int debugId, { if (debug) qDebug() << __FUNCTION__ << "(" << debugId << expression - << m_engines.value(0).debugId() << ")"; + << m_engine.debugId() << ")"; return m_engineClient->queryExpressionResult(debugId, expression, - m_engines.value(0).debugId()); + m_engine.debugId()); } void QmlInspectorAgent::updateWatchData(const WatchData &data) @@ -106,8 +89,7 @@ void QmlInspectorAgent::updateWatchData(const WatchData &data) if (data.id && !m_fetchDataIds.contains(data.id)) { // objects m_fetchDataIds << data.id; - ObjectReference ref(data.id); - m_fetchCurrentObjectsQueryIds << fetchContextObject(ref); + fetchObject(data.id); } } @@ -124,13 +106,12 @@ void QmlInspectorAgent::selectObjectInTree(int debugId) QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname); if (debug) qDebug() << " selecting" << iname << "in tree"; - m_engine->watchHandler()->setCurrentItem(iname); + m_debuggerEngine->watchHandler()->setCurrentItem(iname); m_objectToSelect = 0; } else { // we've to fetch it m_objectToSelect = debugId; - m_fetchCurrentObjectsQueryIds - << fetchContextObject(ObjectReference(debugId)); + fetchObject(debugId); } } @@ -222,49 +203,45 @@ quint32 QmlInspectorAgent::resetBindingForObject(int objectDebugId, return queryId; } - -QList QmlInspectorAgent::objects() const -{ - QList result; - foreach (const ObjectReference &it, m_rootObjects) - result.append(objects(it)); - return result; -} - -ObjectReference QmlInspectorAgent::objectForId(int debugId) const -{ - foreach (const ObjectReference &it, m_rootObjects) { - ObjectReference result = objectForId(debugId, it); - if (result.debugId() == debugId) - return result; - } - return ObjectReference(); -} - ObjectReference QmlInspectorAgent::objectForId( const QString &objectId) const { if (!objectId.isEmpty() && objectId[0].isLower()) { - const QList refs = objects(); - foreach (const ObjectReference &ref, refs) { - if (ref.idString() == objectId) - return ref; + QHashIterator iter(m_debugIdToIname); + while (iter.hasNext()) { + iter.next(); + if (m_debuggerEngine->watchHandler()->findData(iter.value())->name == objectId) + return ObjectReference(iter.key()); } } return ObjectReference(); } -ObjectReference QmlInspectorAgent::objectForLocation( +int QmlInspectorAgent::objectIdForLocation( int line, int column) const { - const QList refs = objects(); - foreach (const ObjectReference &ref, refs) { - if (ref.source().lineNumber() == line - && ref.source().columnNumber() == column) - return ref; + QHashIterator iter(m_debugIdLocations); + while (iter.hasNext()) { + iter.next(); + const FileReference &ref = iter.value(); + if (ref.lineNumber() == line + && ref.columnNumber() == column) + return iter.key(); } - return ObjectReference(); + return -1; +} + +QHash QmlInspectorAgent::rootObjectIds() const +{ + QHash rIds; + foreach (const QByteArray &in, m_debugIdToIname) { + const WatchData *data = m_debuggerEngine->watchHandler()->findData(in); + int debugId = data->id; + QString className = data->type; + rIds.insert(debugId, className); + } + return rIds; } bool QmlInspectorAgent::addObjectWatch(int objectDebugId) @@ -283,14 +260,13 @@ bool QmlInspectorAgent::addObjectWatch(int objectDebugId) if (m_objectWatches.contains(objectDebugId)) return true; - ObjectReference ref = objectForId(objectDebugId); - if (ref.debugId() != objectDebugId) + if (!m_debugIdToIname.contains(objectDebugId)) return false; // is flooding the debugging output log! // log(LogSend, QString("WATCH_PROPERTY %1").arg(objectDebugId)); - if (m_engineClient->addWatch(ref)) + if (m_engineClient->addWatch(objectDebugId)) m_objectWatches.append(objectDebugId); return false; @@ -356,6 +332,21 @@ void QmlInspectorAgent::setEngineClient(BaseEngineDebugClient *client) updateStatus(); } +QString QmlInspectorAgent::displayName(int objectDebugId) const +{ + if (!isConnected() + || !debuggerCore()->boolSetting(ShowQmlObjectTree)) + return QString(); + + if (m_debugIdToIname.contains(objectDebugId)) { + const WatchData *data = m_debuggerEngine->watchHandler()->findData( + m_debugIdToIname.value(objectDebugId)); + QTC_ASSERT(data, return QString()); + return data->name; + } + return QString(); +} + void QmlInspectorAgent::updateStatus() { if (m_engineClient @@ -363,8 +354,7 @@ void QmlInspectorAgent::updateStatus() && debuggerCore()->boolSetting(ShowQmlObjectTree)) { reloadEngines(); } else { - // Clear view. - m_engine->watchHandler()->removeChildren("inspect"); + clearObjectTree(); } } @@ -383,31 +373,27 @@ void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value, if (m_objectTreeQueryIds.contains(queryId)) { m_objectTreeQueryIds.removeOne(queryId); - objectTreeFetched(qvariant_cast(value)); - } else if (queryId == m_engineQueryId) { - m_engineQueryId = 0; - updateEngineList(qvariant_cast >(value)); - } else if (queryId == m_rootContextQueryId) { - m_rootContextQueryId = 0; - rootContextChanged(qvariant_cast(value)); - } else if (m_fetchCurrentObjectsQueryIds.contains(queryId)) { - m_fetchCurrentObjectsQueryIds.removeOne(queryId); if (value.type() == QVariant::List) { QVariantList objList = value.toList(); foreach (QVariant var, objList) { // TODO: check which among the list is the actual // object that needs to be selected. - ObjectReference obj - = qvariant_cast(var); - m_fetchCurrentObjects.push_front(obj); - onCurrentObjectsFetched(obj); + objectTreeFetched(qvariant_cast(var)); } } else { - ObjectReference obj - = qvariant_cast(value); - m_fetchCurrentObjects.push_front(obj); - onCurrentObjectsFetched(obj); + objectTreeFetched(qvariant_cast(value)); } + } else if (queryId == m_engineQueryId) { + m_engineQueryId = 0; + QList engines = qvariant_cast >(value); + QTC_ASSERT(engines.count(), return); + // only care about first engine atm + m_engine = engines.at(0); + queryEngineContext(); + } else if (queryId == m_rootContextQueryId) { + m_rootContextQueryId = 0; + clearObjectTree(); + fetchObjectsInContextRecursive(qvariant_cast(value)); } else { emit expressionResult(queryId, value); } @@ -417,13 +403,19 @@ void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value, } -void QmlInspectorAgent::newObject(int /*engineId*/, int /*objectId*/, int /*parentId*/) +void QmlInspectorAgent::newObject(int engineId, int objectId, int /*parentId*/) { if (debug) qDebug() << __FUNCTION__ << "()"; log(LogReceive, QString("OBJECT_CREATED")); - refreshObjectTree(); + + if (m_engine.debugId() != engineId) + return; + if (m_engineClient->objectName() == QmlDebug::Constants::QML_DEBUGGER) + fetchObject(objectId); + else + m_delayQueryTimer.start(); } void QmlInspectorAgent::reloadEngines() @@ -439,39 +431,36 @@ void QmlInspectorAgent::reloadEngines() m_engineQueryId = m_engineClient->queryAvailableEngines(); } -void QmlInspectorAgent::queryEngineContext(int id) +void QmlInspectorAgent::queryEngineContext() { if (debug) - qDebug() << __FUNCTION__ << "(" << id << ")"; - - if (id < 0) - return; + qDebug() << __FUNCTION__; if (!isConnected() || !debuggerCore()->boolSetting(ShowQmlObjectTree)) return; - log(LogSend, QString("LIST_OBJECTS %1").arg(QString::number(id))); + log(LogSend, QString("LIST_OBJECTS")); m_rootContextQueryId - = m_engineClient->queryRootContexts(EngineReference(id)); + = m_engineClient->queryRootContexts(m_engine); } -quint32 QmlInspectorAgent::fetchContextObject(const ObjectReference &obj) +void QmlInspectorAgent::fetchObject(int debugId) { if (debug) - qDebug() << __FUNCTION__ << "(" << obj << ")"; + qDebug() << __FUNCTION__ << "(" << debugId << ")"; if (!isConnected() || !debuggerCore()->boolSetting(ShowQmlObjectTree)) - return 0; + return; - log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString())); - quint32 queryId = m_engineClient->queryObject(obj); + log(LogSend, QString("FETCH_OBJECT %1").arg(QString::number(debugId))); + quint32 queryId = m_engineClient->queryObject(debugId); if (debug) - qDebug() << __FUNCTION__ << "(" << obj.debugId() << ")" + qDebug() << __FUNCTION__ << "(" << debugId << ")" << " - query id" << queryId; - return queryId; + m_objectTreeQueryIds << queryId; } void QmlInspectorAgent::fetchContextObjectsForLocation(const QString &file, @@ -495,60 +484,32 @@ void QmlInspectorAgent::fetchContextObjectsForLocation(const QString &file, qDebug() << __FUNCTION__ << "(" << file << ":" << lineNumber << ":" << columnNumber << ")" << " - query id" << queryId; - m_fetchCurrentObjectsQueryIds << queryId; + m_objectTreeQueryIds << queryId; } // fetch the root objects from the context + any child contexts -void QmlInspectorAgent::fetchRootObjects(const ContextReference &context, - bool clear) +void QmlInspectorAgent::fetchObjectsInContextRecursive(const ContextReference &context) { if (debug) - qDebug() << __FUNCTION__ << "(" << context << clear << ")"; + qDebug() << __FUNCTION__ << "(" << context << ")"; if (!isConnected() || !debuggerCore()->boolSetting(ShowQmlObjectTree)) return; - if (clear) { - m_rootObjects.clear(); - m_objectTreeQueryIds.clear(); - } foreach (const ObjectReference & obj, context.objects()) { - quint32 queryId = 0; using namespace QmlDebug::Constants; if (m_engineClient->objectName() == QML_DEBUGGER && m_engineClient->serviceVersion() >= CURRENT_SUPPORTED_VERSION) { //Fetch only root objects if (obj.parentId() == -1) - queryId = fetchContextObject(obj); + fetchObject(obj.debugId()); } else { - queryId = m_engineClient->queryObjectRecursive(obj); + m_objectTreeQueryIds << m_engineClient->queryObjectRecursive(obj.debugId()); } - - if (queryId) - m_objectTreeQueryIds << queryId; } foreach (const ContextReference &child, context.contexts()) - fetchRootObjects(child, false); -} - -void QmlInspectorAgent::updateEngineList(const QList &engines) -{ - if (debug) - qDebug() << __FUNCTION__ << "(" << engines << ")"; - - m_engines = engines; - - // only care about first engine atm - queryEngineContext(engines.first().debugId()); -} - -void QmlInspectorAgent::rootContextChanged(const ContextReference &context) -{ - if (debug) - qDebug() << __FUNCTION__ << "(" << context << ")"; - - fetchRootObjects(context, true); + fetchObjectsInContextRecursive(child); } void QmlInspectorAgent::objectTreeFetched(const ObjectReference &object) @@ -556,90 +517,75 @@ void QmlInspectorAgent::objectTreeFetched(const ObjectReference &object) if (debug) qDebug() << __FUNCTION__ << "(" << object << ")"; - m_rootObjects.append(object); - - if (m_objectTreeQueryIds.isEmpty()) { - int old_count = m_debugIdHash.count(); - m_debugIdHash.clear(); - m_debugIdHash.reserve(old_count + 1); - m_debugIdToIname.clear(); - foreach (const ObjectReference &it, m_rootObjects) - buildDebugIdHashRecursive(it); - - emit objectTreeUpdated(); - - // sync tree with watchhandler - QList watchData; - foreach (const ObjectReference &obj, m_rootObjects) - watchData.append(buildWatchData(obj, WatchData())); - - QElapsedTimer t; - if (debug) { - t.start(); - qDebug() << "inserting " << watchData.size() - << "entries into watch handler ..."; - } - - m_engine->watchHandler()->insertData(watchData); - - if (debug) - qDebug() << "inserting entries took" << t.elapsed() << "ms"; - } -} - -void QmlInspectorAgent::onCurrentObjectsFetched(const ObjectReference &obj) -{ - if (debug) - qDebug() << __FUNCTION__ << "( " << obj << ")"; - - // get parents if not known yet - if (!getObjectHierarchy(obj)) + if (!object.isValid()) return; - if (debug) - qDebug() << " adding" << m_fetchCurrentObjects << "to tree"; + m_objectStack.push(object); - foreach (const ObjectReference &o, m_fetchCurrentObjects) - addObjectToTree(o, false); - - ObjectReference last = m_fetchCurrentObjects.last(); - m_fetchCurrentObjects.clear(); - m_fetchDataIds.clear(); - - if (m_objectToSelect == last.debugId()) { - // select item in view - QByteArray iname = m_debugIdToIname.value(last.debugId()); - WatchHandler *handler = m_engine->watchHandler(); - QTC_ASSERT(handler->hasItem(iname), return); - if (debug) - qDebug() << " selecting" << iname << "in tree"; - handler->setCurrentItem(iname); - m_objectToSelect = -1; + if (m_engineClient->objectName() == QmlDebug::Constants::QML_DEBUGGER) { + if (object.parentId() != -1 && !m_debugIdToIname.contains(object.parentId())) { + fetchObject(object.parentId()); + return; + } + } else if (m_objectTreeQueryIds.count()) { + return; } - emit objectFetched(last); - emit objectTreeUpdated(); -} - -// Fetches all anchestors of object. Returns if all has been fetched already. -bool QmlInspectorAgent::getObjectHierarchy(const ObjectReference &obj) -{ - if (debug) - qDebug() << __FUNCTION__ << "(" << obj << ")"; - - ObjectReference parent = objectForId(obj.parentId()); - //for root object - if (obj.parentId() == -1) - return true; - - //for other objects - if (parent.debugId() == -1 || parent.needsMoreData()) { - m_fetchCurrentObjectsQueryIds - << fetchContextObject(ObjectReference(obj.parentId())); + // sync tree with watchhandler + QList watchData; + ObjectReference last; + if (m_engineClient->objectName() == QmlDebug::Constants::QML_DEBUGGER) { + while (!m_objectStack.isEmpty()) { + last = m_objectStack.pop(); + QByteArray parentIname; + if (last.parentId() != -1) { + QTC_ASSERT(m_debugIdToIname.contains(last.parentId()), return); + parentIname = m_debugIdToIname.value(last.parentId()); + } + watchData.append(buildWatchData(last, parentIname)); + buildDebugIdHashRecursive(last); + } } else { - return getObjectHierarchy(parent); + QVectorIterator iter(m_objectStack); + while (iter.hasNext()) { + const ObjectReference &r = iter.next(); + int pid = -1; + QHashIterator > i(m_debugIdChildIds); + while (i.hasNext()) { + QList cids = i.value(); + foreach (int cid, cids) { + if (cid == r.debugId()) { + pid = i.key(); + break; + } + } + if (pid != -1) + break; + } + QByteArray parentIname; + if (m_debugIdToIname.contains(pid)) + parentIname = m_debugIdToIname.value(r.parentId()); + watchData.append(buildWatchData(r, parentIname)); + buildDebugIdHashRecursive(r); + } + m_objectStack.clear(); + } + + m_debuggerEngine->watchHandler()->insertData(watchData); + emit objectTreeUpdated(); + + if (m_engineClient->objectName() == QmlDebug::Constants::QML_DEBUGGER) { + emit objectFetched(last); + + if (m_objectToSelect == last.debugId()) { + // select item in view + QByteArray iname = m_debugIdToIname.value(last.debugId()); + if (debug) + qDebug() << " selecting" << iname << "in tree"; + m_debuggerEngine->watchHandler()->setCurrentItem(iname); + m_objectToSelect = -1; + } } - return false; } void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref) @@ -662,35 +608,35 @@ void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref) } const QString filePath - = m_engine->toFileInProject(fileUrl); + = m_debuggerEngine->toFileInProject(fileUrl); // append the debug ids in the hash QPair file = qMakePair(filePath, rev); QPair location = qMakePair(lineNum, colNum); if (!m_debugIdHash[file][location].contains(ref.debugId())) m_debugIdHash[file][location].append(ref.debugId()); - + m_debugIdLocations.insert(ref.debugId(), FileReference(filePath, lineNum, colNum)); foreach (const ObjectReference &it, ref.children()) buildDebugIdHashRecursive(it); } -static QByteArray buildIName(const WatchData &parent, int debugId) +static QByteArray buildIName(const QByteArray &parentIname, int debugId) { - if (!parent.isValid()) + if (parentIname.isEmpty()) return "inspect." + QByteArray::number(debugId); - return parent.iname + "." + QByteArray::number(debugId); + return parentIname + "." + QByteArray::number(debugId); } -static QByteArray buildIName(const WatchData &parent, const QString &name) +static QByteArray buildIName(const QByteArray &parentIname, const QString &name) { - return parent.iname + "." + name.toLatin1(); + return parentIname + "." + name.toLatin1(); } QList QmlInspectorAgent::buildWatchData(const ObjectReference &obj, - const WatchData &parent) + const QByteArray &parentIname) { if (debug) - qDebug() << __FUNCTION__ << "(" << obj << parent.iname << ")"; + qDebug() << __FUNCTION__ << "(" << obj << parentIname << ")"; QList list; @@ -699,11 +645,14 @@ QList QmlInspectorAgent::buildWatchData(const ObjectReference &obj, if (name.isEmpty()) name = obj.className(); + if (name.isEmpty()) + return list; + // object objWatch.id = obj.debugId(); objWatch.exp = name.toLatin1(); objWatch.name = name; - objWatch.iname = buildIName(parent, obj.debugId()); + objWatch.iname = buildIName(parentIname, obj.debugId()); objWatch.type = obj.className().toLatin1(); objWatch.value = _("object"); objWatch.setHasChildren(true); @@ -712,7 +661,17 @@ QList QmlInspectorAgent::buildWatchData(const ObjectReference &obj, list.append(objWatch); m_debugIdToIname.insert(objWatch.id, objWatch.iname); - if (!m_engine->watchHandler()->isExpandedIName(objWatch.iname) + if (m_engineClient->objectName() != QmlDebug::Constants::QML_DEBUGGER) { + QList childIds; + foreach (const ObjectReference &c, obj.children()) { + childIds << c.debugId(); + } + // For 4.x, we do not get the parentId. Hence, store the child ids + // to look up correct insertion places later + m_debugIdChildIds.insert(objWatch.id, childIds); + } + + if (!m_debuggerEngine->watchHandler()->isExpandedIName(objWatch.iname) && obj.needsMoreData()) { // we don't know the children yet. Not adding the 'properties' // element makes sure we're queried on expansion. @@ -720,94 +679,38 @@ QList QmlInspectorAgent::buildWatchData(const ObjectReference &obj, } // properties - WatchData propertiesWatch; - propertiesWatch.id = objWatch.id; - propertiesWatch.exp = ""; - propertiesWatch.name = tr("properties"); - propertiesWatch.iname = objWatch.iname + ".[properties]"; - propertiesWatch.type = ""; - propertiesWatch.value = _("list"); - propertiesWatch.setHasChildren(true); - propertiesWatch.setAllUnneeded(); + if (obj.properties().count()) { + WatchData propertiesWatch; + propertiesWatch.id = objWatch.id; + propertiesWatch.exp = ""; + propertiesWatch.name = tr("properties"); + propertiesWatch.iname = objWatch.iname + ".[properties]"; + propertiesWatch.type = ""; + propertiesWatch.value = _("list"); + propertiesWatch.setHasChildren(true); + propertiesWatch.setAllUnneeded(); - list.append(propertiesWatch); + list.append(propertiesWatch); - foreach (const PropertyReference &property, obj.properties()) { - WatchData propertyWatch; - propertyWatch.exp = property.name().toLatin1(); - propertyWatch.name = property.name(); - propertyWatch.iname = buildIName(propertiesWatch, property.name()); - propertyWatch.type = property.valueTypeName().toLatin1(); - propertyWatch.value = property.value().toString(); - propertyWatch.setAllUnneeded(); - propertyWatch.setHasChildren(false); - list.append(propertyWatch); + foreach (const PropertyReference &property, obj.properties()) { + WatchData propertyWatch; + propertyWatch.exp = property.name().toLatin1(); + propertyWatch.name = property.name(); + propertyWatch.iname = buildIName(propertiesWatch.iname, property.name()); + propertyWatch.type = property.valueTypeName().toLatin1(); + propertyWatch.value = property.value().toString(); + propertyWatch.setAllUnneeded(); + propertyWatch.setHasChildren(false); + list.append(propertyWatch); + } } // recurse foreach (const ObjectReference &child, obj.children()) - list.append(buildWatchData(child, objWatch)); + list.append(buildWatchData(child, objWatch.iname)); return list; } -void QmlInspectorAgent::addObjectToTree(const ObjectReference &obj, - bool notify) -{ - int count = m_rootObjects.count(); - for (int i = 0; i < count; i++) { - int parentId = obj.parentId(); - if (m_engineClient->serviceVersion() < 2 - && !m_rootObjects.contains(obj)) { - // we don't get parentId in qt 4.x - parentId = m_rootObjects[i].insertObjectInTree(obj); - } - - if (parentId >= 0) { - buildDebugIdHashRecursive(obj); - if (notify) - emit objectTreeUpdated(); - - // find parent - QTC_ASSERT(m_debugIdToIname.contains(parentId), break); - QByteArray iname = m_debugIdToIname.value(parentId); - WatchHandler *handler = m_engine->watchHandler(); - const WatchData *parent = handler->findData(iname); - if (parent) { - QList watches = buildWatchData(obj, *parent); - handler->insertData(watches); - break; - } - } - } -} - -ObjectReference QmlInspectorAgent::objectForId(int debugId, - const ObjectReference &objectRef) const -{ - if (objectRef.debugId() == debugId) - return objectRef; - - foreach (const ObjectReference &child, objectRef.children()) { - ObjectReference result = objectForId(debugId, child); - if (result.debugId() == debugId) - return result; - } - - return ObjectReference(); -} - -QList QmlInspectorAgent::objects( - const ObjectReference &objectRef) const -{ - QList result; - result.append(objectRef); - - foreach (const ObjectReference &child, objectRef.children()) - result.append(objects(child)); - - return result; -} - void QmlInspectorAgent::log(QmlInspectorAgent::LogDirection direction, const QString &message) { @@ -818,15 +721,29 @@ void QmlInspectorAgent::log(QmlInspectorAgent::LogDirection direction, msg += _(" receiving "); msg += message; - if (m_engine) - m_engine->showMessage(msg, LogDebug); + if (m_debuggerEngine) + m_debuggerEngine->showMessage(msg, LogDebug); } -bool QmlInspectorAgent::isConnected() +bool QmlInspectorAgent::isConnected() const { return m_engineClient && (m_engineClient->status() == QmlDebug::Enabled); } +void QmlInspectorAgent::clearObjectTree() +{ + // clear view + m_debuggerEngine->watchHandler()->removeChildren("inspect"); + + m_objectTreeQueryIds.clear(); + + int old_count = m_debugIdHash.count(); + m_debugIdHash.clear(); + m_debugIdHash.reserve(old_count + 1); + m_debugIdToIname.clear(); + m_debugIdChildIds.clear(); + m_objectStack.clear(); +} } // Internal } // Debugger diff --git a/src/plugins/debugger/qml/qmlinspectoragent.h b/src/plugins/debugger/qml/qmlinspectoragent.h index 67bd0b82860..5273e4593a2 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.h +++ b/src/plugins/debugger/qml/qmlinspectoragent.h @@ -34,6 +34,8 @@ #define QMLINSPECTORAGENT_H #include +#include +#include #include #include @@ -57,7 +59,6 @@ public: explicit QmlInspectorAgent(DebuggerEngine *engine, QObject *parent = 0); - void refreshObjectTree(); void fetchObject(int debugId); quint32 queryExpressionResult(int debugId, const QString &expression); @@ -75,11 +76,9 @@ public: quint32 resetBindingForObject(int objectDebugId, const QString &propertyName); - QList objects() const; - QmlDebug::ObjectReference objectForId(int debugId) const; QmlDebug::ObjectReference objectForId(const QString &objectId) const; - QmlDebug::ObjectReference objectForLocation(int line, int column) const; - QList rootObjects() const { return m_rootObjects; } + int objectIdForLocation(int line, int column) const; + QHash rootObjectIds() const; DebugIdHash debugIdHash() const { return m_debugIdHash; } bool addObjectWatch(int objectDebugId); @@ -88,10 +87,13 @@ public: void removeAllObjectWatches(); void setEngineClient(QmlDebug::BaseEngineDebugClient *client); + QString displayName(int objectDebugId) const; public slots: void fetchContextObjectsForLocation(const QString &file, int lineNumber, int columnNumber); + void queryEngineContext(); + signals: void objectTreeUpdated(); void objectFetched(const QmlDebug::ObjectReference &ref); @@ -106,28 +108,13 @@ private slots: private: void reloadEngines(); - void queryEngineContext(int id); - quint32 fetchContextObject(const QmlDebug::ObjectReference &obj); - void fetchRootObjects(const QmlDebug::ContextReference &context, bool clear); + void fetchObjectsInContextRecursive(const QmlDebug::ContextReference &context); - void updateEngineList(const QList &engines); - void rootContextChanged(const QmlDebug::ContextReference &context); void objectTreeFetched(const QmlDebug::ObjectReference &result); - void onCurrentObjectsFetched(const QmlDebug::ObjectReference &result); - bool getObjectHierarchy(const QmlDebug::ObjectReference &object); - void buildDebugIdHashRecursive(const QmlDebug::ObjectReference &ref); QList buildWatchData(const QmlDebug::ObjectReference &obj, - const WatchData &parent); - void addObjectToTree(const QmlDebug::ObjectReference &obj, bool notify); - - QmlDebug::ObjectReference objectForId( - int debugId, - const QmlDebug::ObjectReference &ref) const; - QList objects( - const QmlDebug::ObjectReference &objectRef) const; - + const QByteArray &parentIname); enum LogDirection { LogSend, @@ -135,25 +122,27 @@ private: }; void log(LogDirection direction, const QString &message); - bool isConnected(); + bool isConnected() const; + void clearObjectTree(); private: - DebuggerEngine *m_engine; + DebuggerEngine *m_debuggerEngine; QmlDebug::BaseEngineDebugClient *m_engineClient; quint32 m_engineQueryId; quint32 m_rootContextQueryId; int m_objectToSelect; QList m_objectTreeQueryIds; - QList m_rootObjects; - QList m_fetchCurrentObjectsQueryIds; - QList m_fetchCurrentObjects; - QList m_engines; + QStack m_objectStack; + QmlDebug::EngineReference m_engine; QHash m_debugIdToIname; + QHash > m_debugIdChildIds; // This is for 4.x + QHash m_debugIdLocations; DebugIdHash m_debugIdHash; QList m_objectWatches; QList m_fetchDataIds; + QTimer m_delayQueryTimer; }; } // Internal diff --git a/src/plugins/debugger/qml/qmllivetextpreview.cpp b/src/plugins/debugger/qml/qmllivetextpreview.cpp index 64ac5dc9475..f3995e8fa9f 100644 --- a/src/plugins/debugger/qml/qmllivetextpreview.cpp +++ b/src/plugins/debugger/qml/qmllivetextpreview.cpp @@ -440,19 +440,6 @@ void QmlLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges) m_applyChangesToQmlInspector = applyChanges; } -static QList findRootObjectRecursive(const ObjectReference &object, - const Document::Ptr &doc) -{ - QList result; - if (object.className() == doc->componentName()) - result += object.debugId(); - - foreach (const ObjectReference &it, object.children()) { - result += findRootObjectRecursive(it, doc); - } - return result; -} - void QmlLiveTextPreview::updateDebugIds() { if (!m_initialDoc->qmlProgram()) @@ -485,11 +472,13 @@ void QmlLiveTextPreview::updateDebugIds() // Map the root nodes of the document. if (doc->qmlProgram()->members && doc->qmlProgram()->members->member) { UiObjectMember *root = doc->qmlProgram()->members->member; + QHashIterator rIds(m_inspectorAdapter->agent()->rootObjectIds()); QList r; - foreach (const ObjectReference& it, - m_inspectorAdapter->agent()->rootObjects()) { - r += findRootObjectRecursive(it, doc); - } + while (rIds.hasNext()) { + rIds.next(); + if (rIds.value() == doc->componentName()) + r += rIds.key(); + } if (!r.isEmpty()) m_debugIds[root] += r; } @@ -561,7 +550,7 @@ bool QmlLiveTextPreview::changeSelectedElements(const QList offsets, QList list = objectReferencesForOffset(offset); if (!containsReferenceUnderCursor - && objectRefUnderCursor.debugId() != -1) { + && objectRefUnderCursor.isValid()) { foreach (int id, list) { if (id == objectRefUnderCursor.debugId()) { containsReferenceUnderCursor = true; @@ -577,7 +566,7 @@ bool QmlLiveTextPreview::changeSelectedElements(const QList offsets, // fallback: use ref under cursor if nothing else is found if (selectedReferences.isEmpty() && !containsReferenceUnderCursor - && objectRefUnderCursor.debugId() != -1) { + && objectRefUnderCursor.isValid()) { selectedReferences << objectRefUnderCursor.debugId(); } @@ -613,7 +602,7 @@ void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) m_debugIds = delta(m_previousDoc, doc, m_debugIds); if (delta.referenceRefreshRequired) - m_inspectorAdapter->agent()->refreshObjectTree(); + m_inspectorAdapter->agent()->queryEngineContext(); if (delta.unsyncronizableChanges != NoUnsyncronizableChanges) {