2012-04-18 14:20:54 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
2012-07-19 12:26:56 +02:00
|
|
|
** Contact: http://www.qt-project.org/
|
2012-04-18 14:20:54 +02:00
|
|
|
**
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
|
|
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
|
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
|
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
|
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
|
|
|
** Public License version 2.1 requirements will be met:
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
|
|
|
|
** Other Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "qmlinspectoragent.h"
|
|
|
|
|
|
|
|
|
|
#include "debuggeractions.h"
|
|
|
|
|
#include "debuggercore.h"
|
|
|
|
|
#include "debuggerengine.h"
|
|
|
|
|
#include "debuggerstringutils.h"
|
|
|
|
|
#include "watchhandler.h"
|
|
|
|
|
|
|
|
|
|
#include <qmldebug/qmldebugconstants.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/savedaction.h>
|
2012-05-15 16:39:11 +02:00
|
|
|
#include <QElapsedTimer>
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-10 10:29:11 +02:00
|
|
|
using namespace QmlDebug;
|
2012-09-28 14:40:57 +02:00
|
|
|
using namespace QmlDebug::Constants;
|
2012-05-10 10:29:11 +02:00
|
|
|
|
2012-04-18 14:20:54 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
debug = false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* DebuggerAgent updates the watchhandler with the object tree data.
|
|
|
|
|
*/
|
|
|
|
|
QmlInspectorAgent::QmlInspectorAgent(DebuggerEngine *engine, QObject *parent)
|
|
|
|
|
: QObject(parent)
|
2012-05-14 23:26:23 +02:00
|
|
|
, m_debuggerEngine(engine)
|
2012-04-18 14:20:54 +02:00
|
|
|
, m_engineClient(0)
|
|
|
|
|
, m_engineQueryId(0)
|
|
|
|
|
, m_rootContextQueryId(0)
|
|
|
|
|
, m_objectToSelect(-1)
|
2012-05-29 22:21:04 +02:00
|
|
|
, m_newObjectsCreated(false)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
connect(debuggerCore()->action(ShowQmlObjectTree),
|
|
|
|
|
SIGNAL(valueChanged(QVariant)), SLOT(updateStatus()));
|
2012-05-14 23:26:23 +02:00
|
|
|
m_delayQueryTimer.setSingleShot(true);
|
2012-05-29 22:21:04 +02:00
|
|
|
m_delayQueryTimer.setInterval(100);
|
2012-05-14 23:26:23 +02:00
|
|
|
connect(&m_delayQueryTimer, SIGNAL(timeout()), SLOT(queryEngineContext()));
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint32 QmlInspectorAgent::queryExpressionResult(int debugId,
|
|
|
|
|
const QString &expression)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << debugId << expression
|
|
|
|
|
<< m_engine.debugId() << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
return m_engineClient->queryExpressionResult(debugId, expression,
|
2012-05-14 23:26:23 +02:00
|
|
|
m_engine.debugId());
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-23 14:55:48 +02:00
|
|
|
void QmlInspectorAgent::assignValue(const WatchData *data,
|
|
|
|
|
const QString &expr, const QVariant &valueV)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << data->id << ')' << data->iname;
|
2012-05-23 14:55:48 +02:00
|
|
|
|
|
|
|
|
if (data->id) {
|
|
|
|
|
QString val(valueV.toString());
|
|
|
|
|
if (valueV.type() == QVariant::String) {
|
|
|
|
|
val = val.replace(QLatin1Char('\"'), QLatin1String("\\\""));
|
|
|
|
|
val = QLatin1Char('\"') + val + QLatin1Char('\"');
|
|
|
|
|
}
|
|
|
|
|
QString expression = QString(_("%1 = %2;")).arg(expr).arg(val);
|
|
|
|
|
queryExpressionResult(data->id, expression);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-01 17:13:21 +02:00
|
|
|
int parentIdForIname(const QByteArray &iname)
|
|
|
|
|
{
|
|
|
|
|
// Extract the parent id
|
|
|
|
|
int lastIndex = iname.lastIndexOf('.');
|
|
|
|
|
int secondLastIndex = iname.lastIndexOf('.', lastIndex - 1);
|
|
|
|
|
int parentId = -1;
|
|
|
|
|
if (secondLastIndex != -1)
|
|
|
|
|
parentId = iname.mid(secondLastIndex + 1, lastIndex - secondLastIndex - 1).toInt();
|
|
|
|
|
return parentId;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-18 14:20:54 +02:00
|
|
|
void QmlInspectorAgent::updateWatchData(const WatchData &data)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << data.id << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
if (data.id && !m_fetchDataIds.contains(data.id)) {
|
2012-04-18 14:20:54 +02:00
|
|
|
// objects
|
2012-10-01 17:13:21 +02:00
|
|
|
using namespace QmlDebug::Constants;
|
|
|
|
|
if (m_engineClient->objectName() == QLatin1String(QDECLARATIVE_ENGINE)) {
|
|
|
|
|
int parentId = parentIdForIname(data.iname);
|
|
|
|
|
if (parentId != -1) {
|
|
|
|
|
QList<int> childIds = m_debugIdChildIds.value(parentId);
|
|
|
|
|
childIds << data.id;
|
|
|
|
|
m_debugIdChildIds.insert(parentId, childIds);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-18 02:28:41 +02:00
|
|
|
m_fetchDataIds << data.id;
|
2012-05-14 23:26:23 +02:00
|
|
|
fetchObject(data.id);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-25 17:43:56 +02:00
|
|
|
bool QmlInspectorAgent::selectObjectInTree(int debugId)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug) {
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << debugId << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
qDebug() << " " << debugId << "already fetched? "
|
|
|
|
|
<< m_debugIdToIname.contains(debugId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_debugIdToIname.contains(debugId)) {
|
|
|
|
|
QByteArray iname = m_debugIdToIname.value(debugId);
|
|
|
|
|
QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname);
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << " selecting" << iname << "in tree";
|
2012-05-14 23:26:23 +02:00
|
|
|
m_debuggerEngine->watchHandler()->setCurrentItem(iname);
|
2012-04-18 14:20:54 +02:00
|
|
|
m_objectToSelect = 0;
|
2012-05-25 17:43:56 +02:00
|
|
|
return true;
|
2012-04-18 14:20:54 +02:00
|
|
|
} else {
|
2012-10-05 12:46:30 +02:00
|
|
|
// we may have to fetch it
|
2012-04-18 14:20:54 +02:00
|
|
|
m_objectToSelect = debugId;
|
2012-10-05 12:46:30 +02:00
|
|
|
using namespace QmlDebug::Constants;
|
|
|
|
|
if (m_engineClient->objectName() == QLatin1String(QDECLARATIVE_ENGINE)) {
|
|
|
|
|
// reset current Selection
|
|
|
|
|
QByteArray root = m_debuggerEngine->watchHandler()->watchData(QModelIndex())->iname;
|
|
|
|
|
m_debuggerEngine->watchHandler()->setCurrentItem(root);
|
|
|
|
|
} else {
|
|
|
|
|
fetchObject(debugId);
|
|
|
|
|
}
|
2012-05-25 17:43:56 +02:00
|
|
|
return false;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint32 QmlInspectorAgent::setBindingForObject(int objectDebugId,
|
|
|
|
|
const QString &propertyName,
|
|
|
|
|
const QVariant &value,
|
|
|
|
|
bool isLiteralValue,
|
|
|
|
|
QString source,
|
|
|
|
|
int line)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << objectDebugId << propertyName
|
|
|
|
|
<< value.toString() << isLiteralValue << source << line << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (objectDebugId == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (propertyName == QLatin1String("id"))
|
|
|
|
|
return 0; // Crashes the QMLViewer.
|
|
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QString::fromLatin1("SET_BINDING %1 %2 %3 %4").arg(
|
2012-04-18 14:20:54 +02:00
|
|
|
QString::number(objectDebugId), propertyName, value.toString(),
|
2012-08-22 11:58:33 +02:00
|
|
|
QString(isLiteralValue ? QLatin1String("true") : QLatin1String("false"))));
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
quint32 queryId = m_engineClient->setBindingForObject(
|
|
|
|
|
objectDebugId, propertyName, value.toString(), isLiteralValue,
|
|
|
|
|
source, line);
|
|
|
|
|
|
|
|
|
|
if (!queryId)
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QLatin1String("SET_BINDING failed!"));
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
return queryId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint32 QmlInspectorAgent::setMethodBodyForObject(int objectDebugId,
|
|
|
|
|
const QString &methodName,
|
|
|
|
|
const QString &methodBody)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << objectDebugId
|
|
|
|
|
<< methodName << methodBody << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (objectDebugId == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QString::fromLatin1("SET_METHOD_BODY %1 %2 %3").arg(
|
2012-04-18 14:20:54 +02:00
|
|
|
QString::number(objectDebugId), methodName, methodBody));
|
|
|
|
|
|
|
|
|
|
quint32 queryId = m_engineClient->setMethodBody(
|
|
|
|
|
objectDebugId, methodName, methodBody);
|
|
|
|
|
|
|
|
|
|
if (!queryId)
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QLatin1String("failed!"));
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
return queryId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint32 QmlInspectorAgent::resetBindingForObject(int objectDebugId,
|
|
|
|
|
const QString &propertyName)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << objectDebugId
|
|
|
|
|
<< propertyName << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (objectDebugId == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QString::fromLatin1("RESET_BINDING %1 %2").arg(
|
2012-04-18 14:20:54 +02:00
|
|
|
QString::number(objectDebugId), propertyName));
|
|
|
|
|
|
|
|
|
|
quint32 queryId = m_engineClient->resetBindingForObject(
|
|
|
|
|
objectDebugId, propertyName);
|
|
|
|
|
|
|
|
|
|
if (!queryId)
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QLatin1String("failed!"));
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
return queryId;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-25 17:43:56 +02:00
|
|
|
ObjectReference QmlInspectorAgent::objectForName(
|
2012-04-18 14:20:54 +02:00
|
|
|
const QString &objectId) const
|
|
|
|
|
{
|
|
|
|
|
if (!objectId.isEmpty() && objectId[0].isLower()) {
|
2012-05-14 23:26:23 +02:00
|
|
|
QHashIterator<int, QByteArray> iter(m_debugIdToIname);
|
2012-05-31 15:50:06 +02:00
|
|
|
const WatchHandler *watchHandler = m_debuggerEngine->watchHandler();
|
2012-05-14 23:26:23 +02:00
|
|
|
while (iter.hasNext()) {
|
|
|
|
|
iter.next();
|
2012-05-31 15:50:06 +02:00
|
|
|
const WatchData *wd = watchHandler->findData(iter.value());
|
2012-05-29 22:21:04 +02:00
|
|
|
if (wd && wd->name == objectId)
|
2012-05-14 23:26:23 +02:00
|
|
|
return ObjectReference(iter.key());
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-10 10:29:11 +02:00
|
|
|
return ObjectReference();
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-25 17:43:56 +02:00
|
|
|
ObjectReference QmlInspectorAgent::objectForId(int objectDebugId) const
|
|
|
|
|
{
|
|
|
|
|
if (!m_debugIdToIname.contains(objectDebugId))
|
|
|
|
|
return ObjectReference(objectDebugId);
|
|
|
|
|
|
|
|
|
|
int line = -1;
|
|
|
|
|
int column = -1;
|
|
|
|
|
QString file;
|
|
|
|
|
QHashIterator<QPair<QString, int>, QHash<QPair<int, int>, QList<int> > > iter(m_debugIdHash);
|
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
|
iter.next();
|
|
|
|
|
QHashIterator<QPair<int, int>, QList<int> > i(iter.value());
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
i.next();
|
|
|
|
|
if (i.value().contains(objectDebugId)) {
|
|
|
|
|
line = i.key().first;
|
|
|
|
|
column = i.key().second;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (line != -1) {
|
|
|
|
|
file = iter.key().first;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// TODO: Set correct parentId
|
|
|
|
|
return ObjectReference(objectDebugId, -1,
|
|
|
|
|
FileReference(QUrl::fromLocalFile(file), line, column));
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
int QmlInspectorAgent::objectIdForLocation(
|
2012-04-18 14:20:54 +02:00
|
|
|
int line, int column) const
|
|
|
|
|
{
|
2012-05-14 23:26:23 +02:00
|
|
|
QHashIterator<int, FileReference> iter(m_debugIdLocations);
|
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
|
iter.next();
|
|
|
|
|
const FileReference &ref = iter.value();
|
|
|
|
|
if (ref.lineNumber() == line
|
|
|
|
|
&& ref.columnNumber() == column)
|
|
|
|
|
return iter.key();
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QHash<int,QString> QmlInspectorAgent::rootObjectIds() const
|
|
|
|
|
{
|
|
|
|
|
QHash<int,QString> rIds;
|
2012-05-31 15:50:06 +02:00
|
|
|
const WatchHandler *watchHandler = m_debuggerEngine->watchHandler();
|
2012-05-14 23:26:23 +02:00
|
|
|
foreach (const QByteArray &in, m_debugIdToIname) {
|
2012-05-31 15:50:06 +02:00
|
|
|
const WatchData *data = watchHandler->findData(in);
|
2012-05-25 09:33:02 +02:00
|
|
|
if (!data)
|
|
|
|
|
continue;
|
2012-05-14 23:26:23 +02:00
|
|
|
int debugId = data->id;
|
2012-08-22 11:58:33 +02:00
|
|
|
QString className = QLatin1String(data->type);
|
2012-05-14 23:26:23 +02:00
|
|
|
rIds.insert(debugId, className);
|
|
|
|
|
}
|
|
|
|
|
return rIds;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QmlInspectorAgent::addObjectWatch(int objectDebugId)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << objectDebugId << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (objectDebugId == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// already set
|
|
|
|
|
if (m_objectWatches.contains(objectDebugId))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// is flooding the debugging output log!
|
|
|
|
|
// log(LogSend, QString("WATCH_PROPERTY %1").arg(objectDebugId));
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
if (m_engineClient->addWatch(objectDebugId))
|
2012-04-18 14:20:54 +02:00
|
|
|
m_objectWatches.append(objectDebugId);
|
|
|
|
|
|
2012-05-23 14:55:48 +02:00
|
|
|
return true;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QmlInspectorAgent::isObjectBeingWatched(int objectDebugId)
|
|
|
|
|
{
|
|
|
|
|
return m_objectWatches.contains(objectDebugId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QmlInspectorAgent::removeObjectWatch(int objectDebugId)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << objectDebugId << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (objectDebugId == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!m_objectWatches.contains(objectDebugId))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!isConnected())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_objectWatches.removeOne(objectDebugId);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlInspectorAgent::removeAllObjectWatches()
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "()";
|
|
|
|
|
|
|
|
|
|
foreach (int watchedObject, m_objectWatches)
|
|
|
|
|
removeObjectWatch(watchedObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlInspectorAgent::setEngineClient(BaseEngineDebugClient *client)
|
|
|
|
|
{
|
|
|
|
|
if (m_engineClient == client)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (m_engineClient) {
|
2012-05-10 10:29:11 +02:00
|
|
|
disconnect(m_engineClient, SIGNAL(newStatus(QmlDebug::ClientStatus)),
|
2012-04-18 14:20:54 +02:00
|
|
|
this, SLOT(updateStatus()));
|
|
|
|
|
disconnect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
|
|
|
|
this, SLOT(onResult(quint32,QVariant,QByteArray)));
|
2012-05-14 16:11:12 +02:00
|
|
|
disconnect(m_engineClient, SIGNAL(newObject(int,int,int)),
|
|
|
|
|
this, SLOT(newObject(int,int,int)));
|
2012-05-23 14:55:48 +02:00
|
|
|
disconnect(m_engineClient, SIGNAL(valueChanged(int,QByteArray,QVariant)),
|
|
|
|
|
this, SLOT(onValueChanged(int,QByteArray,QVariant)));
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_engineClient = client;
|
|
|
|
|
|
|
|
|
|
if (m_engineClient) {
|
2012-05-10 10:29:11 +02:00
|
|
|
connect(m_engineClient, SIGNAL(newStatus(QmlDebug::ClientStatus)),
|
2012-04-18 14:20:54 +02:00
|
|
|
this, SLOT(updateStatus()));
|
|
|
|
|
connect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
|
|
|
|
this, SLOT(onResult(quint32,QVariant,QByteArray)));
|
2012-05-14 16:11:12 +02:00
|
|
|
connect(m_engineClient, SIGNAL(newObject(int,int,int)),
|
|
|
|
|
this, SLOT(newObject(int,int,int)));
|
2012-05-23 14:55:48 +02:00
|
|
|
connect(m_engineClient, SIGNAL(valueChanged(int,QByteArray,QVariant)),
|
|
|
|
|
this, SLOT(onValueChanged(int,QByteArray,QVariant)));
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateStatus();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-18 14:20:54 +02:00
|
|
|
void QmlInspectorAgent::updateStatus()
|
|
|
|
|
{
|
|
|
|
|
if (m_engineClient
|
2012-05-10 10:29:11 +02:00
|
|
|
&& (m_engineClient->status() == QmlDebug::Enabled)
|
2012-04-18 14:20:54 +02:00
|
|
|
&& debuggerCore()->boolSetting(ShowQmlObjectTree)) {
|
|
|
|
|
reloadEngines();
|
|
|
|
|
} else {
|
2012-05-14 23:26:23 +02:00
|
|
|
clearObjectTree();
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value,
|
|
|
|
|
const QByteArray &type)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "() ...";
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
if (type == "FETCH_OBJECT_R") {
|
2012-04-18 14:20:54 +02:00
|
|
|
log(LogReceive, _("FETCH_OBJECT_R %1").arg(
|
2012-05-10 10:29:11 +02:00
|
|
|
qvariant_cast<ObjectReference>(value).idString()));
|
2012-08-22 11:58:33 +02:00
|
|
|
} else if (type == "SET_BINDING_R"
|
|
|
|
|
|| type == "RESET_BINDING_R"
|
|
|
|
|
|| type == "SET_METHOD_BODY_R") {
|
2012-10-01 10:07:12 +02:00
|
|
|
QString msg = QLatin1String(type) + tr("Success: ");
|
2012-08-22 11:58:33 +02:00
|
|
|
msg += value.toBool() ? QLatin1Char('1') : QLatin1Char('0');
|
2012-06-04 17:17:50 +02:00
|
|
|
if (!value.toBool())
|
|
|
|
|
emit automaticUpdateFailed();
|
|
|
|
|
log(LogReceive, msg);
|
2012-04-18 14:20:54 +02:00
|
|
|
} else {
|
|
|
|
|
log(LogReceive, QLatin1String(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_objectTreeQueryIds.contains(queryId)) {
|
|
|
|
|
m_objectTreeQueryIds.removeOne(queryId);
|
2012-05-10 17:06:29 +02:00
|
|
|
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.
|
2012-10-01 17:13:21 +02:00
|
|
|
insertObjectInTree(qvariant_cast<ObjectReference>(var));
|
2012-05-10 17:06:29 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2012-10-01 17:13:21 +02:00
|
|
|
insertObjectInTree(qvariant_cast<ObjectReference>(value));
|
2012-05-10 17:06:29 +02:00
|
|
|
}
|
2012-05-14 23:26:23 +02:00
|
|
|
} else if (queryId == m_engineQueryId) {
|
|
|
|
|
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);
|
|
|
|
|
queryEngineContext();
|
|
|
|
|
} else if (queryId == m_rootContextQueryId) {
|
|
|
|
|
m_rootContextQueryId = 0;
|
|
|
|
|
clearObjectTree();
|
2012-10-01 17:13:21 +02:00
|
|
|
updateObjectTree(qvariant_cast<ContextReference>(value));
|
2012-04-18 14:20:54 +02:00
|
|
|
} else {
|
|
|
|
|
emit expressionResult(queryId, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "done";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
void QmlInspectorAgent::newObject(int engineId, int objectId, int /*parentId*/)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "()";
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogReceive, QLatin1String("OBJECT_CREATED"));
|
2012-05-14 23:26:23 +02:00
|
|
|
|
|
|
|
|
if (m_engine.debugId() != engineId)
|
|
|
|
|
return;
|
2012-05-29 22:21:04 +02:00
|
|
|
|
|
|
|
|
m_newObjectsCreated = true;
|
2012-09-28 14:40:57 +02:00
|
|
|
if (m_engineClient->objectName() != QLatin1String(QDECLARATIVE_ENGINE))
|
2012-05-14 23:26:23 +02:00
|
|
|
fetchObject(objectId);
|
|
|
|
|
else
|
|
|
|
|
m_delayQueryTimer.start();
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-23 14:55:48 +02:00
|
|
|
void QmlInspectorAgent::onValueChanged(int debugId, const QByteArray &propertyName,
|
|
|
|
|
const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
const QByteArray iname = m_debugIdToIname.value(debugId) +
|
|
|
|
|
".[properties]." + propertyName;
|
2012-05-31 15:50:06 +02:00
|
|
|
WatchHandler *watchHandler = m_debuggerEngine->watchHandler();
|
|
|
|
|
const WatchData *data = watchHandler->findData(iname);
|
2012-05-23 14:55:48 +02:00
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << debugId << ')' << iname << value.toString();
|
2012-05-23 14:55:48 +02:00
|
|
|
if (data) {
|
|
|
|
|
WatchData d(*data);
|
|
|
|
|
d.value = value.toString();
|
2012-05-31 15:50:06 +02:00
|
|
|
watchHandler->insertData(d);
|
2012-05-23 14:55:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-18 14:20:54 +02:00
|
|
|
void QmlInspectorAgent::reloadEngines()
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "()";
|
|
|
|
|
|
|
|
|
|
if (!isConnected())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
log(LogSend, _("LIST_ENGINES"));
|
|
|
|
|
|
|
|
|
|
m_engineQueryId = m_engineClient->queryAvailableEngines();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-25 09:33:02 +02:00
|
|
|
int QmlInspectorAgent::parentIdForObject(int objectDebugId)
|
|
|
|
|
{
|
|
|
|
|
int pid = -1;
|
|
|
|
|
|
|
|
|
|
if (m_debugIdToIname.contains(objectDebugId)) {
|
|
|
|
|
QByteArray iname = m_debugIdToIname.value(objectDebugId);
|
|
|
|
|
if (iname.count('.') > 1) {
|
|
|
|
|
int offset = iname.lastIndexOf('.');
|
|
|
|
|
QTC_ASSERT(offset > 0, return pid);
|
|
|
|
|
iname = iname.left(offset);
|
|
|
|
|
pid = m_debugIdToIname.key(iname);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return pid;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
void QmlInspectorAgent::queryEngineContext()
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-05-14 23:26:23 +02:00
|
|
|
qDebug() << __FUNCTION__;
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return;
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QLatin1String("LIST_OBJECTS"));
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
m_rootContextQueryId
|
2012-05-14 23:26:23 +02:00
|
|
|
= m_engineClient->queryRootContexts(m_engine);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
void QmlInspectorAgent::fetchObject(int debugId)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << debugId << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
2012-05-14 23:26:23 +02:00
|
|
|
return;
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QLatin1String("FETCH_OBJECT ") + QString::number(debugId));
|
2012-05-14 23:26:23 +02:00
|
|
|
quint32 queryId = m_engineClient->queryObject(debugId);
|
2012-04-18 14:20:54 +02:00
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << debugId << ')'
|
2012-04-18 14:20:54 +02:00
|
|
|
<< " - query id" << queryId;
|
2012-05-14 23:26:23 +02:00
|
|
|
m_objectTreeQueryIds << queryId;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-10 17:06:29 +02:00
|
|
|
void QmlInspectorAgent::fetchContextObjectsForLocation(const QString &file,
|
|
|
|
|
int lineNumber, int columnNumber)
|
|
|
|
|
{
|
|
|
|
|
// This can be an expensive operation as it may return multiple
|
|
|
|
|
// objects. Use fetchContextObject() where possible.
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << file << ':' << lineNumber
|
|
|
|
|
<< ':' << columnNumber << ')';
|
2012-05-10 17:06:29 +02:00
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return;
|
|
|
|
|
|
2012-08-22 11:58:33 +02:00
|
|
|
log(LogSend, QString::fromLatin1("FETCH_OBJECTS_FOR_LOCATION %1:%2:%3").arg(file)
|
2012-05-10 17:06:29 +02:00
|
|
|
.arg(QString::number(lineNumber)).arg(QString::number(columnNumber)));
|
|
|
|
|
quint32 queryId = m_engineClient->queryObjectsForLocation(QFileInfo(file).fileName(),
|
|
|
|
|
lineNumber, columnNumber);
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << file << ':' << lineNumber
|
|
|
|
|
<< ':' << columnNumber << ')' << " - query id" << queryId;
|
2012-05-10 17:06:29 +02:00
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
m_objectTreeQueryIds << queryId;
|
2012-05-10 17:06:29 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-01 17:13:21 +02:00
|
|
|
void QmlInspectorAgent::updateObjectTree(const ContextReference &context)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << context << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
if (!isConnected()
|
|
|
|
|
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
|
|
|
|
return;
|
|
|
|
|
|
2012-10-01 17:13:21 +02:00
|
|
|
foreach (const ObjectReference & obj, context.objects())
|
|
|
|
|
insertObjectInTree(obj);
|
|
|
|
|
|
2012-05-10 10:29:11 +02:00
|
|
|
foreach (const ContextReference &child, context.contexts())
|
2012-10-01 17:13:21 +02:00
|
|
|
updateObjectTree(child);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-01 17:13:21 +02:00
|
|
|
void QmlInspectorAgent::insertObjectInTree(const ObjectReference &object)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << object << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
if (!object.isValid())
|
|
|
|
|
return;
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
m_objectStack.push(object);
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-29 22:21:04 +02:00
|
|
|
if (m_objectTreeQueryIds.count()) {
|
2012-04-18 14:20:54 +02:00
|
|
|
return;
|
2012-05-14 23:26:23 +02:00
|
|
|
}
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-29 22:21:04 +02:00
|
|
|
QElapsedTimer timeElapsed;
|
2012-05-14 23:26:23 +02:00
|
|
|
// sync tree with watchhandler
|
|
|
|
|
QList<WatchData> watchData;
|
|
|
|
|
ObjectReference last;
|
2012-05-29 22:21:04 +02:00
|
|
|
QStack<QmlDebug::ObjectReference> stack;
|
|
|
|
|
|
2012-09-28 14:40:57 +02:00
|
|
|
// qt <= 4.8.3
|
|
|
|
|
if (m_newObjectsCreated && m_engineClient->objectName() == QLatin1String(QDECLARATIVE_ENGINE)) {
|
2012-05-29 22:21:04 +02:00
|
|
|
// We need to reverse the stack as the root objects
|
|
|
|
|
// are pushed to the bottom since they are fetched first.
|
|
|
|
|
// The child objects need to placed in the correct position and therefore
|
|
|
|
|
// the m_debugIdChildIds needs to be populated first.
|
|
|
|
|
while (!m_objectStack.isEmpty())
|
|
|
|
|
stack.push(m_objectStack.pop());
|
2012-05-14 23:26:23 +02:00
|
|
|
} else {
|
2012-05-29 22:21:04 +02:00
|
|
|
stack = m_objectStack;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!stack.isEmpty()) {
|
|
|
|
|
last = stack.pop();
|
|
|
|
|
int parentId = last.parentId();
|
|
|
|
|
QByteArray parentIname;
|
|
|
|
|
|
2012-09-28 14:40:57 +02:00
|
|
|
// qt <= 4.8.3
|
|
|
|
|
if (m_engineClient->objectName() == QLatin1String(QDECLARATIVE_ENGINE)) {
|
2012-05-14 23:26:23 +02:00
|
|
|
QHashIterator<int, QList<int> > i(m_debugIdChildIds);
|
|
|
|
|
while (i.hasNext()) {
|
2012-05-29 22:21:04 +02:00
|
|
|
i.next();
|
|
|
|
|
if (i.value().contains(last.debugId())) {
|
|
|
|
|
parentId = i.key();
|
2012-05-14 23:26:23 +02:00
|
|
|
break;
|
2012-05-29 22:21:04 +02:00
|
|
|
}
|
2012-05-14 23:26:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-29 22:21:04 +02:00
|
|
|
if (m_debugIdToIname.contains(parentId))
|
|
|
|
|
parentIname = m_debugIdToIname.value(parentId);
|
|
|
|
|
if (!m_newObjectsCreated && parentId != -1 && parentIname.isEmpty()) {
|
|
|
|
|
fetchObject(parentId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-09-28 14:40:57 +02:00
|
|
|
// qt > 4.8.3
|
|
|
|
|
if (m_engineClient->objectName() != QLatin1String(QDECLARATIVE_ENGINE)
|
2012-06-05 16:38:34 +02:00
|
|
|
&& m_newObjectsCreated && parentIname.isEmpty()) {
|
2012-06-08 14:41:53 +02:00
|
|
|
if (watchData.count())
|
|
|
|
|
break;
|
2012-06-05 16:38:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 22:21:04 +02:00
|
|
|
if (debug)
|
|
|
|
|
timeElapsed.start();
|
|
|
|
|
watchData.append(buildWatchData(last, parentIname, true));
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "Time: Build Watch Data took "
|
|
|
|
|
<< timeElapsed.elapsed() << " ms";
|
|
|
|
|
if (debug)
|
|
|
|
|
timeElapsed.start();
|
|
|
|
|
buildDebugIdHashRecursive(last);
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "Time: Build Debug Id Hash took "
|
|
|
|
|
<< timeElapsed.elapsed() << " ms";
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
2012-05-29 22:21:04 +02:00
|
|
|
m_newObjectsCreated = false;
|
|
|
|
|
m_objectStack.clear();
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-31 15:50:06 +02:00
|
|
|
WatchHandler *watchHandler = m_debuggerEngine->watchHandler();
|
2012-05-29 22:21:04 +02:00
|
|
|
if (debug)
|
|
|
|
|
timeElapsed.start();
|
2012-05-31 15:50:06 +02:00
|
|
|
watchHandler->insertData(watchData);
|
2012-05-29 22:21:04 +02:00
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "Time: Insertion took " << timeElapsed.elapsed() << " ms";
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-05-29 22:21:04 +02:00
|
|
|
emit objectTreeUpdated();
|
|
|
|
|
emit objectFetched(last);
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-10-05 12:46:30 +02:00
|
|
|
if (m_objectToSelect == last.debugId() || m_debugIdToIname.keys().contains(m_objectToSelect)) {
|
2012-05-29 22:21:04 +02:00
|
|
|
// select item in view
|
2012-10-05 12:46:30 +02:00
|
|
|
QByteArray iname = m_debugIdToIname.value(m_objectToSelect);
|
2012-05-29 22:21:04 +02:00
|
|
|
if (debug)
|
|
|
|
|
qDebug() << " selecting" << iname << "in tree";
|
2012-05-31 15:50:06 +02:00
|
|
|
watchHandler->setCurrentItem(iname);
|
2012-05-29 22:21:04 +02:00
|
|
|
m_objectToSelect = -1;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-10 10:29:11 +02:00
|
|
|
void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << ref << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
QUrl fileUrl = ref.source().url();
|
|
|
|
|
int lineNum = ref.source().lineNumber();
|
|
|
|
|
int colNum = ref.source().columnNumber();
|
|
|
|
|
int rev = 0;
|
|
|
|
|
|
|
|
|
|
// handle the case where the url contains the revision number encoded.
|
|
|
|
|
//(for object created by the debugger)
|
2012-08-22 11:58:33 +02:00
|
|
|
static QRegExp rx(QLatin1String("(.*)_(\\d+):(\\d+)$"));
|
2012-04-18 14:20:54 +02:00
|
|
|
if (rx.exactMatch(fileUrl.path())) {
|
|
|
|
|
fileUrl.setPath(rx.cap(1));
|
|
|
|
|
rev = rx.cap(2).toInt();
|
|
|
|
|
lineNum += rx.cap(3).toInt() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QString filePath
|
2012-05-14 23:26:23 +02:00
|
|
|
= m_debuggerEngine->toFileInProject(fileUrl);
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
// append the debug ids in the hash
|
|
|
|
|
QPair<QString, int> file = qMakePair<QString, int>(filePath, rev);
|
|
|
|
|
QPair<int, int> location = qMakePair<int, int>(lineNum, colNum);
|
|
|
|
|
if (!m_debugIdHash[file][location].contains(ref.debugId()))
|
|
|
|
|
m_debugIdHash[file][location].append(ref.debugId());
|
2012-05-14 23:26:23 +02:00
|
|
|
m_debugIdLocations.insert(ref.debugId(), FileReference(filePath, lineNum, colNum));
|
2012-05-29 22:21:04 +02:00
|
|
|
|
2012-09-28 14:40:57 +02:00
|
|
|
// qt <= 4.8.3
|
2012-10-01 17:13:21 +02:00
|
|
|
if (m_newObjectsCreated
|
|
|
|
|
&& m_engineClient->objectName() == QLatin1String(QDECLARATIVE_ENGINE)) {
|
|
|
|
|
QList<int> childIds = m_debugIdChildIds.value(ref.debugId());
|
2012-05-29 22:21:04 +02:00
|
|
|
foreach (const ObjectReference &c, ref.children()) {
|
|
|
|
|
childIds << c.debugId();
|
|
|
|
|
}
|
2012-09-28 14:40:57 +02:00
|
|
|
// For qt <= 4.8.3, we do not get the parentId. Hence, store the child ids
|
2012-05-29 22:21:04 +02:00
|
|
|
// to look up correct insertion places later
|
|
|
|
|
m_debugIdChildIds.insert(ref.debugId(), childIds);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-10 10:29:11 +02:00
|
|
|
foreach (const ObjectReference &it, ref.children())
|
2012-04-18 14:20:54 +02:00
|
|
|
buildDebugIdHashRecursive(it);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
static QByteArray buildIName(const QByteArray &parentIname, int debugId)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
2012-05-14 23:26:23 +02:00
|
|
|
if (parentIname.isEmpty())
|
2012-04-18 14:20:54 +02:00
|
|
|
return "inspect." + QByteArray::number(debugId);
|
2012-05-14 23:26:23 +02:00
|
|
|
return parentIname + "." + QByteArray::number(debugId);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
static QByteArray buildIName(const QByteArray &parentIname, const QString &name)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
2012-05-14 23:26:23 +02:00
|
|
|
return parentIname + "." + name.toLatin1();
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-10 10:29:11 +02:00
|
|
|
QList<WatchData> QmlInspectorAgent::buildWatchData(const ObjectReference &obj,
|
2012-05-29 22:21:04 +02:00
|
|
|
const QByteArray &parentIname,
|
|
|
|
|
bool append)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
if (debug)
|
2012-08-22 11:58:33 +02:00
|
|
|
qDebug() << __FUNCTION__ << '(' << obj << parentIname << ')';
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
QList<WatchData> list;
|
|
|
|
|
|
2012-05-29 22:21:04 +02:00
|
|
|
int objDebugId = obj.debugId();
|
|
|
|
|
QByteArray objIname = buildIName(parentIname, objDebugId);
|
|
|
|
|
|
|
|
|
|
if (append) {
|
|
|
|
|
WatchData objWatch;
|
|
|
|
|
QString name = obj.idString();
|
|
|
|
|
if (name.isEmpty())
|
|
|
|
|
name = obj.className();
|
|
|
|
|
|
|
|
|
|
if (name.isEmpty())
|
|
|
|
|
return list;
|
|
|
|
|
|
|
|
|
|
// object
|
|
|
|
|
objWatch.id = objDebugId;
|
|
|
|
|
objWatch.exp = name.toLatin1();
|
|
|
|
|
objWatch.name = name;
|
|
|
|
|
objWatch.iname = objIname;
|
|
|
|
|
objWatch.type = obj.className().toLatin1();
|
|
|
|
|
objWatch.value = _("object");
|
|
|
|
|
objWatch.setHasChildren(true);
|
|
|
|
|
objWatch.setAllUnneeded();
|
|
|
|
|
|
|
|
|
|
list.append(objWatch);
|
|
|
|
|
addObjectWatch(objWatch.id);
|
2012-10-05 12:46:30 +02:00
|
|
|
m_debugIdToIname.insert(objDebugId, objIname);
|
2012-05-14 23:26:23 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-31 15:50:06 +02:00
|
|
|
if (!m_debuggerEngine->watchHandler()->isExpandedIName(objIname)) {
|
2012-05-11 14:00:17 +02:00
|
|
|
// we don't know the children yet. Not adding the 'properties'
|
|
|
|
|
// element makes sure we're queried on expansion.
|
2012-05-31 15:50:06 +02:00
|
|
|
if (obj.needsMoreData())
|
|
|
|
|
return list;
|
|
|
|
|
|
|
|
|
|
// To improve performance, we do not insert data for items
|
|
|
|
|
// that have not been previously queried when the object tree is refreshed.
|
|
|
|
|
if (m_newObjectsCreated)
|
|
|
|
|
append = false;
|
2012-05-11 14:00:17 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-18 14:20:54 +02:00
|
|
|
// properties
|
2012-05-29 22:21:04 +02:00
|
|
|
if (append && obj.properties().count()) {
|
2012-05-14 23:26:23 +02:00
|
|
|
WatchData propertiesWatch;
|
2012-05-29 22:21:04 +02:00
|
|
|
propertiesWatch.id = objDebugId;
|
2012-05-14 23:26:23 +02:00
|
|
|
propertiesWatch.exp = "";
|
2012-10-01 10:07:12 +02:00
|
|
|
propertiesWatch.name = tr("Properties");
|
2012-05-29 22:21:04 +02:00
|
|
|
propertiesWatch.iname = objIname + ".[properties]";
|
2012-05-14 23:26:23 +02:00
|
|
|
propertiesWatch.type = "";
|
|
|
|
|
propertiesWatch.value = _("list");
|
|
|
|
|
propertiesWatch.setHasChildren(true);
|
|
|
|
|
propertiesWatch.setAllUnneeded();
|
|
|
|
|
|
|
|
|
|
list.append(propertiesWatch);
|
|
|
|
|
|
|
|
|
|
foreach (const PropertyReference &property, obj.properties()) {
|
|
|
|
|
WatchData propertyWatch;
|
2012-05-29 22:21:04 +02:00
|
|
|
propertyWatch.id = objDebugId;
|
2012-05-14 23:26:23 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// recurse
|
2012-05-10 10:29:11 +02:00
|
|
|
foreach (const ObjectReference &child, obj.children())
|
2012-05-29 22:21:04 +02:00
|
|
|
list.append(buildWatchData(child, objIname, append));
|
2012-04-18 14:20:54 +02:00
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlInspectorAgent::log(QmlInspectorAgent::LogDirection direction,
|
|
|
|
|
const QString &message)
|
|
|
|
|
{
|
|
|
|
|
QString msg = _("Inspector");
|
|
|
|
|
if (direction == LogSend)
|
|
|
|
|
msg += _(" sending ");
|
|
|
|
|
else
|
|
|
|
|
msg += _(" receiving ");
|
|
|
|
|
msg += message;
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
if (m_debuggerEngine)
|
|
|
|
|
m_debuggerEngine->showMessage(msg, LogDebug);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
bool QmlInspectorAgent::isConnected() const
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
|
|
|
|
return m_engineClient
|
2012-05-10 10:29:11 +02:00
|
|
|
&& (m_engineClient->status() == QmlDebug::Enabled);
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-14 23:26:23 +02:00
|
|
|
void QmlInspectorAgent::clearObjectTree()
|
|
|
|
|
{
|
|
|
|
|
// clear view
|
2012-10-01 17:13:21 +02:00
|
|
|
m_debuggerEngine->watchHandler()->cleanup();
|
2012-05-14 23:26:23 +02:00
|
|
|
|
|
|
|
|
m_objectTreeQueryIds.clear();
|
2012-10-01 17:13:21 +02:00
|
|
|
m_fetchDataIds.clear();
|
2012-05-14 23:26:23 +02:00
|
|
|
int old_count = m_debugIdHash.count();
|
|
|
|
|
m_debugIdHash.clear();
|
|
|
|
|
m_debugIdHash.reserve(old_count + 1);
|
|
|
|
|
m_debugIdToIname.clear();
|
|
|
|
|
m_debugIdChildIds.clear();
|
|
|
|
|
m_objectStack.clear();
|
2012-09-28 14:40:57 +02:00
|
|
|
// reset only for qt > 4.8.3.
|
|
|
|
|
if (m_engineClient->objectName() != QLatin1String(QDECLARATIVE_ENGINE))
|
2012-06-08 13:13:54 +02:00
|
|
|
m_newObjectsCreated = false;
|
2012-05-23 14:55:48 +02:00
|
|
|
|
|
|
|
|
removeAllObjectWatches();
|
2012-05-14 23:26:23 +02:00
|
|
|
}
|
2012-04-18 14:20:54 +02:00
|
|
|
} // Internal
|
|
|
|
|
} // Debugger
|
2012-05-23 14:55:48 +02:00
|
|
|
|