summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-05-08 11:57:47 +0200
committerKent Hansen <khansen@trolltech.com>2009-05-08 11:57:47 +0200
commit7db7c6bd5e47b6d329aba162cb1afd2d9e7b8757 (patch)
treebf65828bc7fe18b32ffc850830959b74e6463564
initialize repo
-rw-r--r--debuggee/debuggee.pro9
-rw-r--r--debuggee/example.qs17
-rw-r--r--debuggee/foo.qs5
-rw-r--r--debuggee/main.cpp110
-rw-r--r--debuggee/qscriptdebuggerconnector.cpp452
-rw-r--r--debuggee/qscriptdebuggerconnector.h54
-rw-r--r--main.cpp12
-rw-r--r--qscriptremotetargetdebugger.cpp575
-rw-r--r--qscriptremotetargetdebugger.h107
-rw-r--r--remotescriptdebugger.pro9
10 files changed, 1350 insertions, 0 deletions
diff --git a/debuggee/debuggee.pro b/debuggee/debuggee.pro
new file mode 100644
index 0000000..d4b3eed
--- /dev/null
+++ b/debuggee/debuggee.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+QT += network script scripttools
+# Input
+SOURCES += main.cpp
+SOURCES += qscriptdebuggerconnector.cpp
+HEADERS += qscriptdebuggerconnector.h
diff --git a/debuggee/example.qs b/debuggee/example.qs
new file mode 100644
index 0000000..1b545b6
--- /dev/null
+++ b/debuggee/example.qs
@@ -0,0 +1,17 @@
+function bar() {
+ var x = 1;
+ var y = 2;
+ return x + y + test(x, y);
+}
+
+function foo(a, b, c) {
+ var i = a + bar();
+ var j = b - bar();
+ var k = c * bar();
+ return Math.cos(i) + Math.sin(j) - Math.atan(k);
+}
+
+var first = foo(1, 2, 3);
+var second = foo(4, 5, 6);
+print("first was:", first, ", and second was:", second);
+
diff --git a/debuggee/foo.qs b/debuggee/foo.qs
new file mode 100644
index 0000000..c7d511a
--- /dev/null
+++ b/debuggee/foo.qs
@@ -0,0 +1,5 @@
+function test(a, b) {
+ var c = a * b;
+ var d = Math.sin(c);
+ return d + 2;
+}
diff --git a/debuggee/main.cpp b/debuggee/main.cpp
new file mode 100644
index 0000000..d1a19d7
--- /dev/null
+++ b/debuggee/main.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2007-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the Qt Script Debug project on Trolltech Labs.
+**
+** $TROLLTECH_GPL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+#include <QtScript>
+#include <qscriptdebuggerconnector.h>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+public:
+ MyObject(const QHostAddress &addr, quint16 port, bool connect, QObject *parent = 0);
+private slots:
+ void connected();
+ void disconnected();
+private:
+ QScriptEngine *m_engine;
+ QScriptDebuggerConnector *m_connector;
+};
+
+MyObject::MyObject(const QHostAddress &addr, quint16 port, bool connect, QObject *parent)
+ : QObject(parent)
+{
+ m_engine = new QScriptEngine(this);
+ m_connector = new QScriptDebuggerConnector(this);
+ QObject::connect(m_connector, SIGNAL(connected()), this, SLOT(connected()), Qt::QueuedConnection);
+ QObject::connect(m_connector, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::QueuedConnection);
+ m_connector->setEngine(m_engine);
+ if (connect) {
+ qDebug("attempting to connect to debugger at %s:%d", qPrintable(addr.toString()), port);
+ m_connector->connectToDebugger(addr, port);
+ } else {
+ if (m_connector->listen(addr, port))
+ qDebug("waiting for debugger to connect at %s:%d", qPrintable(addr.toString()), port);
+ else {
+ qWarning("Failed to listen!");
+ QCoreApplication::quit();
+ }
+ }
+}
+
+void MyObject::connected()
+{
+// qDebug("connected!!");
+ QStringList fileNames;
+ QString path = QDir::currentPath();
+ fileNames << (path + QDir::separator() + "foo.qs")
+ << (path + QDir::separator() + "example.qs");
+ for (int i = 0; i < fileNames.size(); ++i) {
+ QString fn = fileNames.at(i);
+ QFile file(fn);
+ file.open(QIODevice::ReadOnly);
+ QString program = file.readAll();
+ qDebug("calling evaluate");
+ m_engine->evaluate(program, fn);
+ qDebug("evaluate done");
+ }
+ m_connector->disconnectFromDebugger();
+}
+
+void MyObject::disconnected()
+{
+ qDebug("disconnected");
+ QCoreApplication::quit();
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QHostAddress addr(QHostAddress::LocalHost);
+ quint16 port = 2000;
+ bool connect = false;
+ for (int i = 1; i < argc; ++i) {
+ QString arg(argv[i]);
+ arg = arg.trimmed();
+ if(arg.startsWith("--")) {
+ QString opt;
+ QString val;
+ int split = arg.indexOf("=");
+ if(split > 0) {
+ opt = arg.mid(2).left(split-2);
+ val = arg.mid(split + 1).trimmed();
+ } else {
+ opt = arg.mid(2);
+ }
+ if (opt == QLatin1String("address"))
+ addr.setAddress(val);
+ else if (opt == QLatin1String("port"))
+ port = val.toUShort();
+ else if (opt == QLatin1String("connect"))
+ connect = true;
+ else if (opt == QLatin1String("help")) {
+ fprintf(stdout, "Usage: debuggee --address=ADDR --port=NUM [--connect]\n");
+ return(0);
+ }
+ }
+ }
+ MyObject obj(addr, port, connect);
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/debuggee/qscriptdebuggerconnector.cpp b/debuggee/qscriptdebuggerconnector.cpp
new file mode 100644
index 0000000..c5fbdb3
--- /dev/null
+++ b/debuggee/qscriptdebuggerconnector.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2007-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the Qt Script Debug project on Trolltech Labs.
+**
+** $TROLLTECH_GPL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qscriptdebuggerconnector.h"
+#include <QtNetwork>
+#include <QtScript>
+#include <private/qscriptdebuggerbackend_p.h>
+#include <private/qscriptdebuggercommand_p.h>
+#include <private/qscriptdebuggerevent_p.h>
+#include <private/qscriptdebuggerresponse_p.h>
+#include <private/qscriptdebuggercommandexecutor_p.h>
+#include <private/qscriptbreakpointdata_p.h>
+#include <private/qscriptdebuggerobjectsnapshotdelta_p.h>
+
+#define DEBUGGERCONNECTOR_DEBUG
+
+Q_DECLARE_METATYPE(QScriptDebuggerCommand)
+Q_DECLARE_METATYPE(QScriptDebuggerResponse)
+Q_DECLARE_METATYPE(QScriptDebuggerEvent)
+Q_DECLARE_METATYPE(QScriptContextInfo)
+Q_DECLARE_METATYPE(QScriptContextInfoList)
+Q_DECLARE_METATYPE(QScriptDebuggerValue)
+Q_DECLARE_METATYPE(QScriptDebuggerValueList)
+Q_DECLARE_METATYPE(QScriptValue::PropertyFlags)
+Q_DECLARE_METATYPE(QScriptBreakpointData)
+Q_DECLARE_METATYPE(QScriptBreakpointMap)
+Q_DECLARE_METATYPE(QScriptScriptData)
+Q_DECLARE_METATYPE(QScriptScriptMap)
+Q_DECLARE_METATYPE(QScriptScriptsDelta)
+Q_DECLARE_METATYPE(QScriptDebuggerValueProperty)
+Q_DECLARE_METATYPE(QScriptDebuggerValuePropertyList)
+Q_DECLARE_METATYPE(QScriptDebuggerObjectSnapshotDelta)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qint64>)
+
+void qScriptDebugRegisterMetaTypes()
+{
+ qMetaTypeId<QScriptDebuggerCommand>();
+ qMetaTypeId<QScriptDebuggerResponse>();
+ qMetaTypeId<QScriptDebuggerEvent>();
+ qMetaTypeId<QScriptContextInfo>();
+ qMetaTypeId<QScriptContextInfoList>();
+ qMetaTypeId<QScriptDebuggerValue>();
+ qMetaTypeId<QScriptDebuggerValueList>();
+ qMetaTypeId<QScriptValue::PropertyFlags>();
+ qMetaTypeId<QScriptBreakpointData>();
+ qMetaTypeId<QScriptBreakpointMap>();
+ qMetaTypeId<QScriptScriptData>();
+ qMetaTypeId<QScriptScriptMap>();
+ qMetaTypeId<QScriptScriptsDelta>();
+ qMetaTypeId<QScriptDebuggerValueProperty>();
+ qMetaTypeId<QScriptDebuggerValuePropertyList>();
+ qMetaTypeId<QScriptDebuggerObjectSnapshotDelta>();
+ qMetaTypeId<QList<int> >();
+ qMetaTypeId<QList<qint64> >();
+
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerCommand>("QScriptDebuggerCommand");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerResponse>("QScriptDebuggerResponse");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerEvent>("QScriptDebuggerEvent");
+ qRegisterMetaTypeStreamOperators<QScriptContextInfo>("QScriptContextInfo");
+ qRegisterMetaTypeStreamOperators<QScriptContextInfoList>("QScriptContextInfoList");
+ qRegisterMetaTypeStreamOperators<QScriptBreakpointData>("QScriptBreakpointData");
+ qRegisterMetaTypeStreamOperators<QScriptBreakpointMap>("QScriptBreakpointMap");
+ qRegisterMetaTypeStreamOperators<QScriptScriptData>("QScriptScriptData");
+ qRegisterMetaTypeStreamOperators<QScriptScriptMap>("QScriptScriptMap");
+ qRegisterMetaTypeStreamOperators<QScriptScriptsDelta>("QScriptScriptsDelta");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerValue>("QScriptDebuggerValue");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerValueList>("QScriptDebuggerValueList");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerValueProperty>("QScriptDebuggerValueProperty");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerValuePropertyList>("QScriptDebuggerValuePropertyList");
+ qRegisterMetaTypeStreamOperators<QScriptDebuggerObjectSnapshotDelta>("QScriptDebuggerObjectSnapshotDelta");
+ qRegisterMetaTypeStreamOperators<QList<int> >("QList<int>");
+ qRegisterMetaTypeStreamOperators<QList<qint64> >("QList<qint64>");
+}
+
+class QScriptRemoteTargetDebuggerBackend : public QObject,
+ public QScriptDebuggerBackend
+{
+ Q_OBJECT
+public:
+ enum Error {
+ NoError,
+ HostNotFoundError,
+ ConnectionRefusedError,
+ HandshakeError,
+ SocketError
+ };
+
+ QScriptRemoteTargetDebuggerBackend();
+ ~QScriptRemoteTargetDebuggerBackend();
+
+ void connectToDebugger(const QHostAddress &address, quint16 port);
+ void disconnectFromDebugger();
+
+ bool listen(const QHostAddress &address, quint16 port);
+
+ void resume();
+
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+ void error(Error error);
+
+protected:
+ void event(const QScriptDebuggerEvent &event);
+
+private Q_SLOTS:
+ void onSocketStateChanged(QAbstractSocket::SocketState);
+ void onSocketError(QAbstractSocket::SocketError);
+ void onReadyRead();
+ void onNewConnection();
+
+private:
+ enum State {
+ UnconnectedState,
+ HandshakingState,
+ ConnectedState
+ };
+
+private:
+ State m_state;
+ QTcpSocket *m_socket;
+ int m_blockSize;
+ QTcpServer *m_server;
+ QList<QEventLoop*> m_eventLoopPool;
+ QList<QEventLoop*> m_eventLoopStack;
+
+private:
+ Q_DISABLE_COPY(QScriptRemoteTargetDebuggerBackend)
+};
+
+QScriptRemoteTargetDebuggerBackend::QScriptRemoteTargetDebuggerBackend()
+ : m_state(UnconnectedState), m_socket(0), m_blockSize(0), m_server(0)
+{
+ qScriptDebugRegisterMetaTypes();
+}
+
+QScriptRemoteTargetDebuggerBackend::~QScriptRemoteTargetDebuggerBackend()
+{
+}
+
+void QScriptRemoteTargetDebuggerBackend::connectToDebugger(const QHostAddress &address, quint16 port)
+{
+ Q_ASSERT(m_state == UnconnectedState);
+ if (!m_socket) {
+ m_socket = new QTcpSocket(this);
+ QObject::connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(onSocketSateChanged(QAbstractSocket::SocketState)));
+ QObject::connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(onSocketError(QAbstractSocket::SocketError)));
+ QObject::connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ }
+ m_socket->connectToHost(address, port);
+}
+
+void QScriptRemoteTargetDebuggerBackend::disconnectFromDebugger()
+{
+ if (!m_socket)
+ return;
+ m_socket->disconnectFromHost();
+}
+
+bool QScriptRemoteTargetDebuggerBackend::listen(const QHostAddress &address, quint16 port)
+{
+ if (m_socket)
+ return false;
+ if (!m_server) {
+ m_server = new QTcpServer();
+ QObject::connect(m_server, SIGNAL(newConnection()),
+ this, SLOT(onNewConnection()));
+ }
+ return m_server->listen(address, port);
+}
+
+void QScriptRemoteTargetDebuggerBackend::onSocketStateChanged(QAbstractSocket::SocketState s)
+{
+ if (s == QAbstractSocket::ConnectedState) {
+ m_state = HandshakingState;
+ } else if (s == QAbstractSocket::UnconnectedState) {
+ engine()->setAgent(0);
+ m_state = UnconnectedState;
+ emit disconnected();
+ }
+}
+
+void QScriptRemoteTargetDebuggerBackend::onSocketError(QAbstractSocket::SocketError err)
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+}
+
+void QScriptRemoteTargetDebuggerBackend::onNewConnection()
+{
+ m_socket = m_server->nextPendingConnection();
+ m_server->close();
+ QObject::connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+ QObject::connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(onSocketError(QAbstractSocket::SocketError)));
+ QObject::connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ // the handshake is initiated by the debugger side, so wait for it
+ m_state = HandshakingState;
+}
+
+void QScriptRemoteTargetDebuggerBackend::onReadyRead()
+{
+ switch (m_state) {
+ case UnconnectedState:
+ Q_ASSERT(0);
+ break;
+
+ case HandshakingState: {
+ QByteArray handshakeData("QtScriptDebug-Handshake");
+ if (m_socket->bytesAvailable() == handshakeData.size()) {
+ QByteArray ba = m_socket->read(handshakeData.size());
+ if (ba == handshakeData) {
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "sending handshake reply (" << handshakeData.size() << "bytes )";
+#endif
+ m_socket->write(handshakeData);
+ // handshaking complete
+ // ### a way to specify if a break should be triggered immediately,
+ // or only if an uncaught exception is triggered
+ interruptEvaluation();
+ m_state = ConnectedState;
+ emit connected();
+ } else {
+// d->error = QScriptDebuggerConnector::HandshakeError;
+// d->errorString = QString::fromLatin1("Incorrect handshake data received");
+ m_state = UnconnectedState;
+ emit error(HandshakeError);
+ m_socket->close();
+ }
+ }
+ } break;
+
+ case ConnectedState: {
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "received data. bytesAvailable:" << m_socket->bytesAvailable();
+#endif
+ QDataStream in(m_socket);
+ in.setVersion(QDataStream::Qt_4_5);
+ if (m_blockSize == 0) {
+ if (m_socket->bytesAvailable() < (int)sizeof(quint32))
+ return;
+ in >> m_blockSize;
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << " blockSize:" << m_blockSize;
+#endif
+ }
+ if (m_socket->bytesAvailable() < m_blockSize)
+ return;
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "deserializing command";
+#endif
+ int wasAvailable = m_socket->bytesAvailable();
+ qint32 id;
+ in >> id;
+ QScriptDebuggerCommand command(QScriptDebuggerCommand::None);
+ in >> command;
+ Q_ASSERT(m_socket->bytesAvailable() == wasAvailable - m_blockSize);
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug("executing command (id=%d, type=%d)", id, command.type());
+#endif
+ QScriptDebuggerResponse response = commandExecutor()->execute(this, command);
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "serializing response";
+#endif
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_5);
+ out << (quint32)0; // reserve 4 bytes for block size
+ out << (quint8)1; // type = command response
+ out << id;
+ out << response;
+ out.device()->seek(0);
+ out << (quint32)(block.size() - sizeof(quint32));
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "writing response (" << block.size() << "bytes )" << block.toHex();
+#endif
+ m_socket->write(block);
+ m_blockSize = 0;
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "bytes available is now" << m_socket->bytesAvailable();
+#endif
+ if (m_socket->bytesAvailable() != 0)
+ QMetaObject::invokeMethod(this, "onReadyRead", Qt::QueuedConnection);
+ } break;
+
+ }
+}
+
+void QScriptRemoteTargetDebuggerBackend::resume()
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+}
+
+void QScriptRemoteTargetDebuggerBackend::event(const QScriptDebuggerEvent &event)
+{
+ if (m_state != ConnectedState)
+ return;
+ if (m_eventLoopPool.isEmpty())
+ m_eventLoopPool.append(new QEventLoop());
+ QEventLoop *eventLoop = m_eventLoopPool.takeFirst();
+ Q_ASSERT(!eventLoop->isRunning());
+ m_eventLoopStack.prepend(eventLoop);
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "serializing event of type" << event.type();
+#endif
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_5);
+ out << (quint32)0; // reserve 4 bytes for block size
+ out << (quint8)0; // type = event
+ out << event;
+ out.device()->seek(0);
+ out << (quint32)(block.size() - sizeof(quint32));
+
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug() << "writing event (" << block.size() << " bytes )";
+#endif
+ m_socket->write(block);
+
+ // run an event loop until the debugger triggers a resume
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug("entering event loop");
+#endif
+ eventLoop->exec();
+#ifdef DEBUGGERCONNECTOR_DEBUG
+ qDebug("returned from event loop");
+#endif
+
+ if (!m_eventLoopStack.isEmpty()) {
+ // the event loop was quit directly (i.e. not via resume())
+ m_eventLoopStack.takeFirst();
+ }
+ m_eventLoopPool.append(eventLoop);
+ doPendingEvaluate(/*postEvent=*/false);
+}
+
+/*!
+ Constructs a new QScriptDebuggerConnector object with the given \a
+ parent.
+*/
+QScriptDebuggerConnector::QScriptDebuggerConnector(QObject *parent)
+ : QObject(parent), m_backend(0)
+{
+}
+
+/*!
+ Destroys this QScriptDebuggerConnector.
+*/
+QScriptDebuggerConnector::~QScriptDebuggerConnector()
+{
+ delete m_backend;
+}
+
+/*!
+ Sets the \a engine that this connector will manage a connection to.
+*/
+void QScriptDebuggerConnector::setEngine(QScriptEngine *engine)
+{
+ if (m_backend) {
+ m_backend->detach();
+ } else {
+ m_backend = new QScriptRemoteTargetDebuggerBackend();
+ QObject::connect(m_backend, SIGNAL(connected()),
+ this, SIGNAL(connected()));
+ QObject::connect(m_backend, SIGNAL(disconnected()),
+ this, SIGNAL(disconnected()));
+ }
+ m_backend->attachTo(engine);
+}
+
+/*!
+ Returns the \a engine that this connector manages a connection to,
+ or 0 if no engine has been set.
+*/
+QScriptEngine *QScriptDebuggerConnector::engine() const
+{
+ if (!m_backend)
+ return 0;
+ return m_backend->engine();
+}
+
+/*!
+ Attempts to make a connection to the given \a address on the given
+ \a port.
+
+ The connected() signal is emitted when the connection has been
+ established.
+
+ \sa disconnectFromDebugger(), listen()
+*/
+void QScriptDebuggerConnector::connectToDebugger(const QHostAddress &address, quint16 port)
+{
+ if (!m_backend) {
+ qWarning("QScriptDebuggerConnector::connectToDebugger(): no engine has been set (call setEngine() first)");
+ return;
+ }
+ m_backend->connectToDebugger(address, port);
+}
+
+/*!
+ Attempts to close the connection.
+
+ The disconnected() signal is emitted when the connection has been
+ closed.
+
+ \sa connectToDebugger()
+*/
+void QScriptDebuggerConnector::disconnectFromDebugger()
+{
+ if (m_backend)
+ m_backend->disconnectFromDebugger();
+}
+
+/*!
+ Listens for an incoming connection on the given \a address and \a
+ port.
+
+ Returns true on success; otherwise returns false.
+
+ The connected() signal is emitted when a connection has been
+ established.
+
+ \sa connectToDebugger()
+*/
+bool QScriptDebuggerConnector::listen(const QHostAddress &address, quint16 port)
+{
+ if (!m_backend) {
+ qWarning("QScriptDebuggerConnector::listen(): no engine has been set (call setEngine() first)");
+ return false;
+ }
+ return m_backend->listen(address, port);
+}
+
+#include "qscriptdebuggerconnector.moc"
diff --git a/debuggee/qscriptdebuggerconnector.h b/debuggee/qscriptdebuggerconnector.h
new file mode 100644
index 0000000..b135ef5
--- /dev/null
+++ b/debuggee/qscriptdebuggerconnector.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2007-$THISYEAR$ $TROLLTECH$. All rights reserved.
+**
+** This file is part of the Qt Script Debug project on Trolltech Labs.
+**
+** $TROLLTECH_GPL_LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef QSCRIPTDEBUGGERCONNECTOR_H
+#define QSCRIPTDEBUGGERCONNECTOR_H
+
+#include <QtCore/qobject.h>
+
+#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qabstractsocket.h>
+
+class QScriptEngine;
+class QScriptRemoteTargetDebuggerBackend;
+class QScriptValue;
+class QTcpSocket;
+class QTcpServer;
+
+class QScriptDebuggerConnector : public QObject
+{
+Q_OBJECT
+public:
+ QScriptDebuggerConnector(QObject *parent = 0);
+ ~QScriptDebuggerConnector();
+
+ void setEngine(QScriptEngine *engine);
+ QScriptEngine *engine() const;
+
+ void connectToDebugger(const QHostAddress &address, quint16 port);
+ void disconnectFromDebugger();
+
+ bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
+
+signals:
+ void connected();
+ void disconnected();
+// void error(Error error);
+
+private:
+ QScriptRemoteTargetDebuggerBackend *m_backend;
+
+ Q_DISABLE_COPY(QScriptDebuggerConnector)
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..1d55979
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,12 @@
+#include <QtGui>
+#include <QtScript>
+#include <QtNetwork>
+#include "qscriptremotetargetdebugger.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QScriptRemoteTargetDebugger debugger;
+ debugger.attachTo(QHostAddress::LocalHost, 2000);
+ return app.exec();
+}
diff --git a/qscriptremotetargetdebugger.cpp b/qscriptremotetargetdebugger.cpp
new file mode 100644
index 0000000..eef37ca
--- /dev/null
+++ b/qscriptremotetargetdebugger.cpp
@@ -0,0 +1,575 @@
+#include <QtNetwork>
+#include <QtGui>
+
+#include "qscriptremotetargetdebugger.h"
+
+#include <private/qscriptdebuggerfrontend_p.h>
+#include <private/qscriptdebugger_p.h>
+#include <private/qscriptdebuggercommand_p.h>
+#include <private/qscriptdebuggerevent_p.h>
+#include <private/qscriptdebuggerresponse_p.h>
+#include <private/qscriptdebuggerwidgetfactoryinterface_p.h>
+#include <private/qscriptdebugoutputwidget_p.h>
+#include <private/qscriptdebuggerconsolewidget_p.h>
+#include <private/qscripterrorlogwidget_p.h>
+#include <private/qscriptbreakpointswidget_p.h>
+#include <private/qscriptdebuggercodewidget_p.h>
+#include <private/qscriptdebuggercodefinderwidget_p.h>
+#include <private/qscriptdebuggerstackwidget_p.h>
+#include <private/qscriptdebuggerscriptswidget_p.h>
+#include <private/qscriptdebuggerlocalswidget_p.h>
+
+namespace {
+
+class WidgetClosedNotifier : public QObject
+{
+ Q_OBJECT
+public:
+ WidgetClosedNotifier(QWidget *w, QObject *parent = 0)
+ : QObject(parent), widget(w)
+ {
+ w->installEventFilter(this);
+ }
+
+ bool eventFilter(QObject *watched, QEvent *e)
+ {
+ if (watched != widget)
+ return false;
+ if (e->type() != QEvent::Close)
+ return false;
+ emit widgetClosed();
+ return true;
+ }
+
+Q_SIGNALS:
+ void widgetClosed();
+
+private:
+ QWidget *widget;
+};
+
+} // namespace
+
+class QScriptRemoteTargetDebuggerFrontend
+ : public QObject, public QScriptDebuggerFrontend
+{
+ Q_OBJECT
+public:
+ enum Error {
+ NoError,
+ HostNotFoundError,
+ ConnectionRefusedError,
+ HandshakeError,
+ SocketError
+ };
+
+ enum State {
+ UnattachedState,
+ ConnectingState,
+ HandshakingState,
+ AttachedState,
+ DetachingState
+ };
+
+ QScriptRemoteTargetDebuggerFrontend();
+ ~QScriptRemoteTargetDebuggerFrontend();
+
+ void attachTo(const QHostAddress &address, quint16 port);
+ void detach();
+
+Q_SIGNALS:
+ void attached();
+ void detached();
+ void error(Error error);
+
+protected:
+ void processCommand(int id, const QScriptDebuggerCommand &command);
+
+private Q_SLOTS:
+ void onSocketStateChanged(QAbstractSocket::SocketState);
+ void onSocketError(QAbstractSocket::SocketError);
+ void onReadyRead();
+
+private:
+ State m_state;
+ QTcpSocket *m_socket;
+ int m_blockSize;
+
+ Q_DISABLE_COPY(QScriptRemoteTargetDebuggerFrontend)
+};
+
+QScriptRemoteTargetDebuggerFrontend::QScriptRemoteTargetDebuggerFrontend()
+ : m_state(UnattachedState), m_socket(0), m_blockSize(0)
+{
+}
+
+QScriptRemoteTargetDebuggerFrontend::~QScriptRemoteTargetDebuggerFrontend()
+{
+}
+
+void QScriptRemoteTargetDebuggerFrontend::attachTo(const QHostAddress &address, quint16 port)
+{
+ Q_ASSERT(m_state == UnattachedState);
+ if (!m_socket) {
+ m_socket = new QTcpSocket(this);
+ QObject::connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+ QObject::connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(onSocketError(QAbstractSocket::SocketError)));
+ QObject::connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ }
+ m_socket->connectToHost(address, port);
+}
+
+void QScriptRemoteTargetDebuggerFrontend::detach()
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
+}
+
+void QScriptRemoteTargetDebuggerFrontend::onSocketStateChanged(QAbstractSocket::SocketState state)
+{
+ switch (state) {
+ case QAbstractSocket::UnconnectedState:
+ m_state = UnattachedState;
+ break;
+ case QAbstractSocket::HostLookupState:
+ case QAbstractSocket::ConnectingState:
+ m_state = ConnectingState;
+ break;
+ case QAbstractSocket::ConnectedState: {
+ m_state = HandshakingState;
+ QByteArray handshakeData("QtScriptDebug-Handshake");
+ qDebug("writing handshake data");
+ m_socket->write(handshakeData);
+ } break;
+ case QAbstractSocket::BoundState:
+ break;
+ case QAbstractSocket::ClosingState:
+ Q_ASSERT(0);
+ break;
+ case QAbstractSocket::ListeningState:
+ break;
+ }
+}
+
+void QScriptRemoteTargetDebuggerFrontend::onSocketError(QAbstractSocket::SocketError error)
+{
+ Q_ASSERT(0);
+}
+
+void QScriptRemoteTargetDebuggerFrontend::onReadyRead()
+{
+ switch (m_state) {
+ case UnattachedState:
+ case ConnectingState:
+ case DetachingState:
+ Q_ASSERT(0);
+ break;
+
+ case HandshakingState: {
+ QByteArray handshakeData("QtScriptDebug-Handshake");
+ if (m_socket->bytesAvailable() >= handshakeData.size()) {
+ QByteArray ba = m_socket->read(handshakeData.size());
+ if (ba == handshakeData) {
+ qDebug("handshake ok!");
+ m_state = AttachedState;
+ QMetaObject::invokeMethod(this, "emitAttachedSignal", Qt::QueuedConnection);
+ if (m_socket->bytesAvailable() > 0)
+ QMetaObject::invokeMethod(this, "onReadyRead", Qt::QueuedConnection);
+ } else {
+// d->error = HandshakeError;
+// d->errorString = QString::fromLatin1("Incorrect handshake data received");
+ m_state = DetachingState;
+ emit error(HandshakeError);
+ m_socket->close();
+ }
+ }
+ } break;
+
+ case AttachedState: {
+ qDebug() << "got something! bytes available:" << m_socket->bytesAvailable();
+ QDataStream in(m_socket);
+ in.setVersion(QDataStream::Qt_4_5);
+ if (m_blockSize == 0) {
+ if (m_socket->bytesAvailable() < (int)sizeof(quint32))
+ return;
+ in >> m_blockSize;
+ if (m_blockSize == 512)
+ qDebug() << m_socket->readAll().toHex();
+ qDebug() << "blockSize:" << m_blockSize;
+ }
+ if (m_socket->bytesAvailable() < m_blockSize) {
+ qDebug("waiting for more...");
+ return;
+ }
+
+ int wasAvailable = m_socket->bytesAvailable();
+ quint8 type;
+ in >> type;
+ if (type == 0) {
+ // event
+ qDebug() << "deserializing event";
+ QScriptDebuggerEvent event(QScriptDebuggerEvent::None);
+ in >> event;
+ qDebug() << "notifying event of type" << event.type();
+ notifyEvent(event);
+ } else {
+ // command response
+ qDebug() << "deserializing command response";
+ qint32 id;
+ in >> id;
+ QScriptDebuggerResponse response;
+ in >> response;
+ qDebug() << "notifying command" << id << "finished";
+ notifyCommandFinished((int)id, response);
+ }
+ Q_ASSERT(m_socket->bytesAvailable() == wasAvailable - m_blockSize);
+ m_blockSize = 0;
+ qDebug() << "bytes available is now" << m_socket->bytesAvailable();
+ if (m_socket->bytesAvailable() != 0)
+ QMetaObject::invokeMethod(this, "onReadyRead", Qt::QueuedConnection);
+ } break;
+ }
+}
+
+void QScriptRemoteTargetDebuggerFrontend::processCommand(int id, const QScriptDebuggerCommand &command)
+{
+ Q_ASSERT(m_state == AttachedState);
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_5);
+ out << (quint32)0; // reserve 4 bytes for block size
+ out << (qint32)id;
+ out << command;
+ out.device()->seek(0);
+ out << (quint32)(block.size() - sizeof(quint32));
+ qDebug("writing command (id=%d, %d bytes)", id, block.size());
+ m_socket->write(block);
+}
+
+QScriptRemoteTargetDebugger::QScriptRemoteTargetDebugger(QObject *parent)
+ : QObject(parent), m_frontend(0), m_debugger(0), m_autoShow(true),
+ m_standardWindow(0)
+{
+}
+
+QScriptRemoteTargetDebugger::~QScriptRemoteTargetDebugger()
+{
+ delete m_frontend;
+ delete m_debugger;
+}
+
+void QScriptRemoteTargetDebugger::attachTo(const QHostAddress &address, quint16 port)
+{
+ createDebugger();
+ if (!m_frontend) {
+ m_frontend = new QScriptRemoteTargetDebuggerFrontend();
+ QObject::connect(m_frontend, SIGNAL(attached()), this, SIGNAL(attached()));
+ QObject::connect(m_frontend, SIGNAL(detached()), this, SIGNAL(detached()));
+ }
+ m_frontend->attachTo(address, port);
+ m_debugger->setFrontend(m_frontend);
+}
+
+void QScriptRemoteTargetDebugger::createDebugger()
+{
+ if (!m_debugger) {
+ m_debugger = new QScriptDebugger();
+ m_debugger->setWidgetFactory(this);
+ QObject::connect(m_debugger, SIGNAL(started()),
+ this, SIGNAL(evaluationResumed()));
+ QObject::connect(m_debugger, SIGNAL(stopped()),
+ this, SIGNAL(evaluationSuspended()));
+ if (m_autoShow) {
+ QObject::connect(this, SIGNAL(evaluationSuspended()),
+ this, SLOT(showStandardWindow()));
+ }
+ }
+}
+
+QMainWindow *QScriptRemoteTargetDebugger::standardWindow() const
+{
+ if (m_standardWindow)
+ return m_standardWindow;
+ if (!QApplication::instance())
+ return 0;
+ QScriptRemoteTargetDebugger *that = const_cast<QScriptRemoteTargetDebugger*>(this);
+
+ QMainWindow *win = new QMainWindow();
+ QDockWidget *scriptsDock = new QDockWidget(win);
+ scriptsDock->setObjectName(QLatin1String("qtscriptdebugger_scriptsDockWidget"));
+ scriptsDock->setWindowTitle(QObject::tr("Loaded Scripts"));
+ scriptsDock->setWidget(widget(ScriptsWidget));
+ win->addDockWidget(Qt::LeftDockWidgetArea, scriptsDock);
+
+ QDockWidget *breakpointsDock = new QDockWidget(win);
+ breakpointsDock->setObjectName(QLatin1String("qtscriptdebugger_breakpointsDockWidget"));
+ breakpointsDock->setWindowTitle(QObject::tr("Breakpoints"));
+ breakpointsDock->setWidget(widget(BreakpointsWidget));
+ win->addDockWidget(Qt::LeftDockWidgetArea, breakpointsDock);
+
+ QDockWidget *stackDock = new QDockWidget(win);
+ stackDock->setObjectName(QLatin1String("qtscriptdebugger_stackDockWidget"));
+ stackDock->setWindowTitle(QObject::tr("Stack"));
+ stackDock->setWidget(widget(StackWidget));
+ win->addDockWidget(Qt::RightDockWidgetArea, stackDock);
+
+ QDockWidget *localsDock = new QDockWidget(win);
+ localsDock->setObjectName(QLatin1String("qtscriptdebugger_localsDockWidget"));
+ localsDock->setWindowTitle(QObject::tr("Locals"));
+ localsDock->setWidget(widget(LocalsWidget));
+ win->addDockWidget(Qt::RightDockWidgetArea, localsDock);
+
+ QDockWidget *consoleDock = new QDockWidget(win);
+ consoleDock->setObjectName(QLatin1String("qtscriptdebugger_consoleDockWidget"));
+ consoleDock->setWindowTitle(QObject::tr("Console"));
+ consoleDock->setWidget(widget(ConsoleWidget));
+ win->addDockWidget(Qt::BottomDockWidgetArea, consoleDock);
+
+ QDockWidget *debugOutputDock = new QDockWidget(win);
+ debugOutputDock->setObjectName(QLatin1String("qtscriptdebugger_debugOutputDockWidget"));
+ debugOutputDock->setWindowTitle(QObject::tr("Debug Output"));
+ debugOutputDock->setWidget(widget(DebugOutputWidget));
+ win->addDockWidget(Qt::BottomDockWidgetArea, debugOutputDock);
+
+ QDockWidget *errorLogDock = new QDockWidget(win);
+ errorLogDock->setObjectName(QLatin1String("qtscriptdebugger_errorLogDockWidget"));
+ errorLogDock->setWindowTitle(QObject::tr("Error Log"));
+ errorLogDock->setWidget(widget(ErrorLogWidget));
+ win->addDockWidget(Qt::BottomDockWidgetArea, errorLogDock);
+
+ win->tabifyDockWidget(errorLogDock, debugOutputDock);
+ win->tabifyDockWidget(debugOutputDock, consoleDock);
+
+ win->addToolBar(Qt::TopToolBarArea, that->createStandardToolBar());
+
+#ifndef QT_NO_MENUBAR
+ win->menuBar()->addMenu(that->createStandardMenu(win));
+
+ QMenu *editMenu = win->menuBar()->addMenu(QObject::tr("Search"));
+ editMenu->addAction(action(FindInScriptAction));
+ editMenu->addAction(action(FindNextInScriptAction));
+ editMenu->addAction(action(FindPreviousInScriptAction));
+ editMenu->addSeparator();
+ editMenu->addAction(action(GoToLineAction));
+
+ QMenu *viewMenu = win->menuBar()->addMenu(QObject::tr("View"));
+ viewMenu->addAction(scriptsDock->toggleViewAction());
+ viewMenu->addAction(breakpointsDock->toggleViewAction());
+ viewMenu->addAction(stackDock->toggleViewAction());
+ viewMenu->addAction(localsDock->toggleViewAction());
+ viewMenu->addAction(consoleDock->toggleViewAction());
+ viewMenu->addAction(debugOutputDock->toggleViewAction());
+ viewMenu->addAction(errorLogDock->toggleViewAction());
+#endif
+
+ QWidget *central = new QWidget();
+ QVBoxLayout *vbox = new QVBoxLayout(central);
+ vbox->addWidget(widget(CodeWidget));
+ vbox->addWidget(widget(CodeFinderWidget));
+ widget(CodeFinderWidget)->hide();
+ win->setCentralWidget(central);
+
+ win->setWindowTitle(QObject::tr("Qt Script Debugger"));
+
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ QVariant geometry = settings.value(QLatin1String("Qt/scripttools/debugging/mainWindowGeometry"));
+ if (geometry.isValid())
+ win->restoreGeometry(geometry.toByteArray());
+ QVariant state = settings.value(QLatin1String("Qt/scripttools/debugging/mainWindowState"));
+ if (state.isValid())
+ win->restoreState(state.toByteArray());
+
+ WidgetClosedNotifier *closedNotifier = new WidgetClosedNotifier(win, that);
+ QObject::connect(closedNotifier, SIGNAL(widgetClosed()),
+ action(ContinueAction), SLOT(trigger()));
+
+ const_cast<QScriptRemoteTargetDebugger*>(this)->m_standardWindow = win;
+ return win;
+}
+
+void QScriptRemoteTargetDebugger::showStandardWindow()
+{
+ (void)standardWindow(); // ensure it's created
+ m_standardWindow->show();
+}
+
+QWidget *QScriptRemoteTargetDebugger::widget(DebuggerWidget widget) const
+{
+ const_cast<QScriptRemoteTargetDebugger*>(this)->createDebugger();
+ switch (widget) {
+ case ConsoleWidget: {
+ QScriptDebuggerConsoleWidgetInterface *w = m_debugger->consoleWidget();
+ if (!w) {
+ w = new QScriptDebuggerConsoleWidget();
+ m_debugger->setConsoleWidget(w);
+ }
+ return w;
+ }
+ case StackWidget: {
+ QScriptDebuggerStackWidgetInterface *w = m_debugger->stackWidget();
+ if (!w) {
+ w = new QScriptDebuggerStackWidget();
+ m_debugger->setStackWidget(w);
+ }
+ return w;
+ }
+ case ScriptsWidget: {
+ QScriptDebuggerScriptsWidgetInterface *w = m_debugger->scriptsWidget();
+ if (!w) {
+ w = new QScriptDebuggerScriptsWidget();
+ m_debugger->setScriptsWidget(w);
+ }
+ return w;
+ }
+ case LocalsWidget: {
+ QScriptDebuggerLocalsWidgetInterface *w = m_debugger->localsWidget();
+ if (!w) {
+ w = new QScriptDebuggerLocalsWidget();
+ m_debugger->setLocalsWidget(w);
+ }
+ return w;
+ }
+ case CodeWidget: {
+ QScriptDebuggerCodeWidgetInterface *w = m_debugger->codeWidget();
+ if (!w) {
+ w = new QScriptDebuggerCodeWidget();
+ m_debugger->setCodeWidget(w);
+ }
+ return w;
+ }
+ case CodeFinderWidget: {
+ QScriptDebuggerCodeFinderWidgetInterface *w = m_debugger->codeFinderWidget();
+ if (!w) {
+ w = new QScriptDebuggerCodeFinderWidget();
+ m_debugger->setCodeFinderWidget(w);
+ }
+ return w;
+ }
+ case BreakpointsWidget: {
+ QScriptBreakpointsWidgetInterface *w = m_debugger->breakpointsWidget();
+ if (!w) {
+ w = new QScriptBreakpointsWidget();
+ m_debugger->setBreakpointsWidget(w);
+ }
+ return w;
+ }
+ case DebugOutputWidget: {
+ QScriptDebugOutputWidgetInterface *w = m_debugger->debugOutputWidget();
+ if (!w) {
+ w = new QScriptDebugOutputWidget();
+ m_debugger->setDebugOutputWidget(w);
+ }
+ return w;
+ }
+ case ErrorLogWidget: {
+ QScriptErrorLogWidgetInterface *w = m_debugger->errorLogWidget();
+ if (!w) {
+ w = new QScriptErrorLogWidget();
+ m_debugger->setErrorLogWidget(w);
+ }
+ return w;
+ }
+ }
+ return 0;
+}
+
+QAction *QScriptRemoteTargetDebugger::action(DebuggerAction action) const
+{
+ QScriptRemoteTargetDebugger *that = const_cast<QScriptRemoteTargetDebugger*>(this);
+ that->createDebugger();
+ switch (action) {
+ case InterruptAction:
+ return m_debugger->interruptAction(that);
+ case ContinueAction:
+ return m_debugger->continueAction(that);
+ case StepIntoAction:
+ return m_debugger->stepIntoAction(that);
+ case StepOverAction:
+ return m_debugger->stepOverAction(that);
+ case StepOutAction:
+ return m_debugger->stepOutAction(that);
+ case RunToCursorAction:
+ return m_debugger->runToCursorAction(that);
+ case RunToNewScriptAction:
+ return m_debugger->runToNewScriptAction(that);
+ case ToggleBreakpointAction:
+ return m_debugger->toggleBreakpointAction(that);
+ case ClearDebugOutputAction:
+ return m_debugger->clearDebugOutputAction(that);
+ case ClearErrorLogAction:
+ return m_debugger->clearErrorLogAction(that);
+ case ClearConsoleAction:
+ return m_debugger->clearConsoleAction(that);
+ case FindInScriptAction:
+ return m_debugger->findInScriptAction(that);
+ case FindNextInScriptAction:
+ return m_debugger->findNextInScriptAction(that);
+ case FindPreviousInScriptAction:
+ return m_debugger->findPreviousInScriptAction(that);
+ case GoToLineAction:
+ return m_debugger->goToLineAction(that);
+ }
+ return 0;
+}
+
+QToolBar *QScriptRemoteTargetDebugger::createStandardToolBar(QWidget *parent)
+{
+ QToolBar *tb = new QToolBar(parent);
+ tb->setObjectName(QLatin1String("qtscriptdebugger_standardToolBar"));
+ tb->addAction(action(ContinueAction));
+ tb->addAction(action(InterruptAction));
+ tb->addAction(action(StepIntoAction));
+ tb->addAction(action(StepOverAction));
+ tb->addAction(action(StepOutAction));
+ tb->addAction(action(RunToCursorAction));
+ tb->addAction(action(RunToNewScriptAction));
+ tb->addSeparator();
+ tb->addAction(action(FindInScriptAction));
+ return tb;
+}
+
+QMenu *QScriptRemoteTargetDebugger::createStandardMenu(QWidget *parent)
+{
+ QMenu *menu = new QMenu(parent);
+ menu->setTitle(QObject::tr("Debug"));
+ menu->addAction(action(ContinueAction));
+ menu->addAction(action(InterruptAction));
+ menu->addAction(action(StepIntoAction));
+ menu->addAction(action(StepOverAction));
+ menu->addAction(action(StepOutAction));
+ menu->addAction(action(RunToCursorAction));
+ menu->addAction(action(RunToNewScriptAction));
+
+ menu->addSeparator();
+ menu->addAction(action(ToggleBreakpointAction));
+
+ menu->addSeparator();
+ menu->addAction(action(ClearDebugOutputAction));
+ menu->addAction(action(ClearErrorLogAction));
+ menu->addAction(action(ClearConsoleAction));
+
+ return menu;
+}
+
+QScriptDebugOutputWidgetInterface *QScriptRemoteTargetDebugger::createDebugOutputWidget()
+{
+ return new QScriptDebugOutputWidget();
+}
+
+QScriptDebuggerConsoleWidgetInterface *QScriptRemoteTargetDebugger::createConsoleWidget()
+{
+ return new QScriptDebuggerConsoleWidget();
+}
+
+QScriptErrorLogWidgetInterface *QScriptRemoteTargetDebugger::createErrorLogWidget()
+{
+ return new QScriptErrorLogWidget();
+}
+
+QScriptDebuggerCodeFinderWidgetInterface *QScriptRemoteTargetDebugger::createCodeFinderWidget()
+{
+ return new QScriptDebuggerCodeFinderWidget();
+}
+
+#include "qscriptremotetargetdebugger.moc"
diff --git a/qscriptremotetargetdebugger.h b/qscriptremotetargetdebugger.h
new file mode 100644
index 0000000..f60a709
--- /dev/null
+++ b/qscriptremotetargetdebugger.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCRIPTREMOTETARGETDEBUGGER_H
+#define QSCRIPTREMOTETARGETDEBUGGER_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qscriptdebuggerwidgetfactoryinterface_p.h>
+
+class QHostAddress;
+class QScriptDebugger;
+class QScriptRemoteTargetDebuggerFrontend;
+class QAction;
+class QWidget;
+class QMainWindow;
+class QMenu;
+class QToolBar;
+
+class QScriptRemoteTargetDebugger
+ : public QObject, private QScriptDebuggerWidgetFactoryInterface
+{
+ Q_OBJECT
+public:
+ enum DebuggerWidget {
+ ConsoleWidget,
+ StackWidget,
+ ScriptsWidget,
+ LocalsWidget,
+ CodeWidget,
+ CodeFinderWidget,
+ BreakpointsWidget,
+ DebugOutputWidget,
+ ErrorLogWidget
+ };
+
+ enum DebuggerAction {
+ InterruptAction,
+ ContinueAction,
+ StepIntoAction,
+ StepOverAction,
+ StepOutAction,
+ RunToCursorAction,
+ RunToNewScriptAction,
+ ToggleBreakpointAction,
+ ClearDebugOutputAction,
+ ClearErrorLogAction,
+ ClearConsoleAction,
+ FindInScriptAction,
+ FindNextInScriptAction,
+ FindPreviousInScriptAction,
+ GoToLineAction
+ };
+
+ QScriptRemoteTargetDebugger(QObject *parent = 0);
+ ~QScriptRemoteTargetDebugger();
+
+ void attachTo(const QHostAddress &address, quint16 port);
+ void detach();
+
+ bool autoShowStandardWindow() const;
+ void setAutoShowStandardWindow(bool autoShow);
+
+ QMainWindow *standardWindow() const;
+ QToolBar *createStandardToolBar(QWidget *parent = 0);
+ QMenu *createStandardMenu(QWidget *parent = 0);
+
+ QWidget *widget(DebuggerWidget widget) const;
+ QAction *action(DebuggerAction action) const;
+
+Q_SIGNALS:
+ void attached();
+ void detached();
+// void error(Error error);
+
+ void evaluationSuspended();
+ void evaluationResumed();
+
+private Q_SLOTS:
+ void showStandardWindow();
+
+private:
+ QScriptDebugOutputWidgetInterface *createDebugOutputWidget();
+ QScriptDebuggerConsoleWidgetInterface *createConsoleWidget();
+ QScriptErrorLogWidgetInterface *createErrorLogWidget();
+ QScriptDebuggerCodeFinderWidgetInterface *createCodeFinderWidget();
+
+ void createDebugger();
+
+private:
+ QScriptRemoteTargetDebuggerFrontend *m_frontend;
+ QScriptDebugger *m_debugger;
+ bool m_autoShow;
+ QMainWindow *m_standardWindow;
+
+ Q_DISABLE_COPY(QScriptRemoteTargetDebugger)
+};
+
+#endif
diff --git a/remotescriptdebugger.pro b/remotescriptdebugger.pro
new file mode 100644
index 0000000..a9124c9
--- /dev/null
+++ b/remotescriptdebugger.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+QT += script scripttools network
+# Input
+SOURCES += main.cpp
+SOURCES += qscriptremotetargetdebugger.cpp
+HEADERS += qscriptremotetargetdebugger.h