forked from qt-creator/qt-creator
QML JS Debugger: Be able to expand objects
This commit is contained in:
@@ -87,10 +87,11 @@ QDataStream& operator>>(QDataStream& s, WatchData &data)
|
||||
QString value;
|
||||
QString type;
|
||||
bool hasChildren;
|
||||
s >> data.exp >> data.name >> value >> type >> hasChildren;
|
||||
s >> data.exp >> data.name >> value >> type >> hasChildren >> data.objectId;
|
||||
data.setType(type, false);
|
||||
data.setValue(value);
|
||||
data.setHasChildren(hasChildren);
|
||||
data.setAllUnneeded();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -526,7 +527,7 @@ void QmlEngine::updateWatchData(const WatchData &data)
|
||||
//watchHandler()->rebuildModel();
|
||||
showStatusMessage(tr("Stopped."), 5000);
|
||||
|
||||
if (!data.name.isEmpty()) {
|
||||
if (!data.name.isEmpty() && data.isValueNeeded()) {
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("EXEC");
|
||||
@@ -534,6 +535,10 @@ void QmlEngine::updateWatchData(const WatchData &data)
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
if (!data.name.isEmpty() && data.isChildrenNeeded() && watchHandler()->isExpandedIName(data.iname)) {
|
||||
expandObject(data.iname, data.objectId);
|
||||
}
|
||||
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
@@ -543,6 +548,16 @@ void QmlEngine::updateWatchData(const WatchData &data)
|
||||
}
|
||||
}
|
||||
|
||||
void QmlEngine::expandObject(const QByteArray& iname, quint64 objectId)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("EXPAND");
|
||||
rs << iname << objectId;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
|
||||
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp)
|
||||
{
|
||||
return new QmlEngine(sp);
|
||||
@@ -599,11 +614,17 @@ void QmlEngine::messageReceived(const QByteArray &message)
|
||||
foreach (WatchData data, watches) {
|
||||
data.iname = watchHandler()->watcherName(data.exp);
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname))
|
||||
expandObject(data.iname, data.objectId);
|
||||
}
|
||||
|
||||
foreach (WatchData data, locals) {
|
||||
data.iname = "local." + data.exp;
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname))
|
||||
expandObject(data.iname, data.objectId);
|
||||
}
|
||||
|
||||
watchHandler()->endCycle();
|
||||
@@ -614,6 +635,18 @@ void QmlEngine::messageReceived(const QByteArray &message)
|
||||
stream >> iname >> data;
|
||||
data.iname = iname;
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
} else if (command == "EXPANDED") {
|
||||
QList<WatchData> result;
|
||||
QByteArray iname;
|
||||
stream >> iname >> result;
|
||||
foreach (WatchData data, result) {
|
||||
data.iname = iname + '.' + data.exp;
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname))
|
||||
expandObject(data.iname, data.objectId);
|
||||
}
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
|
||||
}
|
||||
|
||||
@@ -128,6 +128,8 @@ signals:
|
||||
void sendMessage(const QByteArray &msg);
|
||||
|
||||
private:
|
||||
void expandObject(const QByteArray &iname, quint64 objectId);
|
||||
|
||||
#if 0
|
||||
void createDockWidgets();
|
||||
bool connectToViewer(); // using host, port from widgets
|
||||
|
||||
@@ -25,6 +25,7 @@ WatchData::WatchData() :
|
||||
valueEditable(true),
|
||||
error(false),
|
||||
source(0),
|
||||
objectId(0),
|
||||
state(InitialState),
|
||||
changed(false)
|
||||
{
|
||||
|
||||
@@ -130,6 +130,7 @@ public:
|
||||
|
||||
public:
|
||||
int source; // Originated from dumper or symbol evaluation? (CDB only)
|
||||
quint64 objectId; // Object id used for the QMLEngine
|
||||
int state;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
@@ -52,13 +52,13 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
struct JSAgentWatchData {
|
||||
QByteArray exp;
|
||||
QString name;
|
||||
QString value;
|
||||
QString type;
|
||||
bool hasChildren;
|
||||
quint64 objectId;
|
||||
|
||||
static JSAgentWatchData fromScriptValue(const QString &expression, const QScriptValue &value)
|
||||
{
|
||||
@@ -67,6 +67,7 @@ struct JSAgentWatchData {
|
||||
data.name = expression;
|
||||
data.hasChildren = false;
|
||||
data.value = value.toString();
|
||||
data.objectId = value.objectId();
|
||||
if (value.isArray()) {
|
||||
data.type = QLatin1String("Array");
|
||||
data.value = QString::fromLatin1("[Array of length %1]").arg(value.property("length").toString());
|
||||
@@ -113,9 +114,24 @@ struct JSAgentWatchData {
|
||||
|
||||
QDataStream& operator<<(QDataStream& s, const JSAgentWatchData& data)
|
||||
{
|
||||
return s << data.exp << data.name << data.value << data.type << data.hasChildren;
|
||||
return s << data.exp << data.name << data.value << data.type << data.hasChildren << data.objectId;
|
||||
}
|
||||
|
||||
static QList<JSAgentWatchData> expandObject(const QScriptValue &object)
|
||||
{
|
||||
QList<JSAgentWatchData> result;
|
||||
QScriptValueIterator it(object);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
result << JSAgentWatchData::fromScriptValue(it.name(), it.value());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void JSDebuggerAgent::recordKnownObjects(const QList<JSAgentWatchData>& list)
|
||||
{
|
||||
foreach (const JSAgentWatchData &data, list)
|
||||
knownObjectIds << data.objectId;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +305,7 @@ void JSDebuggerAgent::messageReceived(const QByteArray& message)
|
||||
ds >> id >> expr;
|
||||
|
||||
JSAgentWatchData data = JSAgentWatchData::fromScriptValue(expr, engine()->evaluate(expr));
|
||||
knownObjectIds << data.objectId;
|
||||
// Clear any exceptions occurred during locals evaluation.
|
||||
engine()->clearExceptions();
|
||||
|
||||
@@ -297,6 +314,27 @@ void JSDebuggerAgent::messageReceived(const QByteArray& message)
|
||||
rs << QByteArray("RESULT") << id << data;
|
||||
sendMessage(reply);
|
||||
state = oldState;
|
||||
} else if (command == "EXPAND") {
|
||||
State oldState = state;
|
||||
state = Stopped;
|
||||
QByteArray requestId;
|
||||
quint64 objectId;
|
||||
ds >> requestId >> objectId;
|
||||
QScriptValue v;
|
||||
if (knownObjectIds.contains(objectId))
|
||||
v = engine()->objectById(objectId);
|
||||
|
||||
QList<JSAgentWatchData> result = expandObject(v);
|
||||
recordKnownObjects(result);
|
||||
|
||||
// Clear any exceptions occurred during locals evaluation.
|
||||
engine()->clearExceptions();
|
||||
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("EXPANDED") << requestId << result;
|
||||
sendMessage(reply);
|
||||
state = oldState;
|
||||
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown command" << command;
|
||||
@@ -307,6 +345,7 @@ void JSDebuggerAgent::messageReceived(const QByteArray& message)
|
||||
|
||||
void JSDebuggerAgent::stopped()
|
||||
{
|
||||
knownObjectIds.clear();
|
||||
state = Stopped;
|
||||
QList<QPair<QString, QPair<QString, qint32> > > backtrace;
|
||||
|
||||
@@ -335,17 +374,14 @@ void JSDebuggerAgent::stopped()
|
||||
backtrace.append(qMakePair(functionName, qMakePair( QUrl(info.fileName()).toLocalFile(), info.lineNumber() ) ) );
|
||||
}
|
||||
QList<JSAgentWatchData> watches;
|
||||
foreach (const QString &expr, watchExpressions) {
|
||||
foreach (const QString &expr, watchExpressions)
|
||||
watches << JSAgentWatchData::fromScriptValue(expr, engine()->evaluate(expr));
|
||||
}
|
||||
|
||||
QList<JSAgentWatchData> locals;
|
||||
QScriptValue activationObject = engine()->currentContext()->activationObject();
|
||||
QScriptValueIterator it(activationObject);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
locals << JSAgentWatchData::fromScriptValue(it.name(), it.value());
|
||||
}
|
||||
QList<JSAgentWatchData> locals = expandObject(activationObject);
|
||||
|
||||
recordKnownObjects(watches);
|
||||
recordKnownObjects(locals);
|
||||
|
||||
// Clear any exceptions occurred during locals evaluation.
|
||||
engine()->clearExceptions();
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class JSAgentWatchData;
|
||||
|
||||
class JSDebuggerAgent : public QDeclarativeDebugService , public QScriptEngineAgent
|
||||
{ Q_OBJECT
|
||||
public:
|
||||
@@ -100,6 +102,7 @@ public slots:
|
||||
// void pauses();
|
||||
|
||||
private:
|
||||
|
||||
enum State {
|
||||
NoState,
|
||||
SteppingIntoState,
|
||||
@@ -114,10 +117,14 @@ private:
|
||||
void continueExec();
|
||||
void stopped();
|
||||
|
||||
|
||||
void recordKnownObjects(const QList<JSAgentWatchData> &);
|
||||
|
||||
QEventLoop loop;
|
||||
QHash <qint64, QString> filenames;
|
||||
QSet< QPair<QString, qint32> > breakpointList;
|
||||
QStringList watchExpressions;
|
||||
QSet<qint64> knownObjectIds;
|
||||
|
||||
Q_DISABLE_COPY(JSDebuggerAgent)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user