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;
|
Status status() const;
|
||||||
|
|
||||||
void sendMessage(const QByteArray &);
|
virtual void sendMessage(const QByteArray &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void statusChanged(Status);
|
virtual void statusChanged(Status);
|
||||||
|
|||||||
@@ -1349,7 +1349,7 @@ void CodaGdbAdapter::handleReadRegisters(const CodaCommandResult &result)
|
|||||||
logMessage("ERROR: " + result.errorString(), LogError);
|
logMessage("ERROR: " + result.errorString(), LogError);
|
||||||
return;
|
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(),
|
logMessage(_("Format error in register message: ") + result.toString(),
|
||||||
LogError);
|
LogError);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)
|
include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)
|
||||||
|
include($$PWD/../../../shared/json/json.pri)
|
||||||
|
DEFINES += JSON_INCLUDE_PRI
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/qmlengine.h \
|
$$PWD/qmlengine.h \
|
||||||
@@ -6,10 +8,15 @@ HEADERS += \
|
|||||||
$$PWD/qmldebuggerclient.h \
|
$$PWD/qmldebuggerclient.h \
|
||||||
$$PWD/qmljsprivateapi.h \
|
$$PWD/qmljsprivateapi.h \
|
||||||
$$PWD/qmlcppengine.h \
|
$$PWD/qmlcppengine.h \
|
||||||
$$PWD/scriptconsole.h
|
$$PWD/scriptconsole.h \
|
||||||
|
$$PWD/qscriptdebuggerclient.h \
|
||||||
|
$$PWD/qmlv8debuggerclient.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/qmlengine.cpp \
|
$$PWD/qmlengine.cpp \
|
||||||
$$PWD/qmladapter.cpp \
|
$$PWD/qmladapter.cpp \
|
||||||
$$PWD/qmldebuggerclient.cpp \
|
$$PWD/qmldebuggerclient.cpp \
|
||||||
$$PWD/qmlcppengine.cpp \
|
$$PWD/qmlcppengine.cpp \
|
||||||
$$PWD/scriptconsole.cpp
|
$$PWD/scriptconsole.cpp \
|
||||||
|
$$PWD/qscriptdebuggerclient.cpp \
|
||||||
|
$$PWD/qmlv8debuggerclient.cpp
|
||||||
|
|||||||
@@ -33,10 +33,11 @@
|
|||||||
#include "qmladapter.h"
|
#include "qmladapter.h"
|
||||||
|
|
||||||
#include "debuggerstartparameters.h"
|
#include "debuggerstartparameters.h"
|
||||||
#include "qmldebuggerclient.h"
|
#include "qscriptdebuggerclient.h"
|
||||||
|
#include "qmlv8debuggerclient.h"
|
||||||
#include "qmljsprivateapi.h"
|
#include "qmljsprivateapi.h"
|
||||||
|
|
||||||
#include "debuggerengine.h"
|
#include "qmlengine.h"
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -61,13 +62,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWeakPointer<DebuggerEngine> m_engine;
|
QWeakPointer<DebuggerEngine> m_engine;
|
||||||
Internal::QmlDebuggerClient *m_qmlClient;
|
QmlDebuggerClient *m_qmlClient;
|
||||||
|
|
||||||
QTimer m_connectionTimer;
|
QTimer m_connectionTimer;
|
||||||
int m_connectionAttempts;
|
int m_connectionAttempts;
|
||||||
int m_maxConnectionAttempts;
|
int m_maxConnectionAttempts;
|
||||||
QDeclarativeDebugConnection *m_conn;
|
QDeclarativeDebugConnection *m_conn;
|
||||||
QList<QByteArray> sendBuffer;
|
QHash<QString, QmlDebuggerClient*> debugClients;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // 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)
|
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
|
||||||
{
|
{
|
||||||
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
|
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
|
||||||
@@ -177,8 +168,10 @@ void QmlAdapter::clientStatusChanged(QDeclarativeDebugClient::Status status)
|
|||||||
|
|
||||||
logServiceStatusChange(serviceName, status);
|
logServiceStatusChange(serviceName, status);
|
||||||
|
|
||||||
if (status == QDeclarativeDebugClient::Enabled)
|
if (status == QDeclarativeDebugClient::Enabled) {
|
||||||
flushSendBuffer();
|
d->m_qmlClient = d->debugClients.value(serviceName);
|
||||||
|
d->m_qmlClient->flushSendBuffer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlAdapter::connectionStateChanged()
|
void QmlAdapter::connectionStateChanged()
|
||||||
@@ -202,7 +195,8 @@ void QmlAdapter::connectionStateChanged()
|
|||||||
showConnectionStatusMessage(tr("connected.\n"));
|
showConnectionStatusMessage(tr("connected.\n"));
|
||||||
|
|
||||||
if (!d->m_qmlClient)
|
if (!d->m_qmlClient)
|
||||||
createDebuggerClient();
|
createDebuggerClients();
|
||||||
|
|
||||||
//reloadEngines();
|
//reloadEngines();
|
||||||
emit connected();
|
emit connected();
|
||||||
break;
|
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)));
|
this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
|
||||||
connect(d->m_engine.data(), SIGNAL(sendMessage(QByteArray)),
|
|
||||||
this, SLOT(sendMessage(QByteArray)));
|
Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
|
||||||
connect(d->m_qmlClient, SIGNAL(messageWasReceived(QByteArray)),
|
connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
|
||||||
d->m_engine.data(), SLOT(messageReceived(QByteArray)));
|
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
|
//engine->startSuccessful(); // FIXME: AAA: port to new debugger states
|
||||||
}
|
}
|
||||||
@@ -243,13 +244,13 @@ QDeclarativeDebugConnection *QmlAdapter::connection() const
|
|||||||
void QmlAdapter::showConnectionStatusMessage(const QString &message)
|
void QmlAdapter::showConnectionStatusMessage(const QString &message)
|
||||||
{
|
{
|
||||||
if (!d->m_engine.isNull())
|
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)
|
void QmlAdapter::showConnectionErrorMessage(const QString &message)
|
||||||
{
|
{
|
||||||
if (!d->m_engine.isNull())
|
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)
|
bool QmlAdapter::disableJsDebugging(bool block)
|
||||||
@@ -271,6 +272,15 @@ bool QmlAdapter::disableJsDebugging(bool block)
|
|||||||
return isBlocked;
|
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,
|
void QmlAdapter::logServiceStatusChange(const QString &service,
|
||||||
QDeclarativeDebugClient::Status newStatus)
|
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);
|
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
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ public:
|
|||||||
|
|
||||||
bool disableJsDebugging(bool block);
|
bool disableJsDebugging(bool block);
|
||||||
|
|
||||||
|
Internal::QmlDebuggerClient *activeDebuggerClient();
|
||||||
|
QHash<QString, Internal::QmlDebuggerClient*> debuggerClients();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
|
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
|
||||||
void logServiceActivity(const QString &service, const QString &logMessage);
|
void logServiceActivity(const QString &service, const QString &logMessage);
|
||||||
@@ -82,7 +85,6 @@ signals:
|
|||||||
void serviceConnectionError(const QString serviceName);
|
void serviceConnectionError(const QString serviceName);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void sendMessage(const QByteArray &msg);
|
|
||||||
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
|
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||||
void clientStatusChanged(QDeclarativeDebugClient::Status status);
|
void clientStatusChanged(QDeclarativeDebugClient::Status status);
|
||||||
void connectionStateChanged();
|
void connectionStateChanged();
|
||||||
@@ -90,10 +92,9 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void connectToViewer();
|
void connectToViewer();
|
||||||
void createDebuggerClient();
|
void createDebuggerClients();
|
||||||
void showConnectionStatusMessage(const QString &message);
|
void showConnectionStatusMessage(const QString &message);
|
||||||
void showConnectionErrorMessage(const QString &message);
|
void showConnectionErrorMessage(const QString &message);
|
||||||
void flushSendBuffer();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<Internal::QmlAdapterPrivate> d;
|
QScopedPointer<Internal::QmlAdapterPrivate> d;
|
||||||
|
|||||||
@@ -37,13 +37,21 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
QmlDebuggerClient::QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client)
|
class QmlDebuggerClientPrivate
|
||||||
: QDeclarativeDebugClient(QLatin1String("JSDebugger"), client)
|
{
|
||||||
|
public:
|
||||||
|
QList<QByteArray> sendBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
QmlDebuggerClient::QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client, QLatin1String clientName)
|
||||||
|
: QDeclarativeDebugClient(clientName, client),
|
||||||
|
d(new QmlDebuggerClientPrivate())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlDebuggerClient::~QmlDebuggerClient()
|
QmlDebuggerClient::~QmlDebuggerClient()
|
||||||
{
|
{
|
||||||
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlDebuggerClient::statusChanged(Status status)
|
void QmlDebuggerClient::statusChanged(Status status)
|
||||||
@@ -51,9 +59,21 @@ void QmlDebuggerClient::statusChanged(Status status)
|
|||||||
emit newStatus(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
|
} // Internal
|
||||||
|
|||||||
@@ -30,32 +30,70 @@
|
|||||||
**
|
**
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#ifndef QMLJSDEBUGGERCLIENT_H
|
#ifndef QMLDEBUGGERCLIENT_H
|
||||||
#define QMLJSDEBUGGERCLIENT_H
|
#define QMLDEBUGGERCLIENT_H
|
||||||
|
|
||||||
#include "qmljsprivateapi.h"
|
#include "qmljsprivateapi.h"
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class WatchData;
|
||||||
|
class BreakHandler;
|
||||||
|
class BreakpointModelId;
|
||||||
|
class QmlEngine;
|
||||||
|
class QmlDebuggerClientPrivate;
|
||||||
|
|
||||||
class QmlDebuggerClient : public QDeclarativeDebugClient
|
class QmlDebuggerClient : public QDeclarativeDebugClient
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client);
|
QmlDebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client, QLatin1String clientName);
|
||||||
virtual ~QmlDebuggerClient();
|
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:
|
signals:
|
||||||
void newStatus(QDeclarativeDebugClient::Status status);
|
void newStatus(QDeclarativeDebugClient::Status status);
|
||||||
void messageWasReceived(const QByteArray &data);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void statusChanged(Status status);
|
virtual void statusChanged(Status status);
|
||||||
virtual void messageReceived(const QByteArray &data);
|
void sendMessage(const QByteArray &msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QmlDebuggerClientPrivate *d;
|
||||||
|
friend class QmlDebuggerClientPrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
} // QmlJSInspector
|
} // Debugger
|
||||||
|
|
||||||
#endif // QMLJSDEBUGGERCLIENT_H
|
#endif // QMLDEBUGGERCLIENT_H
|
||||||
|
|||||||
@@ -89,70 +89,6 @@ using namespace ProjectExplorer;
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
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
|
class QmlEnginePrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -160,7 +96,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QmlEngine;
|
friend class QmlEngine;
|
||||||
int m_ping;
|
|
||||||
QmlAdapter m_adapter;
|
QmlAdapter m_adapter;
|
||||||
ApplicationLauncher m_applicationLauncher;
|
ApplicationLauncher m_applicationLauncher;
|
||||||
Utils::FileInProjectFinder fileFinder;
|
Utils::FileInProjectFinder fileFinder;
|
||||||
@@ -168,7 +103,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
||||||
: m_ping(0), m_adapter(q)
|
: m_adapter(q)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
@@ -466,8 +401,6 @@ void QmlEngine::shutdownEngine()
|
|||||||
|
|
||||||
void QmlEngine::setupEngine()
|
void QmlEngine::setupEngine()
|
||||||
{
|
{
|
||||||
d->m_ping = 0;
|
|
||||||
|
|
||||||
connect(&d->m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
|
connect(&d->m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
|
||||||
runControl(), SLOT(bringApplicationToForeground(qint64)),
|
runControl(), SLOT(bringApplicationToForeground(qint64)),
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
@@ -478,12 +411,8 @@ void QmlEngine::setupEngine()
|
|||||||
void QmlEngine::continueInferior()
|
void QmlEngine::continueInferior()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
||||||
QByteArray reply;
|
logMessage(LogSend, "CONTINUE");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->continueInferior();
|
||||||
QByteArray cmd = "CONTINUE";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
@@ -491,23 +420,15 @@ void QmlEngine::continueInferior()
|
|||||||
|
|
||||||
void QmlEngine::interruptInferior()
|
void QmlEngine::interruptInferior()
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, "INTERRUPT");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->interruptInferior();
|
||||||
QByteArray cmd = "INTERRUPT";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
notifyInferiorStopOk();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::executeStep()
|
void QmlEngine::executeStep()
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, "STEPINTO");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->executeStep();
|
||||||
QByteArray cmd = "STEPINTO";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
@@ -515,12 +436,8 @@ void QmlEngine::executeStep()
|
|||||||
|
|
||||||
void QmlEngine::executeStepI()
|
void QmlEngine::executeStepI()
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, "STEPINTO");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->executeStepI();
|
||||||
QByteArray cmd = "STEPINTO";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
@@ -528,12 +445,8 @@ void QmlEngine::executeStepI()
|
|||||||
|
|
||||||
void QmlEngine::executeStepOut()
|
void QmlEngine::executeStepOut()
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, "STEPOUT");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->executeStepOut();
|
||||||
QByteArray cmd = "STEPOUT";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
@@ -541,12 +454,8 @@ void QmlEngine::executeStepOut()
|
|||||||
|
|
||||||
void QmlEngine::executeNext()
|
void QmlEngine::executeNext()
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, "STEPOVER");
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->executeNext();
|
||||||
QByteArray cmd = "STEPOVER";
|
|
||||||
rs << cmd;
|
|
||||||
logMessage(LogSend, cmd);
|
|
||||||
sendMessage(reply);
|
|
||||||
resetLocation();
|
resetLocation();
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
@@ -577,13 +486,8 @@ void QmlEngine::executeJumpToLine(const ContextData &data)
|
|||||||
|
|
||||||
void QmlEngine::activateFrame(int index)
|
void QmlEngine::activateFrame(int index)
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, QString("%1 %2").arg(QString("ACTIVATE_FRAME"), QString::number(index)));
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
d->m_adapter.activeDebuggerClient()->activateFrame(index);
|
||||||
QByteArray cmd = "ACTIVATE_FRAME";
|
|
||||||
rs << cmd
|
|
||||||
<< index;
|
|
||||||
logMessage(LogSend, QString("%1 %2").arg(QString(cmd), QString::number(index)));
|
|
||||||
sendMessage(reply);
|
|
||||||
gotoLocation(stackHandler()->frames().value(index));
|
gotoLocation(stackHandler()->frames().value(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,40 +506,46 @@ void QmlEngine::attemptBreakpointSynchronization()
|
|||||||
handler->setEngine(id, this);
|
handler->setEngine(id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAgentBreakpoints breakpoints;
|
QStringList breakPointsStr;
|
||||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
|
||||||
if (handler->state(id) == BreakpointRemoveRequested) {
|
if (handler->state(id) == BreakpointRemoveRequested) {
|
||||||
handler->notifyBreakpointRemoveProceeding(id);
|
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);
|
handler->notifyBreakpointRemoveOk(id);
|
||||||
} else {
|
} else {
|
||||||
if (handler->state(id) == BreakpointInsertRequested) {
|
if (handler->state(id) == BreakpointInsertRequested) {
|
||||||
handler->notifyBreakpointInsertProceeding(id);
|
handler->notifyBreakpointInsertProceeding(id);
|
||||||
}
|
}
|
||||||
JSAgentBreakpointData bp;
|
if (d->m_adapter.activeDebuggerClient())
|
||||||
bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8();
|
d->m_adapter.activeDebuggerClient()->insertBreakpoints(handler,&id);
|
||||||
bp.lineNumber = handler->lineNumber(id);
|
else {
|
||||||
bp.functionName = handler->functionName(id).toUtf8();
|
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) {
|
||||||
breakpoints.insert(bp);
|
client->insertBreakpoints(handler,&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (handler->state(id) == BreakpointInsertProceeding) {
|
if (handler->state(id) == BreakpointInsertProceeding) {
|
||||||
handler->notifyBreakpointInsertOk(id);
|
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;
|
logMessage(LogSend, QString("%1 [%2]").arg(QString("BREAKPOINTS"), breakPointsStr.join(", ")));
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
|
||||||
QByteArray cmd = "BREAKPOINTS";
|
|
||||||
rs << cmd
|
|
||||||
<< breakpoints;
|
|
||||||
|
|
||||||
QStringList breakPointsStr;
|
if (d->m_adapter.activeDebuggerClient()) {
|
||||||
foreach (const JSAgentBreakpointData &bp, breakpoints) {
|
d->m_adapter.activeDebuggerClient()->setBreakpoints();
|
||||||
breakPointsStr << QString("('%1' '%2' %3)").arg(QString(bp.functionName),
|
}
|
||||||
QString(bp.fileUrl), QString::number(bp.lineNumber));
|
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
|
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)
|
const QString &expression, const QVariant &valueV)
|
||||||
{
|
{
|
||||||
QRegExp inObject("@([0-9a-fA-F]+)->(.+)");
|
quint64 objectId = data->id;
|
||||||
if (inObject.exactMatch(expression)) {
|
if (objectId > 0 && !expression.isEmpty()) {
|
||||||
bool ok = false;
|
logMessage(LogSend, QString("%1 %2 %3 %4 %5").arg(
|
||||||
quint64 objectId = inObject.cap(1).toULongLong(&ok, 16);
|
QString("SET_PROPERTY"), QString::number(objectId), QString(expression),
|
||||||
QString property = inObject.cap(2);
|
valueV.toString()));
|
||||||
if (ok && objectId > 0 && !property.isEmpty()) {
|
d->m_adapter.activeDebuggerClient()->assignValueInDebugger(expression.toUtf8(), objectId, expression, valueV.toString());
|
||||||
QByteArray reply;
|
|
||||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
|
||||||
QByteArray cmd = "SET_PROPERTY";
|
|
||||||
rs << cmd;
|
|
||||||
rs << expression.toUtf8() << objectId << property << valueV.toString();
|
|
||||||
logMessage(LogSend, QString("%1 %2 %3 %4 %5").arg(
|
|
||||||
QString(cmd), QString::number(objectId), QString(property),
|
|
||||||
valueV.toString()));
|
|
||||||
sendMessage(reply);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,19 +612,14 @@ void QmlEngine::updateWatchData(const WatchData &data,
|
|||||||
showStatusMessage(tr("Stopped."), 5000);
|
showStatusMessage(tr("Stopped."), 5000);
|
||||||
|
|
||||||
if (!data.name.isEmpty() && data.isValueNeeded()) {
|
if (!data.name.isEmpty() && data.isValueNeeded()) {
|
||||||
QByteArray reply;
|
logMessage(LogSend, QString("%1 %2 %3").arg(QString("EXEC"), QString(data.iname),
|
||||||
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),
|
|
||||||
QString(data.name)));
|
QString(data.name)));
|
||||||
sendMessage(reply);
|
d->m_adapter.activeDebuggerClient()->updateWatchData(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.name.isEmpty() && data.isChildrenNeeded()
|
if (!data.name.isEmpty() && data.isChildrenNeeded()
|
||||||
&& watchHandler()->isExpandedIName(data.iname)) {
|
&& watchHandler()->isExpandedIName(data.iname)) {
|
||||||
expandObject(data.iname, data.id);
|
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronizeWatchers();
|
synchronizeWatchers();
|
||||||
@@ -735,39 +630,17 @@ void QmlEngine::updateWatchData(const WatchData &data,
|
|||||||
|
|
||||||
void QmlEngine::synchronizeWatchers()
|
void QmlEngine::synchronizeWatchers()
|
||||||
{
|
{
|
||||||
|
QStringList watchedExpressions = watchHandler()->watchedExpressions();
|
||||||
// send watchers list
|
// 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(
|
logMessage(LogSend, QString("%1 %2").arg(
|
||||||
QString(cmd), watchHandler()->watchedExpressions().join(", ")));
|
QString("WATCH_EXPRESSIONS"), watchedExpressions.join(", ")));
|
||||||
sendMessage(reply);
|
if (d->m_adapter.activeDebuggerClient()) {
|
||||||
}
|
d->m_adapter.activeDebuggerClient()->synchronizeWatchers(watchedExpressions);
|
||||||
|
}
|
||||||
void QmlEngine::expandObject(const QByteArray &iname, quint64 objectId)
|
else {
|
||||||
{
|
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients())
|
||||||
QByteArray reply;
|
client->synchronizeWatchers(watchedExpressions);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned QmlEngine::debuggerCapabilities() const
|
unsigned QmlEngine::debuggerCapabilities() const
|
||||||
@@ -794,209 +667,12 @@ QString QmlEngine::toFileInProject(const QUrl &fileUrl)
|
|||||||
return d->fileFinder.findFile(fileUrl);
|
return d->fileFinder.findFile(fileUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::messageReceived(const QByteArray &message)
|
void QmlEngine::inferiorSpontaneousStop()
|
||||||
{
|
{
|
||||||
QByteArray rwData = message;
|
if (state() == InferiorRunOk)
|
||||||
QDataStream stream(&rwData, QIODevice::ReadOnly);
|
notifyInferiorSpontaneousStop();
|
||||||
|
else
|
||||||
QByteArray command;
|
notifyInferiorStopOk();
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::disconnected()
|
void QmlEngine::disconnected()
|
||||||
@@ -1016,14 +692,9 @@ void QmlEngine::wrongSetupMessageBoxFinished(int result)
|
|||||||
|
|
||||||
void QmlEngine::executeDebuggerCommand(const QString& command)
|
void QmlEngine::executeDebuggerCommand(const QString& command)
|
||||||
{
|
{
|
||||||
QByteArray reply;
|
logMessage(LogSend, QString("%1 %2 %3").arg(QString("EXEC"), QString("console"),
|
||||||
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),
|
|
||||||
QString(command)));
|
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)
|
void QmlEngine::logMessage(LogDirection direction, const QString &message)
|
||||||
{
|
{
|
||||||
QString msg = "JSDebugger";
|
QString msg = "QmlDebugger";
|
||||||
if (direction == LogSend) {
|
if (direction == LogSend) {
|
||||||
msg += " sending ";
|
msg += " sending ";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ class QmlEngine : public DebuggerEngine
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum LogDirection {
|
||||||
|
LogSend,
|
||||||
|
LogReceive
|
||||||
|
};
|
||||||
|
|
||||||
QmlEngine(const DebuggerStartParameters &startParameters,
|
QmlEngine(const DebuggerStartParameters &startParameters,
|
||||||
DebuggerEngine *masterEngine);
|
DebuggerEngine *masterEngine);
|
||||||
~QmlEngine();
|
~QmlEngine();
|
||||||
@@ -62,9 +67,12 @@ public:
|
|||||||
int timeout = -1) const;
|
int timeout = -1) const;
|
||||||
void filterApplicationMessage(const QString &msg, int channel);
|
void filterApplicationMessage(const QString &msg, int channel);
|
||||||
virtual bool acceptsWatchesWhileRunning() const;
|
virtual bool acceptsWatchesWhileRunning() const;
|
||||||
|
QString toFileInProject(const QUrl &fileUrl);
|
||||||
|
void inferiorSpontaneousStop();
|
||||||
|
|
||||||
|
void logMessage(LogDirection direction, const QString &str);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void messageReceived(const QByteArray &message);
|
|
||||||
void disconnected();
|
void disconnected();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -120,7 +128,6 @@ private:
|
|||||||
unsigned int debuggerCapabilities() const;
|
unsigned int debuggerCapabilities() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendMessage(const QByteArray &msg);
|
|
||||||
void tooltipRequested(const QPoint &mousePos,
|
void tooltipRequested(const QPoint &mousePos,
|
||||||
TextEditor::ITextEditor *editor, int cursorPos);
|
TextEditor::ITextEditor *editor, int cursorPos);
|
||||||
|
|
||||||
@@ -135,9 +142,6 @@ private slots:
|
|||||||
void synchronizeWatchers();
|
void synchronizeWatchers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void expandObject(const QByteArray &iname, quint64 objectId);
|
|
||||||
void sendPing();
|
|
||||||
|
|
||||||
void closeConnection();
|
void closeConnection();
|
||||||
void startApplicationLauncher();
|
void startApplicationLauncher();
|
||||||
void stopApplicationLauncher();
|
void stopApplicationLauncher();
|
||||||
@@ -148,13 +152,6 @@ private:
|
|||||||
const QString &oldBasePath, const QString &newBasePath) const;
|
const QString &oldBasePath, const QString &newBasePath) const;
|
||||||
QString qmlImportPath() const;
|
QString qmlImportPath() const;
|
||||||
|
|
||||||
enum LogDirection {
|
|
||||||
LogSend,
|
|
||||||
LogReceive
|
|
||||||
};
|
|
||||||
void logMessage(LogDirection direction, const QString &str);
|
|
||||||
QString toFileInProject(const QUrl &fileUrl);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QmlCppEngine;
|
friend class QmlCppEngine;
|
||||||
QmlEnginePrivate *d;
|
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)
|
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
|
//there are processes running. Cannot run mine
|
||||||
appendMessage(tr("The process is already running on the device. Please first close it.\n"), Utils::ErrorMessageFormat);
|
appendMessage(tr("The process is already running on the device. Please first close it.\n"), Utils::ErrorMessageFormat);
|
||||||
finishRunControl();
|
finishRunControl();
|
||||||
@@ -367,7 +367,7 @@ void CodaRunControl::handleCreateProcess(const CodaCommandResult &result)
|
|||||||
if (ok) {
|
if (ok) {
|
||||||
if (m_codaFlags & OptionsUseDebugSession) {
|
if (m_codaFlags & OptionsUseDebugSession) {
|
||||||
if (result.values.size()) {
|
if (result.values.size()) {
|
||||||
JsonValue id = result.values.at(0).findChild("ID");
|
Json::JsonValue id = result.values.at(0).findChild("ID");
|
||||||
if (id.isValid()) {
|
if (id.isValid()) {
|
||||||
m_state = StateProcessRunning;
|
m_state = StateProcessRunning;
|
||||||
m_runningProcessId = id.data();
|
m_runningProcessId = id.data();
|
||||||
|
|||||||
@@ -77,3 +77,6 @@ FORMS += $$PWD/s60createpackagestep.ui \
|
|||||||
$$PWD/s60publishingbuildsettingspageovi.ui \
|
$$PWD/s60publishingbuildsettingspageovi.ui \
|
||||||
$$PWD/s60publishingresultspageovi.ui \
|
$$PWD/s60publishingresultspageovi.ui \
|
||||||
$$PWD/s60publishingsissettingspageovi.ui
|
$$PWD/s60publishingsissettingspageovi.ui
|
||||||
|
|
||||||
|
include(../../../shared/json/json.pri)
|
||||||
|
DEFINES += JSON_INCLUDE_PRI
|
||||||
|
|||||||
@@ -44,14 +44,13 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
//#define DEBUG_JASON
|
|
||||||
#ifdef DEBUG_JASON
|
#ifdef DEBUG_JASON
|
||||||
#define JDEBUG(s) qDebug() << s
|
#define JDEBUG(s) qDebug() << s
|
||||||
#else
|
#else
|
||||||
#define JDEBUG(s)
|
#define JDEBUG(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Coda {
|
using namespace Json;
|
||||||
|
|
||||||
static void skipSpaces(const char *&from, const char *to)
|
static void skipSpaces(const char *&from, const char *to)
|
||||||
{
|
{
|
||||||
@@ -530,11 +529,23 @@ JsonInputStream &JsonInputStream::operator<<(const QVector<QByteArray> &ba)
|
|||||||
return *this;
|
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)
|
JsonInputStream &JsonInputStream::operator<<(bool b)
|
||||||
{
|
{
|
||||||
m_target.append(b ? "true" : "false");
|
m_target.append(b ? "true" : "false");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Coda
|
|
||||||
|
|
||||||
@@ -30,18 +30,18 @@
|
|||||||
**
|
**
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#ifndef SYMBIANUTILS_JSON_H
|
#ifndef JSON_H
|
||||||
#define SYMBIANUTILS_JSON_H
|
#define JSON_H
|
||||||
|
|
||||||
#include "symbianutils_global.h"
|
#include "json_global.h"
|
||||||
|
|
||||||
#include <QtCore/QByteArray>
|
#include <QtCore/QByteArray>
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
|
|
||||||
namespace Coda {
|
namespace Json {
|
||||||
|
|
||||||
class SYMBIANUTILS_EXPORT JsonValue
|
class JSON_EXPORT JsonValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JsonValue() : m_type(Invalid) {}
|
JsonValue() : m_type(Invalid) {}
|
||||||
@@ -106,7 +106,7 @@ private:
|
|||||||
* Note that strings get double quotes and JSON-escaping, characters should be
|
* Note that strings get double quotes and JSON-escaping, characters should be
|
||||||
* used for the array/hash delimiters.
|
* used for the array/hash delimiters.
|
||||||
* */
|
* */
|
||||||
class SYMBIANUTILS_EXPORT JsonInputStream {
|
class JSON_EXPORT JsonInputStream {
|
||||||
public:
|
public:
|
||||||
explicit JsonInputStream(QByteArray &a) : m_target(a) {}
|
explicit JsonInputStream(QByteArray &a) : m_target(a) {}
|
||||||
|
|
||||||
@@ -121,6 +121,9 @@ public:
|
|||||||
// Format as array
|
// Format as array
|
||||||
JsonInputStream &operator<<(const QVector<QByteArray> &ba);
|
JsonInputStream &operator<<(const QVector<QByteArray> &ba);
|
||||||
|
|
||||||
|
//Format as array
|
||||||
|
JsonInputStream &operator<<(const QList<int> &in);
|
||||||
|
|
||||||
JsonInputStream &operator<<(bool b);
|
JsonInputStream &operator<<(bool b);
|
||||||
|
|
||||||
JsonInputStream &operator<<(int i)
|
JsonInputStream &operator<<(int i)
|
||||||
@@ -137,6 +140,6 @@ private:
|
|||||||
QByteArray &m_target;
|
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;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace Json;
|
||||||
namespace Coda {
|
namespace Coda {
|
||||||
// ------------- CodaCommandError
|
// ------------- CodaCommandError
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandError {
|
|||||||
operator bool() const { return isError(); }
|
operator bool() const { return isError(); }
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
void write(QTextStream &str) 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
|
quint64 timeMS; // Since 1.1.1970
|
||||||
qint64 code;
|
qint64 code;
|
||||||
@@ -94,7 +94,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandResult {
|
|||||||
explicit CodaCommandResult(Type t = SuccessReply);
|
explicit CodaCommandResult(Type t = SuccessReply);
|
||||||
explicit CodaCommandResult(char typeChar, Services service,
|
explicit CodaCommandResult(char typeChar, Services service,
|
||||||
const QByteArray &request,
|
const QByteArray &request,
|
||||||
const QVector<JsonValue> &values,
|
const QVector<Json::JsonValue> &values,
|
||||||
const QVariant &cookie);
|
const QVariant &cookie);
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
@@ -107,7 +107,7 @@ struct SYMBIANUTILS_EXPORT CodaCommandResult {
|
|||||||
Services service;
|
Services service;
|
||||||
QByteArray request;
|
QByteArray request;
|
||||||
CodaCommandError commandError;
|
CodaCommandError commandError;
|
||||||
QVector<JsonValue> values;
|
QVector<Json::JsonValue> values;
|
||||||
QVariant cookie;
|
QVariant cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -394,7 +394,7 @@ public:
|
|||||||
static CodaStatResponse parseStat(const CodaCommandResult &r);
|
static CodaStatResponse parseStat(const CodaCommandResult &r);
|
||||||
|
|
||||||
signals:
|
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 codaEvent(const Coda::CodaEvent &knownEvent);
|
||||||
void unknownEvent(uchar protocolId, const QByteArray& data);
|
void unknownEvent(uchar protocolId, const QByteArray& data);
|
||||||
void serialPong(const QString &codaVersion);
|
void serialPong(const QString &codaVersion);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ static const char *serviceNamesC[] =
|
|||||||
"DebugSessionControl",
|
"DebugSessionControl",
|
||||||
"UnknownService"};
|
"UnknownService"};
|
||||||
|
|
||||||
|
using namespace Json;
|
||||||
namespace Coda {
|
namespace Coda {
|
||||||
|
|
||||||
SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep)
|
SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#define CODAMESSAGE_H
|
#define CODAMESSAGE_H
|
||||||
|
|
||||||
#include "symbianutils_global.h"
|
#include "symbianutils_global.h"
|
||||||
|
#include "json_global.h"
|
||||||
|
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
@@ -42,10 +43,12 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QTextStream;
|
class QTextStream;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Coda {
|
namespace Json {
|
||||||
|
|
||||||
class JsonValue;
|
class JsonValue;
|
||||||
class JsonInputStream;
|
class JsonInputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Coda {
|
||||||
|
|
||||||
enum Services {
|
enum Services {
|
||||||
LocatorService,
|
LocatorService,
|
||||||
@@ -101,7 +104,7 @@ struct SYMBIANUTILS_EXPORT RunControlContext {
|
|||||||
unsigned threadId() const;
|
unsigned threadId() const;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
bool parse(const JsonValue &v);
|
bool parse(const Json::JsonValue &v);
|
||||||
void format(QTextStream &str) const;
|
void format(QTextStream &str) const;
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
@@ -122,7 +125,7 @@ struct SYMBIANUTILS_EXPORT RunControlContext {
|
|||||||
struct SYMBIANUTILS_EXPORT ModuleLoadEventInfo {
|
struct SYMBIANUTILS_EXPORT ModuleLoadEventInfo {
|
||||||
ModuleLoadEventInfo();
|
ModuleLoadEventInfo();
|
||||||
void clear();
|
void clear();
|
||||||
bool parse(const JsonValue &v);
|
bool parse(const Json::JsonValue &v);
|
||||||
void format(QTextStream &str) const;
|
void format(QTextStream &str) const;
|
||||||
|
|
||||||
QByteArray name;
|
QByteArray name;
|
||||||
@@ -154,7 +157,7 @@ struct SYMBIANUTILS_EXPORT Breakpoint {
|
|||||||
bool thumb;
|
bool thumb;
|
||||||
};
|
};
|
||||||
|
|
||||||
SYMBIANUTILS_EXPORT JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b);
|
Json::JsonInputStream &operator<<(Json::JsonInputStream &str, const Breakpoint &b);
|
||||||
|
|
||||||
// Event hierarchy
|
// Event hierarchy
|
||||||
class SYMBIANUTILS_EXPORT CodaEvent
|
class SYMBIANUTILS_EXPORT CodaEvent
|
||||||
@@ -179,7 +182,7 @@ public:
|
|||||||
Type type() const;
|
Type type() const;
|
||||||
virtual QString toString() 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:
|
protected:
|
||||||
explicit CodaEvent(Type type = None);
|
explicit CodaEvent(Type type = None);
|
||||||
@@ -252,7 +255,7 @@ public:
|
|||||||
const RunControlContexts &contexts() const { return m_contexts; }
|
const RunControlContexts &contexts() const { return m_contexts; }
|
||||||
virtual QString toString() const;
|
virtual QString toString() const;
|
||||||
|
|
||||||
static CodaRunControlContextAddedEvent *parseEvent(const QVector<JsonValue> &val);
|
static CodaRunControlContextAddedEvent *parseEvent(const QVector<Json::JsonValue> &val);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const RunControlContexts m_contexts;
|
const RunControlContexts m_contexts;
|
||||||
|
|||||||
@@ -10,14 +10,12 @@ HEADERS += $$PWD/symbianutils_global.h \
|
|||||||
$$PWD/symbiandevicemanager.h \
|
$$PWD/symbiandevicemanager.h \
|
||||||
$$PWD/codadevice.h \
|
$$PWD/codadevice.h \
|
||||||
$$PWD/codamessage.h \
|
$$PWD/codamessage.h \
|
||||||
$$PWD/json.h \
|
|
||||||
$$PWD/virtualserialdevice.h
|
$$PWD/virtualserialdevice.h
|
||||||
|
|
||||||
SOURCES += $$PWD/codautils.cpp \
|
SOURCES += $$PWD/codautils.cpp \
|
||||||
$$PWD/symbiandevicemanager.cpp \
|
$$PWD/symbiandevicemanager.cpp \
|
||||||
$$PWD/codadevice.cpp \
|
$$PWD/codadevice.cpp \
|
||||||
$$PWD/codamessage.cpp \
|
$$PWD/codamessage.cpp \
|
||||||
$$PWD/json.cpp \
|
|
||||||
$$PWD/virtualserialdevice.cpp
|
$$PWD/virtualserialdevice.cpp
|
||||||
|
|
||||||
DEFINES += HAS_SERIALPORT
|
DEFINES += HAS_SERIALPORT
|
||||||
@@ -25,3 +23,5 @@ win32:SOURCES += $$PWD/virtualserialdevice_win.cpp
|
|||||||
unix:SOURCES += $$PWD/virtualserialdevice_posix.cpp
|
unix:SOURCES += $$PWD/virtualserialdevice_posix.cpp
|
||||||
|
|
||||||
macx:LIBS += -framework IOKit -framework CoreFoundation
|
macx:LIBS += -framework IOKit -framework CoreFoundation
|
||||||
|
include(../../shared/json/json.pri)
|
||||||
|
DEFINES += JSON_INCLUDE_PRI
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
include(../qttest.pri)
|
include(../qttest.pri)
|
||||||
include($$IDE_SOURCE_TREE/src/libs/symbianutils/symbianutils.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
|
DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger
|
||||||
UTILSDIR = $$IDE_SOURCE_TREE/src/libs
|
UTILSDIR = $$IDE_SOURCE_TREE/src/libs
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public:
|
|||||||
|
|
||||||
void testJson(const char* input)
|
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));
|
'\n' + QString(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user