forked from qt-creator/qt-creator
Delegate javascript debugging to Script and V8 debugger clients.
The appropriate client handles the debugging based on the service available at the server side. Change-Id: I46b66036f700fc7e45e8b38cef7f1ce1445b1122 Reviewed-on: http://codereview.qt.nokia.com/2497 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
@@ -88,7 +88,7 @@ public:
|
||||
|
||||
Status status() const;
|
||||
|
||||
void sendMessage(const QByteArray &);
|
||||
virtual void sendMessage(const QByteArray &);
|
||||
|
||||
protected:
|
||||
virtual void statusChanged(Status);
|
||||
|
||||
@@ -1349,7 +1349,7 @@ void CodaGdbAdapter::handleReadRegisters(const CodaCommandResult &result)
|
||||
logMessage("ERROR: " + result.errorString(), LogError);
|
||||
return;
|
||||
}
|
||||
if (result.values.isEmpty() || result.values.front().type() != JsonValue::String) {
|
||||
if (result.values.isEmpty() || result.values.front().type() != Json::JsonValue::String) {
|
||||
logMessage(_("Format error in register message: ") + result.toString(),
|
||||
LogError);
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)
|
||||
include($$PWD/../../../shared/json/json.pri)
|
||||
DEFINES += JSON_INCLUDE_PRI
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/qmlengine.h \
|
||||
@@ -6,10 +8,15 @@ HEADERS += \
|
||||
$$PWD/qmldebuggerclient.h \
|
||||
$$PWD/qmljsprivateapi.h \
|
||||
$$PWD/qmlcppengine.h \
|
||||
$$PWD/scriptconsole.h
|
||||
$$PWD/scriptconsole.h \
|
||||
$$PWD/qscriptdebuggerclient.h \
|
||||
$$PWD/qmlv8debuggerclient.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmlengine.cpp \
|
||||
$$PWD/qmladapter.cpp \
|
||||
$$PWD/qmldebuggerclient.cpp \
|
||||
$$PWD/qmlcppengine.cpp \
|
||||
$$PWD/scriptconsole.cpp
|
||||
$$PWD/scriptconsole.cpp \
|
||||
$$PWD/qscriptdebuggerclient.cpp \
|
||||
$$PWD/qmlv8debuggerclient.cpp
|
||||
|
||||
@@ -33,10 +33,11 @@
|
||||
#include "qmladapter.h"
|
||||
|
||||
#include "debuggerstartparameters.h"
|
||||
#include "qmldebuggerclient.h"
|
||||
#include "qscriptdebuggerclient.h"
|
||||
#include "qmlv8debuggerclient.h"
|
||||
#include "qmljsprivateapi.h"
|
||||
|
||||
#include "debuggerengine.h"
|
||||
#include "qmlengine.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -61,13 +62,13 @@ public:
|
||||
}
|
||||
|
||||
QWeakPointer<DebuggerEngine> m_engine;
|
||||
Internal::QmlDebuggerClient *m_qmlClient;
|
||||
QmlDebuggerClient *m_qmlClient;
|
||||
|
||||
QTimer m_connectionTimer;
|
||||
int m_connectionAttempts;
|
||||
int m_maxConnectionAttempts;
|
||||
QDeclarativeDebugConnection *m_conn;
|
||||
QList<QByteArray> sendBuffer;
|
||||
QHash<QString, QmlDebuggerClient*> debugClients;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
@@ -149,16 +150,6 @@ void QmlAdapter::connectToViewer()
|
||||
}
|
||||
}
|
||||
|
||||
void QmlAdapter::sendMessage(const QByteArray &msg)
|
||||
{
|
||||
if (d->m_qmlClient->status() == QDeclarativeDebugClient::Enabled) {
|
||||
flushSendBuffer();
|
||||
d->m_qmlClient->sendMessage(msg);
|
||||
} else {
|
||||
d->sendBuffer.append(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
|
||||
@@ -177,8 +168,10 @@ void QmlAdapter::clientStatusChanged(QDeclarativeDebugClient::Status status)
|
||||
|
||||
logServiceStatusChange(serviceName, status);
|
||||
|
||||
if (status == QDeclarativeDebugClient::Enabled)
|
||||
flushSendBuffer();
|
||||
if (status == QDeclarativeDebugClient::Enabled) {
|
||||
d->m_qmlClient = d->debugClients.value(serviceName);
|
||||
d->m_qmlClient->flushSendBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlAdapter::connectionStateChanged()
|
||||
@@ -202,7 +195,8 @@ void QmlAdapter::connectionStateChanged()
|
||||
showConnectionStatusMessage(tr("connected.\n"));
|
||||
|
||||
if (!d->m_qmlClient)
|
||||
createDebuggerClient();
|
||||
createDebuggerClients();
|
||||
|
||||
//reloadEngines();
|
||||
emit connected();
|
||||
break;
|
||||
@@ -216,16 +210,23 @@ void QmlAdapter::connectionStateChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void QmlAdapter::createDebuggerClient()
|
||||
void QmlAdapter::createDebuggerClients()
|
||||
{
|
||||
d->m_qmlClient = new Internal::QmlDebuggerClient(d->m_conn);
|
||||
|
||||
connect(d->m_qmlClient, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
|
||||
Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn);
|
||||
connect(client1, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
|
||||
connect(d->m_engine.data(), SIGNAL(sendMessage(QByteArray)),
|
||||
this, SLOT(sendMessage(QByteArray)));
|
||||
connect(d->m_qmlClient, SIGNAL(messageWasReceived(QByteArray)),
|
||||
d->m_engine.data(), SLOT(messageReceived(QByteArray)));
|
||||
|
||||
Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
|
||||
connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
|
||||
|
||||
d->debugClients.insert(client1->name(),client1);
|
||||
d->debugClients.insert(client2->name(),client2);
|
||||
|
||||
|
||||
client1->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
|
||||
client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
|
||||
|
||||
//engine->startSuccessful(); // FIXME: AAA: port to new debugger states
|
||||
}
|
||||
@@ -243,13 +244,13 @@ QDeclarativeDebugConnection *QmlAdapter::connection() const
|
||||
void QmlAdapter::showConnectionStatusMessage(const QString &message)
|
||||
{
|
||||
if (!d->m_engine.isNull())
|
||||
d->m_engine.data()->showMessage(QLatin1String("QmlJSDebugger: ") + message, LogStatus);
|
||||
d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogStatus);
|
||||
}
|
||||
|
||||
void QmlAdapter::showConnectionErrorMessage(const QString &message)
|
||||
{
|
||||
if (!d->m_engine.isNull())
|
||||
d->m_engine.data()->showMessage(QLatin1String("QmlJSDebugger: ") + message, LogError);
|
||||
d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogError);
|
||||
}
|
||||
|
||||
bool QmlAdapter::disableJsDebugging(bool block)
|
||||
@@ -271,6 +272,15 @@ bool QmlAdapter::disableJsDebugging(bool block)
|
||||
return isBlocked;
|
||||
}
|
||||
|
||||
Internal::QmlDebuggerClient *QmlAdapter::activeDebuggerClient()
|
||||
{
|
||||
return d->m_qmlClient;
|
||||
}
|
||||
|
||||
QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
|
||||
{
|
||||
return d->debugClients;
|
||||
}
|
||||
void QmlAdapter::logServiceStatusChange(const QString &service,
|
||||
QDeclarativeDebugClient::Status newStatus)
|
||||
{
|
||||
@@ -298,12 +308,4 @@ void QmlAdapter::logServiceActivity(const QString &service, const QString &logMe
|
||||
d->m_engine.data()->showMessage(QString("%1 %2").arg(service, logMessage), LogDebug);
|
||||
}
|
||||
|
||||
void QmlAdapter::flushSendBuffer()
|
||||
{
|
||||
QTC_ASSERT(d->m_qmlClient->status() == QDeclarativeDebugClient::Enabled, return);
|
||||
foreach (const QByteArray &msg, d->sendBuffer)
|
||||
d->m_qmlClient->sendMessage(msg);
|
||||
d->sendBuffer.clear();
|
||||
}
|
||||
|
||||
} // namespace Debugger
|
||||
|
||||
@@ -70,6 +70,9 @@ public:
|
||||
|
||||
bool disableJsDebugging(bool block);
|
||||
|
||||
Internal::QmlDebuggerClient *activeDebuggerClient();
|
||||
QHash<QString, Internal::QmlDebuggerClient*> debuggerClients();
|
||||
|
||||
public slots:
|
||||
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
|
||||
void logServiceActivity(const QString &service, const QString &logMessage);
|
||||
@@ -82,7 +85,6 @@ signals:
|
||||
void serviceConnectionError(const QString serviceName);
|
||||
|
||||
private slots:
|
||||
void sendMessage(const QByteArray &msg);
|
||||
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||
void clientStatusChanged(QDeclarativeDebugClient::Status status);
|
||||
void connectionStateChanged();
|
||||
@@ -90,10 +92,9 @@ private slots:
|
||||
|
||||
private:
|
||||
void connectToViewer();
|
||||
void createDebuggerClient();
|
||||
void createDebuggerClients();
|
||||
void showConnectionStatusMessage(const QString &message);
|
||||
void showConnectionErrorMessage(const QString &message);
|
||||
void flushSendBuffer();
|
||||
|
||||
private:
|
||||
QScopedPointer<Internal::QmlAdapterPrivate> d;
|
||||
|
||||
@@ -37,13 +37,21 @@
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
QmlDebuggerClient::QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client)
|
||||
: QDeclarativeDebugClient(QLatin1String("JSDebugger"), client)
|
||||
class QmlDebuggerClientPrivate
|
||||
{
|
||||
public:
|
||||
QList<QByteArray> sendBuffer;
|
||||
};
|
||||
|
||||
QmlDebuggerClient::QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client, QLatin1String clientName)
|
||||
: QDeclarativeDebugClient(clientName, client),
|
||||
d(new QmlDebuggerClientPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
QmlDebuggerClient::~QmlDebuggerClient()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlDebuggerClient::statusChanged(Status status)
|
||||
@@ -51,9 +59,21 @@ void QmlDebuggerClient::statusChanged(Status status)
|
||||
emit newStatus(status);
|
||||
}
|
||||
|
||||
void QmlDebuggerClient::messageReceived(const QByteArray &data)
|
||||
void QmlDebuggerClient::sendMessage(const QByteArray &msg)
|
||||
{
|
||||
emit messageWasReceived(data);
|
||||
if (status() == Enabled) {
|
||||
QDeclarativeDebugClient::sendMessage(msg);
|
||||
} else {
|
||||
d->sendBuffer.append(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlDebuggerClient::flushSendBuffer()
|
||||
{
|
||||
QTC_ASSERT(status() == QDeclarativeDebugClient::Enabled, return);
|
||||
foreach (const QByteArray &msg, d->sendBuffer)
|
||||
QDeclarativeDebugClient::sendMessage(msg);
|
||||
d->sendBuffer.clear();
|
||||
}
|
||||
|
||||
} // Internal
|
||||
|
||||
@@ -30,32 +30,70 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSDEBUGGERCLIENT_H
|
||||
#define QMLJSDEBUGGERCLIENT_H
|
||||
#ifndef QMLDEBUGGERCLIENT_H
|
||||
#define QMLDEBUGGERCLIENT_H
|
||||
|
||||
#include "qmljsprivateapi.h"
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class WatchData;
|
||||
class BreakHandler;
|
||||
class BreakpointModelId;
|
||||
class QmlEngine;
|
||||
class QmlDebuggerClientPrivate;
|
||||
|
||||
class QmlDebuggerClient : public QDeclarativeDebugClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client);
|
||||
QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client, QLatin1String clientName);
|
||||
virtual ~QmlDebuggerClient();
|
||||
|
||||
virtual void executeStep() = 0;
|
||||
virtual void executeStepOut() = 0;
|
||||
virtual void executeNext() = 0;
|
||||
virtual void executeStepI() = 0;
|
||||
|
||||
virtual void continueInferior() = 0;
|
||||
virtual void interruptInferior() = 0;
|
||||
|
||||
virtual void activateFrame(int index) = 0;
|
||||
|
||||
virtual void insertBreakpoints(BreakHandler *handler, BreakpointModelId *id) = 0;
|
||||
virtual void removeBreakpoints(BreakpointModelId *id) = 0;
|
||||
virtual void setBreakpoints() = 0;
|
||||
|
||||
virtual void assignValueInDebugger(const QByteArray expr, const quint64 &id,
|
||||
const QString &property, const QString value) = 0;
|
||||
|
||||
virtual void updateWatchData(const WatchData *data) = 0;
|
||||
virtual void executeDebuggerCommand(const QString &command) = 0;
|
||||
|
||||
virtual void synchronizeWatchers(const QStringList &watchers) = 0;
|
||||
|
||||
virtual void expandObject(const QByteArray &iname, quint64 objectId) = 0;
|
||||
virtual void sendPing() = 0;
|
||||
|
||||
virtual void setEngine(QmlEngine *engine) = 0;
|
||||
|
||||
void flushSendBuffer();
|
||||
|
||||
signals:
|
||||
void newStatus(QDeclarativeDebugClient::Status status);
|
||||
void messageWasReceived(const QByteArray &data);
|
||||
|
||||
protected:
|
||||
virtual void statusChanged(Status status);
|
||||
virtual void messageReceived(const QByteArray &data);
|
||||
void sendMessage(const QByteArray &msg);
|
||||
|
||||
private:
|
||||
QmlDebuggerClientPrivate *d;
|
||||
friend class QmlDebuggerClientPrivate;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSInspector
|
||||
} // Debugger
|
||||
|
||||
#endif // QMLJSDEBUGGERCLIENT_H
|
||||
#endif // QMLDEBUGGERCLIENT_H
|
||||
|
||||
@@ -89,70 +89,6 @@ using namespace ProjectExplorer;
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
struct JSAgentBreakpointData
|
||||
{
|
||||
QByteArray functionName;
|
||||
QByteArray fileUrl;
|
||||
qint32 lineNumber;
|
||||
};
|
||||
|
||||
struct JSAgentStackData
|
||||
{
|
||||
QByteArray functionName;
|
||||
QByteArray fileUrl;
|
||||
qint32 lineNumber;
|
||||
};
|
||||
|
||||
uint qHash(const JSAgentBreakpointData &b)
|
||||
{
|
||||
return b.lineNumber ^ qHash(b.fileUrl);
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
|
||||
{
|
||||
return s << data.functionName << data.fileUrl << data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
|
||||
{
|
||||
return s << data.functionName << data.fileUrl << data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
|
||||
{
|
||||
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &s, JSAgentStackData &data)
|
||||
{
|
||||
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
|
||||
}
|
||||
|
||||
bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
|
||||
{
|
||||
return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl;
|
||||
}
|
||||
|
||||
typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
|
||||
typedef QList<JSAgentStackData> JSAgentStackFrames;
|
||||
|
||||
|
||||
static QDataStream &operator>>(QDataStream &s, WatchData &data)
|
||||
{
|
||||
data = WatchData();
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
QByteArray type;
|
||||
bool hasChildren = false;
|
||||
s >> data.exp >> name >> value >> type >> hasChildren >> data.id;
|
||||
data.name = QString::fromUtf8(name);
|
||||
data.setType(type, false);
|
||||
data.setValue(QString::fromUtf8(value));
|
||||
data.setHasChildren(hasChildren);
|
||||
data.setAllUnneeded();
|
||||
return s;
|
||||
}
|
||||
|
||||
class QmlEnginePrivate
|
||||
{
|
||||
public:
|
||||
@@ -160,7 +96,6 @@ public:
|
||||
|
||||
private:
|
||||
friend class QmlEngine;
|
||||
int m_ping;
|
||||
QmlAdapter m_adapter;
|
||||
ApplicationLauncher m_applicationLauncher;
|
||||
Utils::FileInProjectFinder fileFinder;
|
||||
@@ -168,7 +103,7 @@ private:
|
||||
};
|
||||
|
||||
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
||||
: m_ping(0), m_adapter(q)
|
||||
: m_adapter(q)
|
||||
{}
|
||||
|
||||
|
||||
@@ -466,8 +401,6 @@ void QmlEngine::shutdownEngine()
|
||||
|
||||
void QmlEngine::setupEngine()
|
||||
{
|
||||
d->m_ping = 0;
|
||||
|
||||
connect(&d->m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
|
||||
runControl(), SLOT(bringApplicationToForeground(qint64)),
|
||||
Qt::UniqueConnection);
|
||||
@@ -478,12 +411,8 @@ void QmlEngine::setupEngine()
|
||||
void QmlEngine::continueInferior()
|
||||
{
|
||||
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "CONTINUE";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, "CONTINUE");
|
||||
d->m_adapter.activeDebuggerClient()->continueInferior();
|
||||
resetLocation();
|
||||
notifyInferiorRunRequested();
|
||||
notifyInferiorRunOk();
|
||||
@@ -491,23 +420,15 @@ void QmlEngine::continueInferior()
|
||||
|
||||
void QmlEngine::interruptInferior()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "INTERRUPT";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
notifyInferiorStopOk();
|
||||
logMessage(LogSend, "INTERRUPT");
|
||||
d->m_adapter.activeDebuggerClient()->interruptInferior();
|
||||
|
||||
}
|
||||
|
||||
void QmlEngine::executeStep()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPINTO";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, "STEPINTO");
|
||||
d->m_adapter.activeDebuggerClient()->executeStep();
|
||||
resetLocation();
|
||||
notifyInferiorRunRequested();
|
||||
notifyInferiorRunOk();
|
||||
@@ -515,12 +436,8 @@ void QmlEngine::executeStep()
|
||||
|
||||
void QmlEngine::executeStepI()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPINTO";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, "STEPINTO");
|
||||
d->m_adapter.activeDebuggerClient()->executeStepI();
|
||||
resetLocation();
|
||||
notifyInferiorRunRequested();
|
||||
notifyInferiorRunOk();
|
||||
@@ -528,12 +445,8 @@ void QmlEngine::executeStepI()
|
||||
|
||||
void QmlEngine::executeStepOut()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPOUT";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, "STEPOUT");
|
||||
d->m_adapter.activeDebuggerClient()->executeStepOut();
|
||||
resetLocation();
|
||||
notifyInferiorRunRequested();
|
||||
notifyInferiorRunOk();
|
||||
@@ -541,12 +454,8 @@ void QmlEngine::executeStepOut()
|
||||
|
||||
void QmlEngine::executeNext()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPOVER";
|
||||
rs << cmd;
|
||||
logMessage(LogSend, cmd);
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, "STEPOVER");
|
||||
d->m_adapter.activeDebuggerClient()->executeNext();
|
||||
resetLocation();
|
||||
notifyInferiorRunRequested();
|
||||
notifyInferiorRunOk();
|
||||
@@ -577,13 +486,8 @@ void QmlEngine::executeJumpToLine(const ContextData &data)
|
||||
|
||||
void QmlEngine::activateFrame(int index)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "ACTIVATE_FRAME";
|
||||
rs << cmd
|
||||
<< index;
|
||||
logMessage(LogSend, QString("%1 %2").arg(QString(cmd), QString::number(index)));
|
||||
sendMessage(reply);
|
||||
logMessage(LogSend, QString("%1 %2").arg(QString("ACTIVATE_FRAME"), QString::number(index)));
|
||||
d->m_adapter.activeDebuggerClient()->activateFrame(index);
|
||||
gotoLocation(stackHandler()->frames().value(index));
|
||||
}
|
||||
|
||||
@@ -602,40 +506,46 @@ void QmlEngine::attemptBreakpointSynchronization()
|
||||
handler->setEngine(id, this);
|
||||
}
|
||||
|
||||
JSAgentBreakpoints breakpoints;
|
||||
QStringList breakPointsStr;
|
||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
||||
if (handler->state(id) == BreakpointRemoveRequested) {
|
||||
handler->notifyBreakpointRemoveProceeding(id);
|
||||
if (d->m_adapter.activeDebuggerClient())
|
||||
d->m_adapter.activeDebuggerClient()->removeBreakpoints(&id);
|
||||
else {
|
||||
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) {
|
||||
client->removeBreakpoints(&id);
|
||||
}
|
||||
}
|
||||
handler->notifyBreakpointRemoveOk(id);
|
||||
} else {
|
||||
if (handler->state(id) == BreakpointInsertRequested) {
|
||||
handler->notifyBreakpointInsertProceeding(id);
|
||||
}
|
||||
JSAgentBreakpointData bp;
|
||||
bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8();
|
||||
bp.lineNumber = handler->lineNumber(id);
|
||||
bp.functionName = handler->functionName(id).toUtf8();
|
||||
breakpoints.insert(bp);
|
||||
if (d->m_adapter.activeDebuggerClient())
|
||||
d->m_adapter.activeDebuggerClient()->insertBreakpoints(handler,&id);
|
||||
else {
|
||||
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) {
|
||||
client->insertBreakpoints(handler,&id);
|
||||
}
|
||||
}
|
||||
if (handler->state(id) == BreakpointInsertProceeding) {
|
||||
handler->notifyBreakpointInsertOk(id);
|
||||
}
|
||||
breakPointsStr << QString("('%1' '%2' %3)").arg(QString(handler->functionName(id).toUtf8()),
|
||||
QString(QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8()), QString::number(handler->lineNumber(id)));
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "BREAKPOINTS";
|
||||
rs << cmd
|
||||
<< breakpoints;
|
||||
logMessage(LogSend, QString("%1 [%2]").arg(QString("BREAKPOINTS"), breakPointsStr.join(", ")));
|
||||
|
||||
QStringList breakPointsStr;
|
||||
foreach (const JSAgentBreakpointData &bp, breakpoints) {
|
||||
breakPointsStr << QString("('%1' '%2' %3)").arg(QString(bp.functionName),
|
||||
QString(bp.fileUrl), QString::number(bp.lineNumber));
|
||||
if (d->m_adapter.activeDebuggerClient()) {
|
||||
d->m_adapter.activeDebuggerClient()->setBreakpoints();
|
||||
}
|
||||
else {
|
||||
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients())
|
||||
client->setBreakpoints();
|
||||
}
|
||||
logMessage(LogSend, QString("%1 [%2]").arg(QString(cmd), breakPointsStr.join(", ")));
|
||||
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
bool QmlEngine::acceptsBreakpoint(BreakpointModelId id) const
|
||||
@@ -682,25 +592,15 @@ bool QmlEngine::setToolTipExpression(const QPoint &mousePos,
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void QmlEngine::assignValueInDebugger(const WatchData *,
|
||||
void QmlEngine::assignValueInDebugger(const WatchData *data,
|
||||
const QString &expression, const QVariant &valueV)
|
||||
{
|
||||
QRegExp inObject("@([0-9a-fA-F]+)->(.+)");
|
||||
if (inObject.exactMatch(expression)) {
|
||||
bool ok = false;
|
||||
quint64 objectId = inObject.cap(1).toULongLong(&ok, 16);
|
||||
QString property = inObject.cap(2);
|
||||
if (ok && objectId > 0 && !property.isEmpty()) {
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "SET_PROPERTY";
|
||||
rs << cmd;
|
||||
rs << expression.toUtf8() << objectId << property << valueV.toString();
|
||||
quint64 objectId = data->id;
|
||||
if (objectId > 0 && !expression.isEmpty()) {
|
||||
logMessage(LogSend, QString("%1 %2 %3 %4 %5").arg(
|
||||
QString(cmd), QString::number(objectId), QString(property),
|
||||
QString("SET_PROPERTY"), QString::number(objectId), QString(expression),
|
||||
valueV.toString()));
|
||||
sendMessage(reply);
|
||||
}
|
||||
d->m_adapter.activeDebuggerClient()->assignValueInDebugger(expression.toUtf8(), objectId, expression, valueV.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,19 +612,14 @@ void QmlEngine::updateWatchData(const WatchData &data,
|
||||
showStatusMessage(tr("Stopped."), 5000);
|
||||
|
||||
if (!data.name.isEmpty() && data.isValueNeeded()) {
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXEC";
|
||||
rs << cmd;
|
||||
rs << data.iname << data.name;
|
||||
logMessage(LogSend, QString("%1 %2 %3").arg(QString(cmd), QString(data.iname),
|
||||
logMessage(LogSend, QString("%1 %2 %3").arg(QString("EXEC"), QString(data.iname),
|
||||
QString(data.name)));
|
||||
sendMessage(reply);
|
||||
d->m_adapter.activeDebuggerClient()->updateWatchData(&data);
|
||||
}
|
||||
|
||||
if (!data.name.isEmpty() && data.isChildrenNeeded()
|
||||
&& watchHandler()->isExpandedIName(data.iname)) {
|
||||
expandObject(data.iname, data.id);
|
||||
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id);
|
||||
}
|
||||
|
||||
synchronizeWatchers();
|
||||
@@ -735,39 +630,17 @@ void QmlEngine::updateWatchData(const WatchData &data,
|
||||
|
||||
void QmlEngine::synchronizeWatchers()
|
||||
{
|
||||
QStringList watchedExpressions = watchHandler()->watchedExpressions();
|
||||
// send watchers list
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "WATCH_EXPRESSIONS";
|
||||
rs << cmd;
|
||||
rs << watchHandler()->watchedExpressions();
|
||||
logMessage(LogSend, QString("%1 %2").arg(
|
||||
QString(cmd), watchHandler()->watchedExpressions().join(", ")));
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QmlEngine::expandObject(const QByteArray &iname, quint64 objectId)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXPAND";
|
||||
rs << cmd;
|
||||
rs << iname << objectId;
|
||||
logMessage(LogSend, QString("%1 %2 %3").arg(QString(cmd), QString(iname),
|
||||
QString::number(objectId)));
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QmlEngine::sendPing()
|
||||
{
|
||||
d->m_ping++;
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "PING";
|
||||
rs << cmd;
|
||||
rs << d->m_ping;
|
||||
logMessage(LogSend, QString("%1 %2").arg(QString(cmd), QString::number(d->m_ping)));
|
||||
sendMessage(reply);
|
||||
QString("WATCH_EXPRESSIONS"), watchedExpressions.join(", ")));
|
||||
if (d->m_adapter.activeDebuggerClient()) {
|
||||
d->m_adapter.activeDebuggerClient()->synchronizeWatchers(watchedExpressions);
|
||||
}
|
||||
else {
|
||||
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients())
|
||||
client->synchronizeWatchers(watchedExpressions);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned QmlEngine::debuggerCapabilities() const
|
||||
@@ -794,209 +667,12 @@ QString QmlEngine::toFileInProject(const QUrl &fileUrl)
|
||||
return d->fileFinder.findFile(fileUrl);
|
||||
}
|
||||
|
||||
void QmlEngine::messageReceived(const QByteArray &message)
|
||||
void QmlEngine::inferiorSpontaneousStop()
|
||||
{
|
||||
QByteArray rwData = message;
|
||||
QDataStream stream(&rwData, QIODevice::ReadOnly);
|
||||
|
||||
QByteArray command;
|
||||
stream >> command;
|
||||
|
||||
if (command == "STOPPED") {
|
||||
//qDebug() << command << this << state();
|
||||
if (state() == InferiorRunOk)
|
||||
notifyInferiorSpontaneousStop();
|
||||
|
||||
QString logString = QString::fromLatin1(command);
|
||||
|
||||
JSAgentStackFrames stackFrames;
|
||||
QList<WatchData> watches;
|
||||
QList<WatchData> locals;
|
||||
stream >> stackFrames >> watches >> locals;
|
||||
|
||||
logString += QString::fromLatin1(" (%1 stack frames) (%2 watches) (%3 locals)").
|
||||
arg(stackFrames.size()).arg(watches.size()).arg(locals.size());
|
||||
|
||||
StackFrames ideStackFrames;
|
||||
for (int i = 0; i != stackFrames.size(); ++i) {
|
||||
StackFrame frame;
|
||||
frame.line = stackFrames.at(i).lineNumber;
|
||||
frame.function = stackFrames.at(i).functionName;
|
||||
frame.file = toFileInProject(QUrl(stackFrames.at(i).fileUrl));
|
||||
frame.usable = QFileInfo(frame.file).isReadable();
|
||||
frame.level = i + 1;
|
||||
ideStackFrames << frame;
|
||||
}
|
||||
|
||||
if (ideStackFrames.size() && ideStackFrames.back().function == "<global>")
|
||||
ideStackFrames.takeLast();
|
||||
stackHandler()->setFrames(ideStackFrames);
|
||||
|
||||
watchHandler()->beginCycle();
|
||||
bool needPing = false;
|
||||
|
||||
foreach (WatchData data, watches) {
|
||||
data.iname = watchHandler()->watcherName(data.exp);
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WatchData data, locals) {
|
||||
data.iname = "local." + data.exp;
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (needPing) {
|
||||
sendPing();
|
||||
} else {
|
||||
watchHandler()->endCycle();
|
||||
}
|
||||
|
||||
bool becauseOfException;
|
||||
stream >> becauseOfException;
|
||||
|
||||
logString += becauseOfException ? " exception" : " no_exception";
|
||||
|
||||
if (becauseOfException) {
|
||||
QString error;
|
||||
stream >> error;
|
||||
|
||||
logString += QLatin1Char(' ');
|
||||
logString += error;
|
||||
logMessage(LogReceive, logString);
|
||||
|
||||
QString msg = stackFrames.isEmpty()
|
||||
? tr("<p>An uncaught exception occurred:</p><p>%1</p>")
|
||||
.arg(Qt::escape(error))
|
||||
: tr("<p>An uncaught exception occurred in <i>%1</i>:</p><p>%2</p>")
|
||||
.arg(stackFrames.value(0).fileUrl, Qt::escape(error));
|
||||
showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg);
|
||||
} else {
|
||||
//
|
||||
// Make breakpoint non-pending
|
||||
//
|
||||
QString file;
|
||||
QString function;
|
||||
int line = -1;
|
||||
|
||||
if (!ideStackFrames.isEmpty()) {
|
||||
file = ideStackFrames.at(0).file;
|
||||
line = ideStackFrames.at(0).line;
|
||||
function = ideStackFrames.at(0).function;
|
||||
}
|
||||
|
||||
BreakHandler *handler = breakHandler();
|
||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
||||
QString processedFilename = handler->fileName(id);
|
||||
if (processedFilename == file && handler->lineNumber(id) == line) {
|
||||
QTC_CHECK(handler->state(id) == BreakpointInserted);
|
||||
BreakpointResponse br = handler->response(id);
|
||||
br.fileName = file;
|
||||
br.lineNumber = line;
|
||||
br.functionName = function;
|
||||
handler->setResponse(id, br);
|
||||
}
|
||||
}
|
||||
|
||||
logMessage(LogReceive, logString);
|
||||
}
|
||||
|
||||
if (!ideStackFrames.isEmpty())
|
||||
gotoLocation(ideStackFrames.value(0));
|
||||
|
||||
} else if (command == "RESULT") {
|
||||
WatchData data;
|
||||
QByteArray iname;
|
||||
stream >> iname >> data;
|
||||
|
||||
logMessage(LogReceive, QString("%1 %2 %3").arg(QString(command),
|
||||
QString(iname), QString(data.value)));
|
||||
data.iname = iname;
|
||||
if (iname.startsWith("watch.")) {
|
||||
watchHandler()->insertData(data);
|
||||
} else if(iname == "console") {
|
||||
showMessage(data.value, ScriptConsoleOutput);
|
||||
} else {
|
||||
qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
|
||||
}
|
||||
} else if (command == "EXPANDED") {
|
||||
QList<WatchData> result;
|
||||
QByteArray iname;
|
||||
stream >> iname >> result;
|
||||
|
||||
logMessage(LogReceive, QString("%1 %2 (%3 x watchdata)").arg(
|
||||
QString(command), QString(iname), QString::number(result.size())));
|
||||
bool needPing = false;
|
||||
foreach (WatchData data, result) {
|
||||
data.iname = iname + '.' + data.exp;
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
if (needPing)
|
||||
sendPing();
|
||||
} else if (command == "LOCALS") {
|
||||
QList<WatchData> locals;
|
||||
QList<WatchData> watches;
|
||||
int frameId;
|
||||
stream >> frameId >> locals;
|
||||
if (!stream.atEnd()) { // compatibility with jsdebuggeragent from 2.1, 2.2
|
||||
stream >> watches;
|
||||
}
|
||||
|
||||
logMessage(LogReceive, QString("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
|
||||
QString(command), QString::number(frameId),
|
||||
QString::number(locals.size()),
|
||||
QString::number(watches.size())));
|
||||
watchHandler()->beginCycle();
|
||||
bool needPing = false;
|
||||
foreach (WatchData data, watches) {
|
||||
data.iname = watchHandler()->watcherName(data.exp);
|
||||
watchHandler()->insertData(data);
|
||||
|
||||
if (watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WatchData data, locals) {
|
||||
data.iname = "local." + data.exp;
|
||||
watchHandler()->insertData(data);
|
||||
if (watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
if (needPing)
|
||||
sendPing();
|
||||
else
|
||||
watchHandler()->endCycle();
|
||||
|
||||
} else if (command == "PONG") {
|
||||
int ping;
|
||||
stream >> ping;
|
||||
|
||||
logMessage(LogReceive, QString("%1 %2").arg(QString(command), QString::number(ping)));
|
||||
|
||||
if (ping == d->m_ping)
|
||||
watchHandler()->endCycle();
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
|
||||
logMessage(LogReceive, QString("%1 UNKNOWN COMMAND!!").arg(QString(command)));
|
||||
}
|
||||
notifyInferiorStopOk();
|
||||
}
|
||||
|
||||
void QmlEngine::disconnected()
|
||||
@@ -1016,14 +692,9 @@ void QmlEngine::wrongSetupMessageBoxFinished(int result)
|
||||
|
||||
void QmlEngine::executeDebuggerCommand(const QString& command)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXEC";
|
||||
QByteArray console = "console";
|
||||
rs << cmd << console << command;
|
||||
logMessage(LogSend, QString("%1 %2 %3").arg(QString(cmd), QString(console),
|
||||
logMessage(LogSend, QString("%1 %2 %3").arg(QString("EXEC"), QString("console"),
|
||||
QString(command)));
|
||||
sendMessage(reply);
|
||||
d->m_adapter.activeDebuggerClient()->executeDebuggerCommand(command);
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,7 +705,7 @@ QString QmlEngine::qmlImportPath() const
|
||||
|
||||
void QmlEngine::logMessage(LogDirection direction, const QString &message)
|
||||
{
|
||||
QString msg = "JSDebugger";
|
||||
QString msg = "QmlDebugger";
|
||||
if (direction == LogSend) {
|
||||
msg += " sending ";
|
||||
} else {
|
||||
|
||||
@@ -49,6 +49,11 @@ class QmlEngine : public DebuggerEngine
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum LogDirection {
|
||||
LogSend,
|
||||
LogReceive
|
||||
};
|
||||
|
||||
QmlEngine(const DebuggerStartParameters &startParameters,
|
||||
DebuggerEngine *masterEngine);
|
||||
~QmlEngine();
|
||||
@@ -62,9 +67,12 @@ public:
|
||||
int timeout = -1) const;
|
||||
void filterApplicationMessage(const QString &msg, int channel);
|
||||
virtual bool acceptsWatchesWhileRunning() const;
|
||||
QString toFileInProject(const QUrl &fileUrl);
|
||||
void inferiorSpontaneousStop();
|
||||
|
||||
void logMessage(LogDirection direction, const QString &str);
|
||||
|
||||
public slots:
|
||||
void messageReceived(const QByteArray &message);
|
||||
void disconnected();
|
||||
|
||||
private slots:
|
||||
@@ -120,7 +128,6 @@ private:
|
||||
unsigned int debuggerCapabilities() const;
|
||||
|
||||
signals:
|
||||
void sendMessage(const QByteArray &msg);
|
||||
void tooltipRequested(const QPoint &mousePos,
|
||||
TextEditor::ITextEditor *editor, int cursorPos);
|
||||
|
||||
@@ -135,9 +142,6 @@ private slots:
|
||||
void synchronizeWatchers();
|
||||
|
||||
private:
|
||||
void expandObject(const QByteArray &iname, quint64 objectId);
|
||||
void sendPing();
|
||||
|
||||
void closeConnection();
|
||||
void startApplicationLauncher();
|
||||
void stopApplicationLauncher();
|
||||
@@ -148,13 +152,6 @@ private:
|
||||
const QString &oldBasePath, const QString &newBasePath) const;
|
||||
QString qmlImportPath() const;
|
||||
|
||||
enum LogDirection {
|
||||
LogSend,
|
||||
LogReceive
|
||||
};
|
||||
void logMessage(LogDirection direction, const QString &str);
|
||||
QString toFileInProject(const QUrl &fileUrl);
|
||||
|
||||
private:
|
||||
friend class QmlCppEngine;
|
||||
QmlEnginePrivate *d;
|
||||
|
||||
624
src/plugins/debugger/qml/qmlv8debuggerclient.cpp
Normal file
624
src/plugins/debugger/qml/qmlv8debuggerclient.cpp
Normal file
@@ -0,0 +1,624 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlv8debuggerclient.h"
|
||||
|
||||
#include "watchdata.h"
|
||||
#include "watchhandler.h"
|
||||
#include "breakpoint.h"
|
||||
#include "breakhandler.h"
|
||||
#include "debuggerconstants.h"
|
||||
#include "qmlengine.h"
|
||||
#include "stackhandler.h"
|
||||
#include "debuggercore.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtGui/QTextDocument>
|
||||
#include <QtGui/QMessageBox>
|
||||
|
||||
#define INITIALPARAMS "seq" << ':' << ++d->sequence << ',' << "type" << ':' << "request"
|
||||
|
||||
using namespace Json;
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class QmlV8DebuggerClientPrivate
|
||||
{
|
||||
public:
|
||||
explicit QmlV8DebuggerClientPrivate(QmlV8DebuggerClient *) :
|
||||
sequence(0), ping(0), engine(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int sequence;
|
||||
int ping;
|
||||
QmlEngine *engine;
|
||||
QHash<BreakpointModelId,int> breakpoints;
|
||||
QHash<int,BreakpointModelId> breakpointsSync;
|
||||
QHash<int,QByteArray> locals;
|
||||
QHash<int,QByteArray> watches;
|
||||
QByteArray frames;
|
||||
};
|
||||
|
||||
QmlV8DebuggerClient::QmlV8DebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client)
|
||||
: QmlDebuggerClient(client, QLatin1String("V8Debugger")),
|
||||
d(new QmlV8DebuggerClientPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
QmlV8DebuggerClient::~QmlV8DebuggerClient()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QByteArray QmlV8DebuggerClient::packMessage(QByteArray& message)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "V8DEBUG";
|
||||
rs << cmd << message;
|
||||
return reply;
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::executeStep()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "continue";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "stepaction" << ':' << "in";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::executeStepOut()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "continue";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "stepaction" << ':' << "out";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::executeNext()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "continue";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "stepaction" << ':' << "next";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::executeStepI()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "continue";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "stepaction" << ':' << "in";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::continueInferior()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "continue";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::interruptInferior()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "interrupt";
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::activateFrame(int index)
|
||||
{
|
||||
setLocals(index);
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::insertBreakpoints(BreakHandler *handler, BreakpointModelId *id)
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "setbreakpoint";
|
||||
JsonInputStream(request) << ',' << "arguments" << ':' << '{';
|
||||
if (handler->breakpointData(*id).type == BreakpointByFileAndLine) {
|
||||
JsonInputStream(request) << "type" << ':' << "script";
|
||||
JsonInputStream(request) << ',' << "target" << ':' << QFileInfo(handler->fileName(*id)).fileName().toUtf8();
|
||||
JsonInputStream(request) << ',' << "line" << ':' << handler->lineNumber(*id) - 1;
|
||||
} else if (handler->breakpointData(*id).type == BreakpointByFunction) {
|
||||
JsonInputStream(request) << "type" << ':' << "function";
|
||||
JsonInputStream(request) << ',' << "target" << ':' << handler->functionName(*id).toUtf8();
|
||||
}
|
||||
JsonInputStream(request) << '}';
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
d->breakpointsSync.insert(d->sequence,*id);
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::removeBreakpoints(BreakpointModelId *id)
|
||||
{
|
||||
QList<int> breakpoints = d->breakpoints.values(*id);
|
||||
d->breakpoints.remove(*id);
|
||||
|
||||
foreach (int bp, breakpoints) {
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "clearbreakpoint";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "breakpoint" << ':' << bp;
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setBreakpoints()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::assignValueInDebugger(const QByteArray expr, const quint64 &id,
|
||||
const QString &property, const QString value)
|
||||
{
|
||||
//TODO::
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::updateWatchData(const WatchData *data)
|
||||
{
|
||||
if (!data->iname.startsWith("watch."))
|
||||
return;
|
||||
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "evaluate";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "expression" << ':' << data->exp;
|
||||
JsonInputStream(request) << ',' << "frame" << ':' << d->engine->stackHandler()->currentFrame().level;
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
d->watches.insert(d->sequence,data->iname);
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::executeDebuggerCommand(const QString &command)
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "evaluate";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "expression" << ':' << command;
|
||||
JsonInputStream(request) << ',' << "global" << ':' << true;
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::synchronizeWatchers(const QStringList &watchers)
|
||||
{
|
||||
//TODO:: send watchers list
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId)
|
||||
{
|
||||
d->locals.insert(objectId,iname);
|
||||
QList<int> ids;
|
||||
ids.append(objectId);
|
||||
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "lookup";
|
||||
|
||||
JsonInputStream(request) << ',' << "arguments" << ':';
|
||||
JsonInputStream(request) << '{' << "handles" << ':' << ids;
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::sendPing()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "ping" << '}';
|
||||
|
||||
d->ping = d->sequence;
|
||||
sendMessage(packMessage(request));
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::backtrace()
|
||||
{
|
||||
QByteArray request;
|
||||
|
||||
JsonInputStream(request) << '{' << INITIALPARAMS ;
|
||||
JsonInputStream(request) << ',' << "command" << ':' << "backtrace";
|
||||
JsonInputStream(request) << '}';
|
||||
|
||||
sendMessage(packMessage(request));
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::messageReceived(const QByteArray &data)
|
||||
{
|
||||
QDataStream ds(data);
|
||||
QByteArray command;
|
||||
ds >> command;
|
||||
|
||||
if (command == "V8DEBUG") {
|
||||
QByteArray response;
|
||||
ds >> response;
|
||||
|
||||
JsonValue value(response);
|
||||
QString type = value.findChild("type").toVariant().toString();
|
||||
|
||||
if (type == "response") {
|
||||
|
||||
if (!value.findChild("success").toVariant().toBool()) {
|
||||
//TODO:: Error
|
||||
qDebug() << Q_FUNC_INFO << value.toString(true,2);
|
||||
return;
|
||||
}
|
||||
|
||||
QString debugCommand(value.findChild("command").toVariant().toString());
|
||||
if (debugCommand == "pong") {
|
||||
//DO NOTHING
|
||||
} else if (debugCommand == "backtrace") {
|
||||
setStackFrames(response);
|
||||
|
||||
} else if (debugCommand == "lookup") {
|
||||
expandLocal(response);
|
||||
|
||||
} else if (debugCommand == "setbreakpoint") {
|
||||
int sequence = value.findChild("request_seq").toVariant().toInt();
|
||||
int breakpoint = value.findChild("body").findChild("breakpoint").toVariant().toInt();
|
||||
d->breakpoints.insertMulti(d->breakpointsSync.take(sequence),breakpoint);
|
||||
|
||||
} else if (debugCommand == "evaluate") {
|
||||
setExpression(response);
|
||||
|
||||
} else {
|
||||
//TODO::
|
||||
//qDebug() << Q_FUNC_INFO << value.toString(true,2);
|
||||
}
|
||||
|
||||
} else if (type == "event") {
|
||||
QString event(value.findChild("event").toVariant().toString());
|
||||
|
||||
if (event == "break") {
|
||||
d->engine->inferiorSpontaneousStop();
|
||||
backtrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setStackFrames(QByteArray &message)
|
||||
{
|
||||
d->frames = message;
|
||||
JsonValue response(message);
|
||||
|
||||
JsonValue refs = response.findChild("refs");
|
||||
JsonValue body = response.findChild("body");
|
||||
|
||||
int totalFrames = body.findChild("totalFrames").toVariant().toInt();
|
||||
JsonValue stackFrames = body.findChild("frames");
|
||||
|
||||
StackFrames ideStackFrames;
|
||||
for (int i = 0; i != totalFrames; ++i) {
|
||||
|
||||
JsonValue stackFrame = stackFrames.childAt(i);
|
||||
|
||||
StackFrame frame;
|
||||
|
||||
int frameIndex = stackFrame.findChild("index").toVariant().toInt();
|
||||
frame.level = frameIndex;
|
||||
|
||||
frame.line = stackFrame.findChild("line").toVariant().toInt() + 1;
|
||||
|
||||
int index = indexInRef(refs,stackFrame.findChild("func").findChild("ref").toVariant().toInt());
|
||||
if (index != -1) {
|
||||
JsonValue func = refs.childAt(index);
|
||||
frame.function = func.findChild("name").toVariant().toString();
|
||||
}
|
||||
|
||||
index = indexInRef(refs,stackFrame.findChild("script").findChild("ref").toVariant().toInt());
|
||||
if (index != -1) {
|
||||
JsonValue script = refs.childAt(index);
|
||||
frame.file = d->engine->toFileInProject(script.findChild("name").toVariant().toString());
|
||||
frame.usable = QFileInfo(frame.file).isReadable();
|
||||
}
|
||||
ideStackFrames << frame;
|
||||
}
|
||||
|
||||
d->engine->stackHandler()->setFrames(ideStackFrames);
|
||||
|
||||
QString fileName;
|
||||
QString file;
|
||||
QString function;
|
||||
int line = -1;
|
||||
|
||||
if (!ideStackFrames.isEmpty()) {
|
||||
file = ideStackFrames.at(0).file;
|
||||
fileName = QFileInfo(file).fileName();
|
||||
line = ideStackFrames.at(0).line;
|
||||
function = ideStackFrames.at(0).function;
|
||||
}
|
||||
|
||||
BreakHandler *handler = d->engine->breakHandler();
|
||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(d->engine)) {
|
||||
QString processedFilename = QFileInfo(handler->fileName(id)).fileName();
|
||||
if (processedFilename == fileName && handler->lineNumber(id) == line) {
|
||||
QTC_ASSERT(handler->state(id) == BreakpointInserted,/**/);
|
||||
BreakpointResponse br = handler->response(id);
|
||||
br.fileName = file;
|
||||
br.lineNumber = line;
|
||||
br.functionName = function;
|
||||
handler->setResponse(id, br);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ideStackFrames.isEmpty()) {
|
||||
setLocals(0);
|
||||
d->engine->gotoLocation(ideStackFrames.value(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setLocals(int frameIndex)
|
||||
{
|
||||
JsonValue response(d->frames);
|
||||
|
||||
JsonValue refs = response.findChild("refs");
|
||||
JsonValue body = response.findChild("body");
|
||||
|
||||
int totalFrames = body.findChild("totalFrames").toVariant().toInt();
|
||||
JsonValue stackFrames = body.findChild("frames");
|
||||
|
||||
|
||||
for (int i = 0; i != totalFrames; ++i) {
|
||||
|
||||
JsonValue stackFrame = stackFrames.childAt(i);
|
||||
int index = stackFrame.findChild("index").toVariant().toInt();
|
||||
if (index != frameIndex)
|
||||
continue;
|
||||
|
||||
JsonValue locals = stackFrame.findChild("locals");
|
||||
|
||||
d->engine->watchHandler()->beginCycle();
|
||||
|
||||
int localsCount = locals.childCount();
|
||||
for (int j = 0; j != localsCount; ++j) {
|
||||
JsonValue local = locals.childAt(j);
|
||||
|
||||
WatchData data;
|
||||
data.exp = local.findChild("name").toVariant().toByteArray();
|
||||
data.name = data.exp;
|
||||
data.iname = "local." + data.exp;
|
||||
JsonValue val = refs.childAt(indexInRef(refs,local.findChild("value").findChild("ref").toVariant().toInt()));
|
||||
data.type = val.findChild("type").toVariant().toByteArray();
|
||||
|
||||
if (data.type == "object") {
|
||||
data.hasChildren = true;
|
||||
data.value = val.findChild("className").toVariant().toByteArray();
|
||||
|
||||
} else if (data.type == "function" || data.type == "undefined") {
|
||||
data.hasChildren = false;
|
||||
data.value = val.findChild("text").toVariant().toByteArray();
|
||||
|
||||
} else {
|
||||
data.hasChildren = false;
|
||||
data.value = val.findChild("value").toVariant().toByteArray();
|
||||
}
|
||||
|
||||
data.id = val.findChild("handle").toVariant().toInt();
|
||||
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
d->engine->watchHandler()->endCycle();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::expandLocal(QByteArray &message)
|
||||
{
|
||||
JsonValue response(message);
|
||||
|
||||
JsonValue refs = response.findChild("refs");
|
||||
JsonValue body = response.findChild("body");
|
||||
JsonValue details = body.childAt(0);
|
||||
|
||||
int id = QString(details.name()).toInt();
|
||||
QByteArray prepend = d->locals.take(id);
|
||||
|
||||
JsonValue properties = details.findChild("properties");
|
||||
int propertiesCount = properties.childCount();
|
||||
|
||||
for (int k = 0; k != propertiesCount; ++k) {
|
||||
JsonValue property = properties.childAt(k);
|
||||
setPropertyValue(refs,property,prepend);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setExpression(QByteArray &message)
|
||||
{
|
||||
JsonValue response(message);
|
||||
JsonValue body = response.findChild("body");
|
||||
|
||||
int seq = response.findChild("request_seq").toVariant().toInt();
|
||||
|
||||
if (!d->watches.contains(seq)) {
|
||||
d->engine->showMessage(body.findChild("text").toVariant().toString(), ScriptConsoleOutput);
|
||||
return;
|
||||
}
|
||||
//TODO::
|
||||
// JsonValue refs = response.findChild("refs");
|
||||
// JsonValue body = response.findChild("body");
|
||||
// JsonValue details = body.childAt(0);
|
||||
|
||||
// int id = QString(details.name()).toInt();
|
||||
// QByteArray prepend = d->locals.take(id);
|
||||
|
||||
// JsonValue properties = details.findChild("properties");
|
||||
// int propertiesCount = properties.childCount();
|
||||
|
||||
// for (int k = 0; k != propertiesCount; ++k) {
|
||||
// JsonValue property = properties.childAt(k);
|
||||
// setPropertyValue(refs,property,prepend);
|
||||
// }
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setPropertyValue(JsonValue &refs, JsonValue &property, QByteArray &prepend)
|
||||
{
|
||||
WatchData data;
|
||||
data.exp = property.findChild("name").toVariant().toByteArray();
|
||||
data.name = data.exp;
|
||||
data.iname = prepend + '.' + data.exp;
|
||||
JsonValue val = refs.childAt(indexInRef(refs,property.findChild("ref").toVariant().toInt()));
|
||||
data.type = val.findChild("type").toVariant().toByteArray();
|
||||
|
||||
if (data.type == "object") {
|
||||
data.hasChildren = true;
|
||||
data.value = val.findChild("className").toVariant().toByteArray();
|
||||
|
||||
} else if (data.type == "function") {
|
||||
data.hasChildren = false;
|
||||
data.value = val.findChild("text").toVariant().toByteArray();
|
||||
|
||||
} else {
|
||||
data.hasChildren = false;
|
||||
data.value = val.findChild("value").toVariant().toByteArray();
|
||||
}
|
||||
|
||||
data.id = val.findChild("handle").toVariant().toInt();
|
||||
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
int QmlV8DebuggerClient::indexInRef(const JsonValue &refs, int refIndex)
|
||||
{
|
||||
for (int i = 0; i != refs.childCount(); ++i) {
|
||||
JsonValue ref = refs.childAt(i);
|
||||
int index = ref.findChild("handle").toVariant().toInt();
|
||||
if (index == refIndex)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QmlV8DebuggerClient::setEngine(QmlEngine *engine)
|
||||
{
|
||||
d->engine = engine;
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
||||
106
src/plugins/debugger/qml/qmlv8debuggerclient.h
Normal file
106
src/plugins/debugger/qml/qmlv8debuggerclient.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLV8DEBUGGERCLIENT_H
|
||||
#define QMLV8DEBUGGERCLIENT_H
|
||||
|
||||
#include "qmldebuggerclient.h"
|
||||
#include "stackframe.h"
|
||||
#include "watchdata.h"
|
||||
#include "qmlengine.h"
|
||||
#include "json.h"
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class QmlV8DebuggerClientPrivate;
|
||||
|
||||
class QmlV8DebuggerClient : public QmlDebuggerClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlV8DebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client);
|
||||
~QmlV8DebuggerClient();
|
||||
|
||||
void executeStep();
|
||||
void executeStepOut();
|
||||
void executeNext();
|
||||
void executeStepI();
|
||||
|
||||
void continueInferior();
|
||||
void interruptInferior();
|
||||
|
||||
void activateFrame(int index);
|
||||
|
||||
void insertBreakpoints(BreakHandler *handler, BreakpointModelId *id);
|
||||
void removeBreakpoints(BreakpointModelId *id);
|
||||
void setBreakpoints();
|
||||
|
||||
void assignValueInDebugger(const QByteArray expr, const quint64 &id,
|
||||
const QString &property, const QString value);
|
||||
|
||||
void updateWatchData(const WatchData *data);
|
||||
void executeDebuggerCommand(const QString &command);
|
||||
|
||||
void synchronizeWatchers(const QStringList &watchers);
|
||||
|
||||
void expandObject(const QByteArray &iname, quint64 objectId);
|
||||
void sendPing();
|
||||
|
||||
void setEngine(QmlEngine *engine);
|
||||
|
||||
signals:
|
||||
void notifyDebuggerStopped();
|
||||
|
||||
protected:
|
||||
void messageReceived(const QByteArray &data);
|
||||
|
||||
private:
|
||||
void backtrace();
|
||||
void setStackFrames(QByteArray &);
|
||||
void setLocals(int frameIndex);
|
||||
void setExpression(QByteArray &message);
|
||||
void expandLocal(QByteArray &message);
|
||||
void setPropertyValue(Json::JsonValue &refs, Json::JsonValue &property, QByteArray &prepend);
|
||||
int indexInRef(const Json::JsonValue &refs, int refIndex);
|
||||
QByteArray packMessage(QByteArray& message);
|
||||
|
||||
private:
|
||||
QmlV8DebuggerClientPrivate *d;
|
||||
friend class QmlV8DebuggerClientPrivate;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
||||
|
||||
#endif // QMLV8DEBUGGERCLIENT_H
|
||||
511
src/plugins/debugger/qml/qscriptdebuggerclient.cpp
Normal file
511
src/plugins/debugger/qml/qscriptdebuggerclient.cpp
Normal file
@@ -0,0 +1,511 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "qscriptdebuggerclient.h"
|
||||
|
||||
#include "watchdata.h"
|
||||
#include "watchhandler.h"
|
||||
#include "breakpoint.h"
|
||||
#include "breakhandler.h"
|
||||
#include "debuggerconstants.h"
|
||||
#include "qmlengine.h"
|
||||
#include "stackhandler.h"
|
||||
#include "debuggercore.h"
|
||||
|
||||
#include <QTextDocument>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
struct JSAgentBreakpointData
|
||||
{
|
||||
QByteArray functionName;
|
||||
QByteArray fileUrl;
|
||||
qint32 lineNumber;
|
||||
};
|
||||
|
||||
struct JSAgentStackData
|
||||
{
|
||||
QByteArray functionName;
|
||||
QByteArray fileUrl;
|
||||
qint32 lineNumber;
|
||||
};
|
||||
|
||||
uint qHash(const JSAgentBreakpointData &b)
|
||||
{
|
||||
return b.lineNumber ^ qHash(b.fileUrl);
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
|
||||
{
|
||||
return s << data.functionName << data.fileUrl << data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
|
||||
{
|
||||
return s << data.functionName << data.fileUrl << data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
|
||||
{
|
||||
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &s, JSAgentStackData &data)
|
||||
{
|
||||
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
|
||||
}
|
||||
|
||||
bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
|
||||
{
|
||||
return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl;
|
||||
}
|
||||
|
||||
typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
|
||||
typedef QList<JSAgentStackData> JSAgentStackFrames;
|
||||
|
||||
|
||||
static QDataStream &operator>>(QDataStream &s, WatchData &data)
|
||||
{
|
||||
data = WatchData();
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
QByteArray type;
|
||||
bool hasChildren = false;
|
||||
s >> data.exp >> name >> value >> type >> hasChildren >> data.id;
|
||||
data.name = QString::fromUtf8(name);
|
||||
data.setType(type, false);
|
||||
data.setValue(QString::fromUtf8(value));
|
||||
data.setHasChildren(hasChildren);
|
||||
data.setAllUnneeded();
|
||||
return s;
|
||||
}
|
||||
|
||||
class QScriptDebuggerClientPrivate
|
||||
{
|
||||
public:
|
||||
explicit QScriptDebuggerClientPrivate(QScriptDebuggerClient *) :
|
||||
ping(0), engine(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ping;
|
||||
QmlEngine *engine;
|
||||
JSAgentBreakpoints breakpoints;
|
||||
};
|
||||
|
||||
QScriptDebuggerClient::QScriptDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client)
|
||||
: QmlDebuggerClient(client, QLatin1String("JSDebugger")),
|
||||
d(new QScriptDebuggerClientPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
QScriptDebuggerClient::~QScriptDebuggerClient()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::executeStep()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPINTO";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::executeStepOut()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPOUT";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::executeNext()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPOVER";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::executeStepI()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "STEPINTO";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::continueInferior()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "CONTINUE";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::interruptInferior()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "INTERRUPT";
|
||||
rs << cmd;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::activateFrame(int index)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "ACTIVATE_FRAME";
|
||||
rs << cmd
|
||||
<< index;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::insertBreakpoints(BreakHandler *handler, BreakpointModelId *id)
|
||||
{
|
||||
JSAgentBreakpointData bp;
|
||||
bp.fileUrl = QUrl::fromLocalFile(handler->fileName(*id)).toString().toUtf8();
|
||||
bp.lineNumber = handler->lineNumber(*id);
|
||||
bp.functionName = handler->functionName(*id).toUtf8();
|
||||
d->breakpoints.insert(bp);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::removeBreakpoints(BreakpointModelId */*id*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::setBreakpoints()
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "BREAKPOINTS";
|
||||
rs << cmd
|
||||
<< d->breakpoints;
|
||||
|
||||
QStringList breakPointsStr;
|
||||
foreach (const JSAgentBreakpointData &bp, d->breakpoints) {
|
||||
breakPointsStr << QString("('%1' '%2' %3)").arg(QString(bp.functionName),
|
||||
QString(bp.fileUrl), QString::number(bp.lineNumber));
|
||||
}
|
||||
|
||||
sendMessage(reply);
|
||||
|
||||
d->breakpoints.clear();
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::assignValueInDebugger(const QByteArray expr, const quint64 &id,
|
||||
const QString &property, const QString value)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "SET_PROPERTY";
|
||||
rs << cmd;
|
||||
rs << expr << id << property << value;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::updateWatchData(const WatchData *data)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXEC";
|
||||
rs << cmd;
|
||||
rs << data->iname << data->name;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::executeDebuggerCommand(const QString &command)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXEC";
|
||||
QByteArray console = "console";
|
||||
rs << cmd << console << command;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::synchronizeWatchers(const QStringList &watchers)
|
||||
{
|
||||
// send watchers list
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "WATCH_EXPRESSIONS";
|
||||
rs << cmd;
|
||||
rs << watchers;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::expandObject(const QByteArray &iname, quint64 objectId)
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "EXPAND";
|
||||
rs << cmd;
|
||||
rs << iname << objectId;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::sendPing()
|
||||
{
|
||||
d->ping++;
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
QByteArray cmd = "PING";
|
||||
rs << cmd;
|
||||
rs << d->ping;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::messageReceived(const QByteArray &data)
|
||||
{
|
||||
QByteArray rwData = data;
|
||||
QDataStream stream(&rwData, QIODevice::ReadOnly);
|
||||
|
||||
QByteArray command;
|
||||
stream >> command;
|
||||
|
||||
if (command == "STOPPED") {
|
||||
d->engine->inferiorSpontaneousStop();
|
||||
|
||||
QString logString = QString::fromLatin1(command);
|
||||
|
||||
JSAgentStackFrames stackFrames;
|
||||
QList<WatchData> watches;
|
||||
QList<WatchData> locals;
|
||||
stream >> stackFrames >> watches >> locals;
|
||||
|
||||
logString += QString::fromLatin1(" (%1 stack frames) (%2 watches) (%3 locals)").
|
||||
arg(stackFrames.size()).arg(watches.size()).arg(locals.size());
|
||||
|
||||
StackFrames ideStackFrames;
|
||||
for (int i = 0; i != stackFrames.size(); ++i) {
|
||||
StackFrame frame;
|
||||
frame.line = stackFrames.at(i).lineNumber;
|
||||
frame.function = stackFrames.at(i).functionName;
|
||||
frame.file = d->engine->toFileInProject(QUrl(stackFrames.at(i).fileUrl));
|
||||
frame.usable = QFileInfo(frame.file).isReadable();
|
||||
frame.level = i + 1;
|
||||
ideStackFrames << frame;
|
||||
}
|
||||
|
||||
if (ideStackFrames.size() && ideStackFrames.back().function == "<global>")
|
||||
ideStackFrames.takeLast();
|
||||
d->engine->stackHandler()->setFrames(ideStackFrames);
|
||||
|
||||
d->engine->watchHandler()->beginCycle();
|
||||
bool needPing = false;
|
||||
|
||||
foreach (WatchData data, watches) {
|
||||
data.iname = d->engine->watchHandler()->watcherName(data.exp);
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname,data.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WatchData data, locals) {
|
||||
data.iname = "local." + data.exp;
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname,data.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (needPing) {
|
||||
sendPing();
|
||||
} else {
|
||||
d->engine->watchHandler()->endCycle();
|
||||
}
|
||||
|
||||
bool becauseOfException;
|
||||
stream >> becauseOfException;
|
||||
|
||||
logString += becauseOfException ? " exception" : " no_exception";
|
||||
|
||||
if (becauseOfException) {
|
||||
QString error;
|
||||
stream >> error;
|
||||
|
||||
logString += QLatin1Char(' ');
|
||||
logString += error;
|
||||
d->engine->logMessage(QmlEngine::LogReceive, logString);
|
||||
|
||||
QString msg = stackFrames.isEmpty()
|
||||
? tr("<p>An uncaught exception occurred:</p><p>%1</p>")
|
||||
.arg(Qt::escape(error))
|
||||
: tr("<p>An uncaught exception occurred in <i>%1</i>:</p><p>%2</p>")
|
||||
.arg(stackFrames.value(0).fileUrl, Qt::escape(error));
|
||||
showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg);
|
||||
} else {
|
||||
//
|
||||
// Make breakpoint non-pending
|
||||
//
|
||||
QString file;
|
||||
QString function;
|
||||
int line = -1;
|
||||
|
||||
if (!ideStackFrames.isEmpty()) {
|
||||
file = ideStackFrames.at(0).file;
|
||||
line = ideStackFrames.at(0).line;
|
||||
function = ideStackFrames.at(0).function;
|
||||
}
|
||||
|
||||
BreakHandler *handler = d->engine->breakHandler();
|
||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(d->engine)) {
|
||||
QString processedFilename = handler->fileName(id);
|
||||
if (processedFilename == file && handler->lineNumber(id) == line) {
|
||||
QTC_ASSERT(handler->state(id) == BreakpointInserted,/**/);
|
||||
BreakpointResponse br = handler->response(id);
|
||||
br.fileName = file;
|
||||
br.lineNumber = line;
|
||||
br.functionName = function;
|
||||
handler->setResponse(id, br);
|
||||
}
|
||||
}
|
||||
|
||||
d->engine->logMessage(QmlEngine::LogReceive, logString);
|
||||
}
|
||||
|
||||
if (!ideStackFrames.isEmpty())
|
||||
d->engine->gotoLocation(ideStackFrames.value(0));
|
||||
|
||||
} else if (command == "RESULT") {
|
||||
WatchData data;
|
||||
QByteArray iname;
|
||||
stream >> iname >> data;
|
||||
|
||||
d->engine->logMessage(QmlEngine::LogReceive, QString("%1 %2 %3").arg(QString(command),
|
||||
QString(iname), QString(data.value)));
|
||||
data.iname = iname;
|
||||
if (iname.startsWith("watch.")) {
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
} else if (iname == "console") {
|
||||
d->engine->showMessage(data.value, ScriptConsoleOutput);
|
||||
} else {
|
||||
qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
|
||||
}
|
||||
} else if (command == "EXPANDED") {
|
||||
QList<WatchData> result;
|
||||
QByteArray iname;
|
||||
stream >> iname >> result;
|
||||
|
||||
d->engine->logMessage(QmlEngine::LogReceive, QString("%1 %2 (%3 x watchdata)").arg(
|
||||
QString(command), QString(iname), QString::number(result.size())));
|
||||
bool needPing = false;
|
||||
foreach (WatchData data, result) {
|
||||
data.iname = iname + '.' + data.exp;
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
if (needPing)
|
||||
sendPing();
|
||||
} else if (command == "LOCALS") {
|
||||
QList<WatchData> locals;
|
||||
QList<WatchData> watches;
|
||||
int frameId;
|
||||
stream >> frameId >> locals;
|
||||
if (!stream.atEnd()) { // compatibility with jsdebuggeragent from 2.1, 2.2
|
||||
stream >> watches;
|
||||
}
|
||||
|
||||
d->engine->logMessage(QmlEngine::LogReceive, QString("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
|
||||
QString(command), QString::number(frameId),
|
||||
QString::number(locals.size()),
|
||||
QString::number(watches.size())));
|
||||
d->engine->watchHandler()->beginCycle();
|
||||
bool needPing = false;
|
||||
foreach (WatchData data, watches) {
|
||||
data.iname = d->engine->watchHandler()->watcherName(data.exp);
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WatchData data, locals) {
|
||||
data.iname = "local." + data.exp;
|
||||
d->engine->watchHandler()->insertData(data);
|
||||
if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
|
||||
needPing = true;
|
||||
expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
if (needPing)
|
||||
sendPing();
|
||||
else
|
||||
d->engine->watchHandler()->endCycle();
|
||||
|
||||
} else if (command == "PONG") {
|
||||
int ping;
|
||||
stream >> ping;
|
||||
|
||||
d->engine->logMessage(QmlEngine::LogReceive, QString("%1 %2").arg(QString(command), QString::number(ping)));
|
||||
|
||||
if (ping == d->ping)
|
||||
d->engine->watchHandler()->endCycle();
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
|
||||
d->engine->logMessage(QmlEngine::LogReceive, QString("%1 UNKNOWN COMMAND!!").arg(QString(command)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QScriptDebuggerClient::setEngine(QmlEngine *engine)
|
||||
{
|
||||
d->engine = engine;
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
||||
95
src/plugins/debugger/qml/qscriptdebuggerclient.h
Normal file
95
src/plugins/debugger/qml/qscriptdebuggerclient.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QSCRIPTDEBUGGERCLIENT_H
|
||||
#define QSCRIPTDEBUGGERCLIENT_H
|
||||
|
||||
#include "qmldebuggerclient.h"
|
||||
#include "stackframe.h"
|
||||
#include "watchdata.h"
|
||||
#include "qmlengine.h"
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class QScriptDebuggerClientPrivate;
|
||||
|
||||
class QScriptDebuggerClient : public QmlDebuggerClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QScriptDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client);
|
||||
~QScriptDebuggerClient();
|
||||
|
||||
void executeStep();
|
||||
void executeStepOut();
|
||||
void executeNext();
|
||||
void executeStepI();
|
||||
|
||||
void continueInferior();
|
||||
void interruptInferior();
|
||||
|
||||
void activateFrame(int index);
|
||||
|
||||
void insertBreakpoints(BreakHandler *handler, BreakpointModelId *id);
|
||||
void removeBreakpoints(BreakpointModelId *id);
|
||||
void setBreakpoints();
|
||||
|
||||
void assignValueInDebugger(const QByteArray expr, const quint64 &id,
|
||||
const QString &property, const QString value);
|
||||
|
||||
void updateWatchData(const WatchData *data);
|
||||
void executeDebuggerCommand(const QString &command);
|
||||
|
||||
void synchronizeWatchers(const QStringList &watchers);
|
||||
|
||||
void expandObject(const QByteArray &iname, quint64 objectId);
|
||||
void sendPing();
|
||||
|
||||
void setEngine(QmlEngine *engine);
|
||||
|
||||
signals:
|
||||
void notifyDebuggerStopped();
|
||||
|
||||
protected:
|
||||
void messageReceived(const QByteArray &data);
|
||||
|
||||
private:
|
||||
QScriptDebuggerClientPrivate *d;
|
||||
friend class QScriptDebuggerClientPrivate;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
||||
|
||||
#endif // QSCRIPTDEBUGGERCLIENT_H
|
||||
@@ -344,7 +344,7 @@ void CodaRunControl::handleDebugSessionEnded(const CodaCommandResult &result)
|
||||
|
||||
void CodaRunControl::handleFindProcesses(const CodaCommandResult &result)
|
||||
{
|
||||
if (result.values.size() && result.values.at(0).type() == JsonValue::Array && result.values.at(0).children().count()) {
|
||||
if (result.values.size() && result.values.at(0).type() == Json::JsonValue::Array && result.values.at(0).children().count()) {
|
||||
//there are processes running. Cannot run mine
|
||||
appendMessage(tr("The process is already running on the device. Please first close it.\n"), Utils::ErrorMessageFormat);
|
||||
finishRunControl();
|
||||
@@ -367,7 +367,7 @@ void CodaRunControl::handleCreateProcess(const CodaCommandResult &result)
|
||||
if (ok) {
|
||||
if (m_codaFlags & OptionsUseDebugSession) {
|
||||
if (result.values.size()) {
|
||||
JsonValue id = result.values.at(0).findChild("ID");
|
||||
Json::JsonValue id = result.values.at(0).findChild("ID");
|
||||
if (id.isValid()) {
|
||||
m_state = StateProcessRunning;
|
||||
m_runningProcessId = id.data();
|
||||
|
||||
@@ -77,3 +77,6 @@ FORMS += $$PWD/s60createpackagestep.ui \
|
||||
$$PWD/s60publishingbuildsettingspageovi.ui \
|
||||
$$PWD/s60publishingresultspageovi.ui \
|
||||
$$PWD/s60publishingsissettingspageovi.ui
|
||||
|
||||
include(../../../shared/json/json.pri)
|
||||
DEFINES += JSON_INCLUDE_PRI
|
||||
|
||||
@@ -44,14 +44,13 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
//#define DEBUG_JASON
|
||||
#ifdef DEBUG_JASON
|
||||
#define JDEBUG(s) qDebug() << s
|
||||
#else
|
||||
#define JDEBUG(s)
|
||||
#endif
|
||||
|
||||
namespace Coda {
|
||||
using namespace Json;
|
||||
|
||||
static void skipSpaces(const char *&from, const char *to)
|
||||
{
|
||||
@@ -530,11 +529,23 @@ JsonInputStream &JsonInputStream::operator<<(const QVector<QByteArray> &ba)
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonInputStream &JsonInputStream::operator<<(const QList<int> &in)
|
||||
{
|
||||
m_target.append('[');
|
||||
const int count = in.size();
|
||||
for (int i = 0 ; i < count; i++) {
|
||||
if (i)
|
||||
m_target.append(',');
|
||||
m_target.append(QByteArray::number(in.at(i)));
|
||||
}
|
||||
m_target.append(']');
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonInputStream &JsonInputStream::operator<<(bool b)
|
||||
{
|
||||
m_target.append(b ? "true" : "false");
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Coda
|
||||
|
||||
@@ -30,18 +30,18 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SYMBIANUTILS_JSON_H
|
||||
#define SYMBIANUTILS_JSON_H
|
||||
#ifndef JSON_H
|
||||
#define JSON_H
|
||||
|
||||
#include "symbianutils_global.h"
|
||||
#include "json_global.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace Coda {
|
||||
namespace Json {
|
||||
|
||||
class SYMBIANUTILS_EXPORT JsonValue
|
||||
class JSON_EXPORT JsonValue
|
||||
{
|
||||
public:
|
||||
JsonValue() : m_type(Invalid) {}
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
* Note that strings get double quotes and JSON-escaping, characters should be
|
||||
* used for the array/hash delimiters.
|
||||
* */
|
||||
class SYMBIANUTILS_EXPORT JsonInputStream {
|
||||
class JSON_EXPORT JsonInputStream {
|
||||
public:
|
||||
explicit JsonInputStream(QByteArray &a) : m_target(a) {}
|
||||
|
||||
@@ -121,6 +121,9 @@ public:
|
||||
// Format as array
|
||||
JsonInputStream &operator<<(const QVector<QByteArray> &ba);
|
||||
|
||||
//Format as array
|
||||
JsonInputStream &operator<<(const QList<int> &in);
|
||||
|
||||
JsonInputStream &operator<<(bool b);
|
||||
|
||||
JsonInputStream &operator<<(int i)
|
||||
@@ -137,6 +140,6 @@ private:
|
||||
QByteArray &m_target;
|
||||
};
|
||||
|
||||
} // namespace Coda
|
||||
} //namespace Json
|
||||
|
||||
#endif // SYMBIANUTILS_JSON_H
|
||||
#endif // JSON_H
|
||||
7
src/shared/json/json.pri
Normal file
7
src/shared/json/json.pri
Normal file
@@ -0,0 +1,7 @@
|
||||
INCLUDEPATH *= $$PWD
|
||||
|
||||
# Input
|
||||
HEADERS += $$PWD/json_global.h \
|
||||
$$PWD/json.h
|
||||
|
||||
SOURCES += $$PWD/json.cpp
|
||||
46
src/shared/json/json_global.h
Normal file
46
src/shared/json/json_global.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (info@qt.nokia.com)
|
||||
**
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at info@qt.nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef JSON_GLOBAL_H
|
||||
#define JSON_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(JSON_BUILD_LIB)
|
||||
# define JSON_EXPORT Q_DECL_EXPORT
|
||||
#elif defined(JSON_BUILD_STATIC_LIB) || defined(JSON_INCLUDE_PRI)
|
||||
# define JSON_EXPORT
|
||||
#else
|
||||
# define JSON_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // SYMBIANUTILS_GLOBAL_H
|
||||
@@ -112,6 +112,7 @@ static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn)
|
||||
return frame;
|
||||
}
|
||||
|
||||
using namespace Json;
|
||||
namespace Coda {
|
||||
// ------------- CodaCommandError
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandError {
|
||||
operator bool() const { return isError(); }
|
||||
QString toString() const;
|
||||
void write(QTextStream &str) const;
|
||||
bool parse(const QVector<JsonValue> &values);
|
||||
bool parse(const QVector<Json::JsonValue> &values);
|
||||
|
||||
quint64 timeMS; // Since 1.1.1970
|
||||
qint64 code;
|
||||
@@ -94,7 +94,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandResult {
|
||||
explicit CodaCommandResult(Type t = SuccessReply);
|
||||
explicit CodaCommandResult(char typeChar, Services service,
|
||||
const QByteArray &request,
|
||||
const QVector<JsonValue> &values,
|
||||
const QVector<Json::JsonValue> &values,
|
||||
const QVariant &cookie);
|
||||
|
||||
QString toString() const;
|
||||
@@ -107,7 +107,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandResult {
|
||||
Services service;
|
||||
QByteArray request;
|
||||
CodaCommandError commandError;
|
||||
QVector<JsonValue> values;
|
||||
QVector<Json::JsonValue> values;
|
||||
QVariant cookie;
|
||||
};
|
||||
|
||||
@@ -394,7 +394,7 @@ public:
|
||||
static CodaStatResponse parseStat(const CodaCommandResult &r);
|
||||
|
||||
signals:
|
||||
void genericCodaEvent(int service, const QByteArray &name, const QVector<JsonValue> &value);
|
||||
void genericCodaEvent(int service, const QByteArray &name, const QVector<Json::JsonValue> &value);
|
||||
void codaEvent(const Coda::CodaEvent &knownEvent);
|
||||
void unknownEvent(uchar protocolId, const QByteArray& data);
|
||||
void serialPong(const QString &codaVersion);
|
||||
|
||||
@@ -43,6 +43,7 @@ static const char *serviceNamesC[] =
|
||||
"DebugSessionControl",
|
||||
"UnknownService"};
|
||||
|
||||
using namespace Json;
|
||||
namespace Coda {
|
||||
|
||||
SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#define CODAMESSAGE_H
|
||||
|
||||
#include "symbianutils_global.h"
|
||||
#include "json_global.h"
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
@@ -42,10 +43,12 @@ QT_BEGIN_NAMESPACE
|
||||
class QTextStream;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Coda {
|
||||
|
||||
namespace Json {
|
||||
class JsonValue;
|
||||
class JsonInputStream;
|
||||
}
|
||||
|
||||
namespace Coda {
|
||||
|
||||
enum Services {
|
||||
LocatorService,
|
||||
@@ -101,7 +104,7 @@ struct SYMBIANUTILS_EXPORT RunControlContext {
|
||||
unsigned threadId() const;
|
||||
|
||||
void clear();
|
||||
bool parse(const JsonValue &v);
|
||||
bool parse(const Json::JsonValue &v);
|
||||
void format(QTextStream &str) const;
|
||||
QString toString() const;
|
||||
|
||||
@@ -122,7 +125,7 @@ struct SYMBIANUTILS_EXPORT RunControlContext {
|
||||
struct SYMBIANUTILS_EXPORT ModuleLoadEventInfo {
|
||||
ModuleLoadEventInfo();
|
||||
void clear();
|
||||
bool parse(const JsonValue &v);
|
||||
bool parse(const Json::JsonValue &v);
|
||||
void format(QTextStream &str) const;
|
||||
|
||||
QByteArray name;
|
||||
@@ -154,7 +157,7 @@ struct SYMBIANUTILS_EXPORT Breakpoint {
|
||||
bool thumb;
|
||||
};
|
||||
|
||||
SYMBIANUTILS_EXPORT JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b);
|
||||
Json::JsonInputStream &operator<<(Json::JsonInputStream &str, const Breakpoint &b);
|
||||
|
||||
// Event hierarchy
|
||||
class SYMBIANUTILS_EXPORT CodaEvent
|
||||
@@ -179,7 +182,7 @@ public:
|
||||
Type type() const;
|
||||
virtual QString toString() const;
|
||||
|
||||
static CodaEvent *parseEvent(Services s, const QByteArray &name, const QVector<JsonValue> &val);
|
||||
static CodaEvent *parseEvent(Services s, const QByteArray &name, const QVector<Json::JsonValue> &val);
|
||||
|
||||
protected:
|
||||
explicit CodaEvent(Type type = None);
|
||||
@@ -252,7 +255,7 @@ public:
|
||||
const RunControlContexts &contexts() const { return m_contexts; }
|
||||
virtual QString toString() const;
|
||||
|
||||
static CodaRunControlContextAddedEvent *parseEvent(const QVector<JsonValue> &val);
|
||||
static CodaRunControlContextAddedEvent *parseEvent(const QVector<Json::JsonValue> &val);
|
||||
|
||||
private:
|
||||
const RunControlContexts m_contexts;
|
||||
|
||||
@@ -10,14 +10,12 @@ HEADERS += $$PWD/symbianutils_global.h \
|
||||
$$PWD/symbiandevicemanager.h \
|
||||
$$PWD/codadevice.h \
|
||||
$$PWD/codamessage.h \
|
||||
$$PWD/json.h \
|
||||
$$PWD/virtualserialdevice.h
|
||||
|
||||
SOURCES += $$PWD/codautils.cpp \
|
||||
$$PWD/symbiandevicemanager.cpp \
|
||||
$$PWD/codadevice.cpp \
|
||||
$$PWD/codamessage.cpp \
|
||||
$$PWD/json.cpp \
|
||||
$$PWD/virtualserialdevice.cpp
|
||||
|
||||
DEFINES += HAS_SERIALPORT
|
||||
@@ -25,3 +23,5 @@ win32:SOURCES += $$PWD/virtualserialdevice_win.cpp
|
||||
unix:SOURCES += $$PWD/virtualserialdevice_posix.cpp
|
||||
|
||||
macx:LIBS += -framework IOKit -framework CoreFoundation
|
||||
include(../../shared/json/json.pri)
|
||||
DEFINES += JSON_INCLUDE_PRI
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
include(../qttest.pri)
|
||||
include($$IDE_SOURCE_TREE/src/libs/symbianutils/symbianutils.pri)
|
||||
include($$IDE_SOURCE_TREE/src/shared/json/json.pri)
|
||||
DEFINES += JSON_INCLUDE_PRI
|
||||
|
||||
DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger
|
||||
UTILSDIR = $$IDE_SOURCE_TREE/src/libs
|
||||
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
|
||||
void testJson(const char* input)
|
||||
{
|
||||
QCOMPARE('\n' + QString::fromLatin1(Coda::JsonValue(input).toString(false)),
|
||||
QCOMPARE('\n' + QString::fromLatin1(Json::JsonValue(input).toString(false)),
|
||||
'\n' + QString(input));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user