Commit 05090515 authored by Olivier Goffart's avatar Olivier Goffart
Browse files

QML JS Debugger: Be able to expand objects

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