2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2012-04-18 14:20:54 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
|
|
|
** Contact: http://www.qt-project.org/legal
|
2012-04-18 14:20:54 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2012-04-18 14:20:54 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2012-04-18 14:20:54 +02:00
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, 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, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2012-04-18 14:20:54 +02:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-04-18 14:20:54 +02:00
|
|
|
|
|
|
|
|
#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
|
|
|
{
|
2012-11-23 17:15:29 +01:00
|
|
|
m_debugIdToIname.insert(-1, QByteArray("inspect"));
|
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-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-11-23 13:35:44 +01:00
|
|
|
void QmlInspectorAgent::watchDataSelected(const WatchData *data)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << '(' << data->id << ')';
|
|
|
|
|
|
|
|
|
|
if (data->id) {
|
|
|
|
|
QTC_ASSERT(m_debugIdLocations.keys().contains(data->id), return);
|
2012-11-27 17:16:57 +01:00
|
|
|
emit jumpToObjectDefinition(m_debugIdLocations.value(data->id), data->id);
|
2012-11-23 13:35:44 +01: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)) {
|
2012-11-23 17:15:29 +01:00
|
|
|
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-11-23 17:15:29 +01:00
|
|
|
verifyAndInsertObjectInTree(qvariant_cast<ObjectReference>(var));
|
2012-05-10 17:06:29 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2012-11-23 17:15:29 +01:00
|
|
|
verifyAndInsertObjectInTree(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-10-11 16:49:45 +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
|
|
|
|
2012-10-11 16:49:45 +02:00
|
|
|
// TODO: FIX THIS for qt 5.x (Needs update in the qt side)
|
|
|
|
|
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())
|
2012-11-23 17:15:29 +01:00
|
|
|
verifyAndInsertObjectInTree(obj);
|
2012-10-01 17:13:21 +02:00
|
|
|
|
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-11-23 17:15:29 +01:00
|
|
|
void QmlInspectorAgent::verifyAndInsertObjectInTree(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-11-23 17:15:29 +01:00
|
|
|
// Find out the correct position in the tree
|
|
|
|
|
// Objects are inserted to the tree if they satisfy one of the two conditions.
|
|
|
|
|
// Condition 1: Object is a root object i.e. parentId == -1.
|
|
|
|
|
// Condition 2: Object has an expanded parent i.e. siblings are known.
|
|
|
|
|
// If the two conditions are not met then we push the object to a stack and recursively
|
|
|
|
|
// fetch parents till we find a previously expanded parent.
|
|
|
|
|
|
|
|
|
|
WatchHandler *handler = m_debuggerEngine->watchHandler();
|
|
|
|
|
const int parentId = object.parentId();
|
|
|
|
|
const int objectDebugId = object.debugId();
|
|
|
|
|
if (m_debugIdToIname.contains(parentId)) {
|
|
|
|
|
QByteArray parentIname = m_debugIdToIname.value(parentId);
|
|
|
|
|
if (parentId != -1 && !handler->isExpandedIName(parentIname)) {
|
|
|
|
|
m_objectStack.push(object);
|
|
|
|
|
handler->model()->fetchMore(handler->watchDataIndex(parentIname));
|
|
|
|
|
return; // recursive
|
|
|
|
|
}
|
|
|
|
|
insertObjectInTree(object);
|
2012-05-29 22:21:04 +02:00
|
|
|
|
2012-11-23 17:15:29 +01:00
|
|
|
} else {
|
|
|
|
|
m_objectStack.push(object);
|
|
|
|
|
fetchObject(parentId);
|
|
|
|
|
return; // recursive
|
|
|
|
|
}
|
|
|
|
|
if (!m_objectStack.isEmpty()) {
|
|
|
|
|
const ObjectReference &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)) {
|
|
|
|
|
QByteArray objectIname = m_debugIdToIname.value(objectDebugId);
|
|
|
|
|
if (!handler->isExpandedIName(objectIname)) {
|
|
|
|
|
handler->model()->fetchMore(handler->watchDataIndex(objectIname));
|
|
|
|
|
} else {
|
|
|
|
|
verifyAndInsertObjectInTree(m_objectStack.pop());
|
|
|
|
|
return; // recursive
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmlInspectorAgent::insertObjectInTree(const ObjectReference &object)
|
|
|
|
|
{
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << '(' << object << ')';
|
2012-05-29 22:21:04 +02:00
|
|
|
|
2012-11-23 17:15:29 +01:00
|
|
|
const int objectDebugId = object.debugId();
|
|
|
|
|
const int parentId = parentIdForIname(m_debugIdToIname.value(objectDebugId));
|
2012-06-05 16:38:34 +02:00
|
|
|
|
2012-11-23 17:15:29 +01:00
|
|
|
QElapsedTimer timeElapsed;
|
|
|
|
|
QList<WatchData> watchData;
|
2012-10-11 16:49:45 +02:00
|
|
|
if (debug)
|
|
|
|
|
timeElapsed.start();
|
|
|
|
|
watchData.append(buildWatchData(object, m_debugIdToIname.value(parentId), true));
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "Time: Build Watch Data took "
|
|
|
|
|
<< timeElapsed.elapsed() << " ms";
|
|
|
|
|
if (debug)
|
|
|
|
|
timeElapsed.start();
|
|
|
|
|
buildDebugIdHashRecursive(object);
|
|
|
|
|
if (debug)
|
|
|
|
|
qDebug() << __FUNCTION__ << "Time: Build Debug Id Hash took "
|
|
|
|
|
<< timeElapsed.elapsed() << " ms";
|
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();
|
2012-10-11 16:49:45 +02:00
|
|
|
emit objectFetched(object);
|
2012-04-18 14:20:54 +02:00
|
|
|
|
2012-10-11 16:49:45 +02:00
|
|
|
if (m_debugIdToIname.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-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-11 16:49:45 +02:00
|
|
|
if (m_debugIdToIname.contains(objDebugId)) {
|
|
|
|
|
// The data needs to be removed since we now know the parent and
|
|
|
|
|
// hence we can insert the data in the correct position
|
|
|
|
|
const QByteArray oldIname = m_debugIdToIname.value(objDebugId);
|
|
|
|
|
if (oldIname != objIname)
|
|
|
|
|
m_debuggerEngine->watchHandler()->removeData(oldIname);
|
|
|
|
|
}
|
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()
|
|
|
|
|
{
|
2012-10-11 16:49:45 +02:00
|
|
|
m_debuggerEngine->watchHandler()->removeAllData(true);
|
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();
|
2012-11-23 17:15:29 +01:00
|
|
|
m_debugIdToIname.insert(-1, QByteArray("inspect"));
|
2012-05-14 23:26:23 +02:00
|
|
|
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
|
|
|
|