summaryrefslogtreecommitdiffstats
path: root/src/declarative/debugger
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/debugger')
-rw-r--r--src/declarative/debugger/debugger.pri33
-rw-r--r--src/declarative/debugger/qdeclarativedebug.h67
-rw-r--r--src/declarative/debugger/qdeclarativedebugclient.cpp292
-rw-r--r--src/declarative/debugger/qdeclarativedebugclient_p.h103
-rw-r--r--src/declarative/debugger/qdeclarativedebuggerstatus.cpp54
-rw-r--r--src/declarative/debugger/qdeclarativedebuggerstatus_p.h68
-rw-r--r--src/declarative/debugger/qdeclarativedebughelper.cpp76
-rw-r--r--src/declarative/debugger/qdeclarativedebughelper_p.h73
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver.cpp426
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver_p.h91
-rw-r--r--src/declarative/debugger/qdeclarativedebugserverconnection_p.h74
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice.cpp230
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p.h96
-rw-r--r--src/declarative/debugger/qdeclarativedebugservice_p_p.h71
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace.cpp225
-rw-r--r--src/declarative/debugger/qdeclarativedebugtrace_p.h132
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebug.cpp1068
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebug_p.h387
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebugservice.cpp747
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebugservice_p.h134
-rw-r--r--src/declarative/debugger/qdeclarativeinspectorinterface_p.h69
-rw-r--r--src/declarative/debugger/qdeclarativeinspectorservice.cpp147
-rw-r--r--src/declarative/debugger/qdeclarativeinspectorservice_p.h93
-rw-r--r--src/declarative/debugger/qjsdebuggeragent.cpp614
-rw-r--r--src/declarative/debugger/qjsdebuggeragent_p.h229
-rw-r--r--src/declarative/debugger/qjsdebugservice.cpp259
-rw-r--r--src/declarative/debugger/qjsdebugservice_p.h123
-rw-r--r--src/declarative/debugger/qpacketprotocol.cpp557
-rw-r--r--src/declarative/debugger/qpacketprotocol_p.h127
29 files changed, 6665 insertions, 0 deletions
diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri
new file mode 100644
index 00000000..c81968ee
--- /dev/null
+++ b/src/declarative/debugger/debugger.pri
@@ -0,0 +1,33 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qdeclarativedebuggerstatus.cpp \
+ $$PWD/qpacketprotocol.cpp \
+ $$PWD/qdeclarativedebugservice.cpp \
+ $$PWD/qdeclarativedebugclient.cpp \
+ $$PWD/qdeclarativeenginedebug.cpp \
+ $$PWD/qdeclarativedebugtrace.cpp \
+ $$PWD/qdeclarativedebughelper.cpp \
+ $$PWD/qdeclarativedebugserver.cpp \
+ $$PWD/qdeclarativeinspectorservice.cpp \
+ $$PWD/qjsdebuggeragent.cpp \
+ $$PWD/qjsdebugservice.cpp \
+ $$PWD/qdeclarativeenginedebugservice.cpp
+
+HEADERS += \
+ $$PWD/qdeclarativedebuggerstatus_p.h \
+ $$PWD/qpacketprotocol_p.h \
+ $$PWD/qdeclarativedebugservice_p.h \
+ $$PWD/qdeclarativedebugservice_p_p.h \
+ $$PWD/qdeclarativedebugclient_p.h \
+ $$PWD/qdeclarativeenginedebug_p.h \
+ $$PWD/qdeclarativedebugtrace_p.h \
+ $$PWD/qdeclarativedebughelper_p.h \
+ $$PWD/qdeclarativedebugserver_p.h \
+ $$PWD/qdeclarativedebugserverconnection_p.h \
+ $$PWD/qdeclarativeinspectorservice_p.h \
+ $$PWD/qdeclarativeinspectorinterface_p.h \
+ $$PWD/qjsdebuggeragent_p.h \
+ $$PWD/qjsdebugservice_p.h \
+ $$PWD/qdeclarativedebug.h \
+ $$PWD/qdeclarativeenginedebugservice_p.h
diff --git a/src/declarative/debugger/qdeclarativedebug.h b/src/declarative/debugger/qdeclarativedebug.h
new file mode 100644
index 00000000..8b0a65c2
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebug.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUG_H
+#define QDECLARATIVEDEBUG_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct Q_DECLARATIVE_EXPORT QDeclarativeDebuggingEnabler
+{
+ QDeclarativeDebuggingEnabler();
+};
+
+// Execute code in constructor before first QDeclarativeEngine is instantiated
+#if defined(QT_DECLARATIVE_DEBUG)
+static QDeclarativeDebuggingEnabler qmlEnableDebuggingHelper;
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUG_H
diff --git a/src/declarative/debugger/qdeclarativedebugclient.cpp b/src/declarative/debugger/qdeclarativedebugclient.cpp
new file mode 100644
index 00000000..9c3d8144
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugclient.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativedebugclient_p.h"
+
+#include "private/qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+const int protocolVersion = 1;
+const QString serverId = QLatin1String("QDeclarativeDebugServer");
+const QString clientId = QLatin1String("QDeclarativeDebugClient");
+
+class QDeclarativeDebugClientPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugClient)
+public:
+ QDeclarativeDebugClientPrivate();
+
+ QString name;
+ QDeclarativeDebugConnection *connection;
+};
+
+class QDeclarativeDebugConnectionPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c);
+ QDeclarativeDebugConnection *q;
+ QPacketProtocol *protocol;
+
+ bool gotHello;
+ QStringList serverPlugins;
+ QHash<QString, QDeclarativeDebugClient *> plugins;
+
+ void advertisePlugins();
+
+public Q_SLOTS:
+ void connected();
+ void readyRead();
+};
+
+QDeclarativeDebugConnectionPrivate::QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c)
+: QObject(c), q(c), protocol(0), gotHello(false)
+{
+ protocol = new QPacketProtocol(q, this);
+ QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
+ QObject::connect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+void QDeclarativeDebugConnectionPrivate::advertisePlugins()
+{
+ if (!q->isConnected())
+ return;
+
+ QPacket pack;
+ pack << serverId << 1 << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QDeclarativeDebugConnectionPrivate::connected()
+{
+ QPacket pack;
+ pack << serverId << 0 << protocolVersion << plugins.keys();
+ protocol->send(pack);
+ q->flush();
+}
+
+void QDeclarativeDebugConnectionPrivate::readyRead()
+{
+ if (!gotHello) {
+ QPacket pack = protocol->read();
+ QString name;
+
+ pack >> name;
+
+ bool validHello = false;
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+ if (op == 0) {
+ int version = -1;
+ pack >> version;
+ if (version == protocolVersion) {
+ pack >> serverPlugins;
+ validHello = true;
+ }
+ }
+ }
+
+ if (!validHello) {
+ qWarning("QDeclarativeDebugConnection: Invalid hello message");
+ QObject::disconnect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ return;
+ }
+
+ gotHello = true;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
+ if (serverPlugins.contains(iter.key()))
+ newStatus = QDeclarativeDebugClient::Enabled;
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+
+ while (protocol->packetsAvailable()) {
+ QPacket pack = protocol->read();
+ QString name;
+ pack >> name;
+
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QStringList oldServerPlugins = serverPlugins;
+ pack >> serverPlugins;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
+ for (; iter != plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
+ if (serverPlugins.contains(pluginName))
+ newStatus = QDeclarativeDebugClient::Enabled;
+
+ if (oldServerPlugins.contains(pluginName)
+ != serverPlugins.contains(pluginName)) {
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+ } else {
+ qWarning() << "QDeclarativeDebugConnection: Unknown control message id" << op;
+ }
+ } else {
+ QByteArray message;
+ pack >> message;
+
+ QHash<QString, QDeclarativeDebugClient *>::Iterator iter =
+ plugins.find(name);
+ if (iter == plugins.end()) {
+ qWarning() << "QDeclarativeDebugConnection: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent)
+: QTcpSocket(parent), d(new QDeclarativeDebugConnectionPrivate(this))
+{
+}
+
+QDeclarativeDebugConnection::~QDeclarativeDebugConnection()
+{
+ QHash<QString, QDeclarativeDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ iter.value()->d_func()->connection = 0;
+ iter.value()->statusChanged(QDeclarativeDebugClient::NotConnected);
+ }
+}
+
+bool QDeclarativeDebugConnection::isConnected() const
+{
+ return state() == ConnectedState;
+}
+
+QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate()
+: connection(0)
+{
+}
+
+QDeclarativeDebugClient::QDeclarativeDebugClient(const QString &name,
+ QDeclarativeDebugConnection *parent)
+: QObject(*(new QDeclarativeDebugClientPrivate), parent)
+{
+ Q_D(QDeclarativeDebugClient);
+ d->name = name;
+ d->connection = parent;
+
+ if (!d->connection)
+ return;
+
+ if (d->connection->d->plugins.contains(name)) {
+ qWarning() << "QDeclarativeDebugClient: Conflicting plugin name" << name;
+ d->connection = 0;
+ } else {
+ d->connection->d->plugins.insert(name, this);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QDeclarativeDebugClient::~QDeclarativeDebugClient()
+{
+ Q_D(const QDeclarativeDebugClient);
+ if (d->connection && d->connection->d) {
+ d->connection->d->plugins.remove(d->name);
+ d->connection->d->advertisePlugins();
+ }
+}
+
+QString QDeclarativeDebugClient::name() const
+{
+ Q_D(const QDeclarativeDebugClient);
+ return d->name;
+}
+
+QDeclarativeDebugClient::Status QDeclarativeDebugClient::status() const
+{
+ Q_D(const QDeclarativeDebugClient);
+ if (!d->connection
+ || !d->connection->isConnected()
+ || !d->connection->d->gotHello)
+ return NotConnected;
+
+ if (d->connection->d->serverPlugins.contains(d->name))
+ return Enabled;
+
+ return Unavailable;
+}
+
+void QDeclarativeDebugClient::sendMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugClient);
+
+ if (status() != Enabled)
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->connection->d->protocol->send(pack);
+ d->connection->d->q->flush();
+}
+
+void QDeclarativeDebugClient::statusChanged(Status)
+{
+}
+
+void QDeclarativeDebugClient::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativedebugclient.moc>
diff --git a/src/declarative/debugger/qdeclarativedebugclient_p.h b/src/declarative/debugger/qdeclarativedebugclient_p.h
new file mode 100644
index 00000000..ea099fe2
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugclient_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGCLIENT_H
+#define QDECLARATIVEDEBUGCLIENT_H
+
+#include <QtNetwork/qtcpsocket.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugConnectionPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugConnection : public QTcpSocket
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QDeclarativeDebugConnection)
+public:
+ QDeclarativeDebugConnection(QObject * = 0);
+ ~QDeclarativeDebugConnection();
+
+ bool isConnected() const;
+private:
+ QDeclarativeDebugConnectionPrivate *d;
+ friend class QDeclarativeDebugClient;
+ friend class QDeclarativeDebugClientPrivate;
+};
+
+class QDeclarativeDebugClientPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugClient : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugClient)
+ Q_DISABLE_COPY(QDeclarativeDebugClient)
+
+public:
+ enum Status { NotConnected, Unavailable, Enabled };
+
+ QDeclarativeDebugClient(const QString &, QDeclarativeDebugConnection *parent);
+ ~QDeclarativeDebugClient();
+
+ QString name() const;
+
+ Status status() const;
+
+ void sendMessage(const QByteArray &);
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QDeclarativeDebugConnection;
+ friend class QDeclarativeDebugConnectionPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGCLIENT_H
diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus.cpp b/src/declarative/debugger/qdeclarativedebuggerstatus.cpp
new file mode 100644
index 00000000..2e2f4f5b
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebuggerstatus.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativedebuggerstatus_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeDebuggerStatus::~QDeclarativeDebuggerStatus()
+{
+}
+
+void QDeclarativeDebuggerStatus::setSelectedState(bool)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus_p.h b/src/declarative/debugger/qdeclarativedebuggerstatus_p.h
new file mode 100644
index 00000000..0404e0f8
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebuggerstatus_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGGERSTATUS_P_H
+#define QDECLARATIVEDEBUGGERSTATUS_P_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebuggerStatus
+{
+public:
+ virtual ~QDeclarativeDebuggerStatus();
+
+ virtual void setSelectedState(bool);
+};
+Q_DECLARE_INTERFACE(QDeclarativeDebuggerStatus, "com.trolltech.qml.QDeclarativeDebuggerStatus")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLMDEBUGGERSTATUS_P_H
diff --git a/src/declarative/debugger/qdeclarativedebughelper.cpp b/src/declarative/debugger/qdeclarativedebughelper.cpp
new file mode 100644
index 00000000..1a460bfb
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebughelper.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtScript/QScriptEngine>
+
+#include "private/qdeclarativedebughelper_p.h"
+
+#include <QtCore/QAbstractAnimation>
+#include <QtScript/QScriptEngine>
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qabstractanimation_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QScriptEngine *QDeclarativeDebugHelper::getScriptEngine(QDeclarativeEngine *engine)
+{
+ return QDeclarativeEnginePrivate::getScriptEngine(engine);
+}
+
+void QDeclarativeDebugHelper::setAnimationSlowDownFactor(qreal factor)
+{
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setSlowModeEnabled(factor != 1.0);
+ timer->setSlowdownFactor(factor);
+}
+
+void QDeclarativeDebugHelper::enableDebugging() {
+#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL
+ if (!QDeclarativeEnginePrivate::qml_debugging_enabled) {
+ qWarning("Qml debugging is enabled. Only use this in a safe environment!");
+ }
+ QDeclarativeEnginePrivate::qml_debugging_enabled = true;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebughelper_p.h b/src/declarative/debugger/qdeclarativedebughelper_p.h
new file mode 100644
index 00000000..93370982
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebughelper_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGHELPER_P_H
+#define QDECLARATIVEDEBUGHELPER_P_H
+
+#include <QtCore/qglobal.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QScriptEngine;
+class QDeclarativeEngine;
+
+// Helper methods to access private API through a stable interface
+// This is used in the qmljsdebugger library of QtCreator.
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
+{
+public:
+ static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static void setAnimationSlowDownFactor(qreal factor);
+
+ // Enables remote debugging functionality
+ // Only use this for debugging in a safe environment!
+ static void enableDebugging();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGHELPER_P_H
diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp
new file mode 100644
index 00000000..c664f960
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserver.cpp
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativedebugserver_p.h"
+#include "private/qdeclarativedebugservice_p.h"
+#include "private/qdeclarativedebugservice_p_p.h"
+#include "private/qdeclarativeengine_p.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QStringList>
+
+#include <private/qobject_p.h>
+#include <private/qapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QDeclarativeDebug Protocol (Version 1):
+
+ handshake:
+ 1. Client sends
+ "QDeclarativeDebugServer" 0 version pluginNames
+ version: an int representing the highest protocol version the client knows
+ pluginNames: plugins available on client side
+ 2. Server sends
+ "QDeclarativeDebugClient" 0 version pluginNames
+ version: an int representing the highest protocol version the client & server know
+ pluginNames: plugins available on server side. plugins both in the client and server message are enabled.
+ client plugin advertisement
+ 1. Client sends
+ "QDeclarativeDebugServer" 1 pluginNames
+ server plugin advertisement
+ 1. Server sends
+ "QDeclarativeDebugClient" 1 pluginNames
+ plugin communication:
+ Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin.
+ */
+
+const int protocolVersion = 1;
+
+
+class QDeclarativeDebugServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugServer)
+public:
+ QDeclarativeDebugServerPrivate();
+
+ void advertisePlugins();
+
+ QDeclarativeDebugServerConnection *connection;
+ QHash<QString, QDeclarativeDebugService *> plugins;
+ QStringList clientPlugins;
+ bool gotHello;
+ QString waitingForMsgFromService;
+ bool waitingForMsgSucceeded;
+
+private:
+ // private slot
+ void _q_deliverMessage(const QString &serviceName, const QByteArray &message);
+ static QDeclarativeDebugServerConnection *loadConnectionPlugin(QPluginLoader *loader, const QString &pluginName);
+};
+
+QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() :
+ connection(0),
+ gotHello(false),
+ waitingForMsgSucceeded(false)
+{
+}
+
+void QDeclarativeDebugServerPrivate::advertisePlugins()
+{
+ if (!gotHello)
+ return;
+
+ QByteArray message;
+ {
+ QDataStream out(&message, QIODevice::WriteOnly);
+ out << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys();
+ }
+ connection->send(message);
+}
+
+QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin(
+ QPluginLoader *loader, const QString &pluginName)
+{
+#ifndef QT_NO_LIBRARY
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists()) {
+ QStringList plugins(dir.entryList(QDir::Files));
+ foreach (const QString &pluginPath, plugins) {
+ if (QFileInfo(pluginPath).fileName().contains(pluginName))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+ }
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ loader->setFileName(pluginPath);
+ if (!loader->load()) {
+ continue;
+ }
+ QDeclarativeDebugServerConnection *connection = 0;
+ if (QObject *instance = loader->instance())
+ connection = qobject_cast<QDeclarativeDebugServerConnection*>(instance);
+
+ if (connection)
+ return connection;
+ loader->unload();
+ }
+#endif
+ return 0;
+}
+
+bool QDeclarativeDebugServer::hasDebuggingClient() const
+{
+ Q_D(const QDeclarativeDebugServer);
+ return d->connection
+ && d->connection->isConnected()
+ && d->gotHello;
+}
+
+QDeclarativeDebugServer *QDeclarativeDebugServer::instance()
+{
+ static bool commandLineTested = false;
+ static QDeclarativeDebugServer *server = 0;
+
+ if (!commandLineTested) {
+ commandLineTested = true;
+
+ QApplicationPrivate *appD = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp));
+#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL
+ // ### remove port definition when protocol is changed
+ int port = 0;
+ bool block = false;
+ bool ok = false;
+
+ // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block]
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ if (!QDeclarativeEnginePrivate::qml_debugging_enabled) {
+ qWarning() << QString::fromLatin1(
+ "QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Debugging has not been enabled.").arg(
+ appD->qmljsDebugArgumentsString());
+ return 0;
+ }
+
+ QString pluginName;
+ if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) {
+ int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(','));
+ port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok);
+ pluginName = QLatin1String("qmldbg_tcp");
+ } else if (appD->qmljsDebugArgumentsString().contains(QLatin1String("ost"))) {
+ pluginName = QLatin1String("qmldbg_ost");
+ ok = true;
+ }
+
+ block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block"));
+
+ if (ok) {
+ server = new QDeclarativeDebugServer();
+
+ QPluginLoader *loader = new QPluginLoader(server);
+ QDeclarativeDebugServerConnection *connection
+ = QDeclarativeDebugServerPrivate::loadConnectionPlugin(loader, pluginName);
+ if (connection) {
+ server->d_func()->connection = connection;
+
+ connection->setServer(server);
+ connection->setPort(port, block);
+ } else {
+ qWarning() << QString::fromLatin1(
+ "QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Remote debugger plugin has not been found.").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+
+ } else {
+ qWarning() << QString::fromLatin1(
+ "QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "Format is -qmljsdebugger=port:<port>[,block]").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+ }
+#else
+ if (!appD->qmljsDebugArgumentsString().isEmpty()) {
+ qWarning() << QString::fromLatin1(
+ "QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". "
+ "QtDeclarative is not configured for debugging.").arg(
+ appD->qmljsDebugArgumentsString());
+ }
+#endif
+ }
+
+ return server;
+}
+
+QDeclarativeDebugServer::QDeclarativeDebugServer()
+: QObject(*(new QDeclarativeDebugServerPrivate))
+{
+}
+
+void QDeclarativeDebugServer::receiveMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugServer);
+
+ QDataStream in(message);
+ if (!d->gotHello) {
+ QString name;
+ int op;
+ in >> name >> op;
+
+ if (name != QLatin1String("QDeclarativeDebugServer")
+ || op != 0) {
+ qWarning("QDeclarativeDebugServer: Invalid hello message");
+ d->connection->disconnect();
+ return;
+ }
+
+ int version;
+ in >> version >> d->clientPlugins;
+
+ // Send the hello answer immediately, since it needs to arrive before
+ // the plugins below start sending messages.
+ QByteArray helloAnswer;
+ {
+ QDataStream out(&helloAnswer, QIODevice::WriteOnly);
+ out << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys();
+ }
+ d->connection->send(helloAnswer);
+
+ d->gotHello = true;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(iter.key()))
+ newStatus = QDeclarativeDebugService::Enabled;
+ iter.value()->d_func()->status = newStatus;
+ iter.value()->statusChanged(newStatus);
+ }
+
+ qDebug("QDeclarativeDebugServer: Connection established");
+ } else {
+
+ QString debugServer(QLatin1String("QDeclarativeDebugServer"));
+
+ QString name;
+ in >> name;
+
+ if (name == debugServer) {
+ int op = -1;
+ in >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QStringList oldClientPlugins = d->clientPlugins;
+ in >> d->clientPlugins;
+
+ QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(pluginName))
+ newStatus = QDeclarativeDebugService::Enabled;
+
+ if (oldClientPlugins.contains(pluginName)
+ != d->clientPlugins.contains(pluginName)) {
+ iter.value()->d_func()->status = newStatus;
+ iter.value()->statusChanged(newStatus);
+ }
+ }
+ } else {
+ qWarning("QDeclarativeDebugServer: Invalid control message %d", op);
+ }
+ } else {
+ QByteArray message;
+ in >> message;
+
+ if (d->waitingForMsgFromService == name) {
+ // deliver directly so that it is delivered before waitForMessage is returning.
+ d->_q_deliverMessage(name, message);
+ d->waitingForMsgSucceeded = true;
+ } else {
+ // deliver message in next event loop run.
+ // Fixes the case that the service does start it's own event loop ...,
+ // but the networking code doesn't deliver any new messages because readyRead
+ // hasn't returned.
+ QMetaObject::invokeMethod(this, "_q_deliverMessage", Qt::QueuedConnection,
+ Q_ARG(QString, name),
+ Q_ARG(QByteArray, message));
+ }
+ }
+ }
+}
+
+void QDeclarativeDebugServerPrivate::_q_deliverMessage(const QString &serviceName, const QByteArray &message)
+{
+ QHash<QString, QDeclarativeDebugService *>::Iterator iter = plugins.find(serviceName);
+ if (iter == plugins.end()) {
+ qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << serviceName;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+}
+
+QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const
+{
+ const Q_D(QDeclarativeDebugServer);
+ return d->plugins.values();
+}
+
+QStringList QDeclarativeDebugServer::serviceNames() const
+{
+ const Q_D(QDeclarativeDebugServer);
+ return d->plugins.keys();
+}
+
+bool QDeclarativeDebugServer::addService(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+ if (!service || d->plugins.contains(service->name()))
+ return false;
+
+ d->plugins.insert(service->name(), service);
+ d->advertisePlugins();
+
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable;
+ if (d->clientPlugins.contains(service->name()))
+ newStatus = QDeclarativeDebugService::Enabled;
+ service->d_func()->status = newStatus;
+ service->statusChanged(newStatus);
+ return true;
+}
+
+bool QDeclarativeDebugServer::removeService(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+ if (!service || !d->plugins.contains(service->name()))
+ return false;
+
+ d->plugins.remove(service->name());
+ d->advertisePlugins();
+
+ QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected;
+ service->d_func()->server = 0;
+ service->d_func()->status = newStatus;
+ service->statusChanged(newStatus);
+ return true;
+}
+
+void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service,
+ const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugServer);
+ QByteArray msg;
+ {
+ QDataStream out(&msg, QIODevice::WriteOnly);
+ out << service->name() << message;
+ }
+ d->connection->send(msg);
+}
+
+bool QDeclarativeDebugServer::waitForMessage(QDeclarativeDebugService *service)
+{
+ Q_D(QDeclarativeDebugServer);
+
+ if (!service
+ || !d->plugins.contains(service->name())
+ || !d->waitingForMsgFromService.isEmpty())
+ return false;
+
+ d->waitingForMsgFromService = service->name();
+
+ do {
+ d->connection->waitForMessage();
+ } while (!d->waitingForMsgSucceeded);
+ d->waitingForMsgSucceeded = false;
+ d->waitingForMsgFromService.clear();
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdeclarativedebugserver_p.cpp"
diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h
new file mode 100644
index 00000000..922f981d
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserver_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGSERVER_H
+#define QDECLARATIVEDEBUGSERVER_H
+
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativedebugserverconnection_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugService;
+
+class QDeclarativeDebugServerPrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugServer)
+ Q_DISABLE_COPY(QDeclarativeDebugServer)
+public:
+ static QDeclarativeDebugServer *instance();
+
+ void setConnection(QDeclarativeDebugServerConnection *connection);
+
+ bool hasDebuggingClient() const;
+
+ QList<QDeclarativeDebugService*> services() const;
+ QStringList serviceNames() const;
+
+ bool addService(QDeclarativeDebugService *service);
+ bool removeService(QDeclarativeDebugService *service);
+
+ void sendMessage(QDeclarativeDebugService *service, const QByteArray &message);
+ void receiveMessage(const QByteArray &message);
+
+ bool waitForMessage(QDeclarativeDebugService *service);
+
+private:
+ friend class QDeclarativeDebugService;
+ friend class QDeclarativeDebugServicePrivate;
+ QDeclarativeDebugServer();
+ Q_PRIVATE_SLOT(d_func(), void _q_deliverMessage(QString, QByteArray))
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_H
diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
new file mode 100644
index 00000000..16fa798e
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGSERVERCONNECTION_H
+#define QDECLARATIVEDEBUGSERVERCONNECTION_H
+
+#include <QtDeclarative/private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServer;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugServerConnection
+{
+public:
+ QDeclarativeDebugServerConnection() {}
+ virtual ~QDeclarativeDebugServerConnection() {}
+
+ virtual void setServer(QDeclarativeDebugServer *server) = 0;
+ virtual void setPort(int port, bool bock) = 0;
+ virtual bool isConnected() const = 0;
+ virtual void send(const QByteArray &message) = 0;
+ virtual void disconnect() = 0;
+ virtual bool waitForMessage() = 0;
+};
+
+Q_DECLARE_INTERFACE(QDeclarativeDebugServerConnection, "com.trolltech.Qt.QDeclarativeDebugServerConnection/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVERCONNECTION_H
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp
new file mode 100644
index 00000000..111bd24c
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativedebugservice_p.h"
+#include "private/qdeclarativedebugservice_p_p.h"
+#include "private/qdeclarativedebugserver_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeDebugServicePrivate::QDeclarativeDebugServicePrivate()
+: server(0)
+{
+}
+
+QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject *parent)
+: QObject(*(new QDeclarativeDebugServicePrivate), parent)
+{
+ Q_D(QDeclarativeDebugService);
+ d->name = name;
+ d->server = QDeclarativeDebugServer::instance();
+ d->status = QDeclarativeDebugService::NotConnected;
+
+ if (!d->server)
+ return;
+
+ if (d->server->serviceNames().contains(name)) {
+ qWarning() << "QDeclarativeDebugService: Conflicting plugin name" << name;
+ d->server = 0;
+ } else {
+ d->server->addService(this);
+ }
+}
+
+QDeclarativeDebugService::~QDeclarativeDebugService()
+{
+ Q_D(const QDeclarativeDebugService);
+ if (d->server) {
+ d->server->removeService(this);
+ }
+}
+
+QString QDeclarativeDebugService::name() const
+{
+ Q_D(const QDeclarativeDebugService);
+ return d->name;
+}
+
+QDeclarativeDebugService::Status QDeclarativeDebugService::status() const
+{
+ Q_D(const QDeclarativeDebugService);
+ return d->status;
+}
+
+namespace {
+
+ struct ObjectReference
+ {
+ QPointer<QObject> object;
+ int id;
+ };
+
+ struct ObjectReferenceHash
+ {
+ ObjectReferenceHash() : nextId(0) {}
+
+ QHash<QObject *, ObjectReference> objects;
+ QHash<int, QObject *> ids;
+
+ int nextId;
+ };
+
+}
+Q_GLOBAL_STATIC(ObjectReferenceHash, objectReferenceHash);
+
+
+/*!
+ Returns a unique id for \a object. Calling this method multiple times
+ for the same object will return the same id.
+*/
+int QDeclarativeDebugService::idForObject(QObject *object)
+{
+ if (!object)
+ return -1;
+
+ ObjectReferenceHash *hash = objectReferenceHash();
+ QHash<QObject *, ObjectReference>::Iterator iter =
+ hash->objects.find(object);
+
+ if (iter == hash->objects.end()) {
+ int id = hash->nextId++;
+
+ hash->ids.insert(id, object);
+ iter = hash->objects.insert(object, ObjectReference());
+ iter->object = object;
+ iter->id = id;
+ } else if (iter->object != object) {
+ int id = hash->nextId++;
+
+ hash->ids.remove(iter->id);
+
+ hash->ids.insert(id, object);
+ iter->object = object;
+ iter->id = id;
+ }
+ return iter->id;
+}
+
+/*!
+ Returns the object for unique \a id. If the object has not previously been
+ assigned an id, through idForObject(), then 0 is returned. If the object
+ has been destroyed, 0 is returned.
+*/
+QObject *QDeclarativeDebugService::objectForId(int id)
+{
+ ObjectReferenceHash *hash = objectReferenceHash();
+
+ QHash<int, QObject *>::Iterator iter = hash->ids.find(id);
+ if (iter == hash->ids.end())
+ return 0;
+
+
+ QHash<QObject *, ObjectReference>::Iterator objIter =
+ hash->objects.find(*iter);
+ Q_ASSERT(objIter != hash->objects.end());
+
+ if (objIter->object == 0) {
+ hash->ids.erase(iter);
+ hash->objects.erase(objIter);
+ return 0;
+ } else {
+ return *iter;
+ }
+}
+
+bool QDeclarativeDebugService::isDebuggingEnabled()
+{
+ return QDeclarativeDebugServer::instance() != 0;
+}
+
+bool QDeclarativeDebugService::hasDebuggingClient()
+{
+ return QDeclarativeDebugServer::instance() != 0
+ && QDeclarativeDebugServer::instance()->hasDebuggingClient();
+}
+
+QString QDeclarativeDebugService::objectToString(QObject *obj)
+{
+ if(!obj)
+ return QLatin1String("NULL");
+
+ QString objectName = obj->objectName();
+ if(objectName.isEmpty())
+ objectName = QLatin1String("<unnamed>");
+
+ QString rv = QString::fromUtf8(obj->metaObject()->className()) +
+ QLatin1String(": ") + objectName;
+
+ return rv;
+}
+
+void QDeclarativeDebugService::sendMessage(const QByteArray &message)
+{
+ Q_D(QDeclarativeDebugService);
+
+ if (status() != Enabled)
+ return;
+
+ d->server->sendMessage(this, message);
+}
+
+bool QDeclarativeDebugService::waitForMessage()
+{
+ Q_D(QDeclarativeDebugService);
+
+ if (status() != Enabled)
+ return false;
+
+ return d->server->waitForMessage(this);
+}
+
+void QDeclarativeDebugService::statusChanged(Status)
+{
+}
+
+void QDeclarativeDebugService::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h
new file mode 100644
index 00000000..2abef713
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGSERVICE_H
+#define QDECLARATIVEDEBUGSERVICE_H
+
+#include <QtCore/qobject.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServicePrivate;
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugService : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeDebugService)
+ Q_DISABLE_COPY(QDeclarativeDebugService)
+
+public:
+ explicit QDeclarativeDebugService(const QString &, QObject *parent = 0);
+ ~QDeclarativeDebugService();
+
+ QString name() const;
+
+ enum Status { NotConnected, Unavailable, Enabled };
+ Status status() const;
+
+ void sendMessage(const QByteArray &);
+ bool waitForMessage();
+
+ static int idForObject(QObject *);
+ static QObject *objectForId(int);
+
+ static QString objectToString(QObject *obj);
+
+ static bool isDebuggingEnabled();
+ static bool hasDebuggingClient();
+
+protected:
+ virtual void statusChanged(Status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QDeclarativeDebugServer;
+ friend class QDeclarativeDebugServerPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_H
+
diff --git a/src/declarative/debugger/qdeclarativedebugservice_p_p.h b/src/declarative/debugger/qdeclarativedebugservice_p_p.h
new file mode 100644
index 00000000..1a169334
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugservice_p_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGSERVICE_P_H
+#define QDECLARATIVEDEBUGSERVICE_P_H
+
+#include <QtCore/qglobal.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugServer;
+
+class QDeclarativeDebugServicePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeDebugService)
+public:
+ QDeclarativeDebugServicePrivate();
+
+ QString name;
+ QDeclarativeDebugServer *server;
+ QDeclarativeDebugService::Status status;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGSERVICE_P_H
diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp
new file mode 100644
index 00000000..16e6dfb1
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativedebugtrace_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qtimer.h>
+
+Q_GLOBAL_STATIC(QDeclarativeDebugTrace, traceInstance);
+
+// convert to a QByteArray that can be sent to the debug client
+// use of QDataStream can skew results if m_deferredSend == false
+// (see tst_qperformancetimer::trace() benchmark)
+QByteArray QDeclarativeDebugData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << time << messageType << detailType;
+ if (messageType == (int)QDeclarativeDebugTrace::RangeData)
+ ds << detailData;
+ if (messageType == (int)QDeclarativeDebugTrace::RangeLocation)
+ ds << detailData << line;
+ return data;
+}
+
+QDeclarativeDebugTrace::QDeclarativeDebugTrace()
+: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")),
+ m_enabled(false), m_deferredSend(true), m_messageReceived(false)
+{
+ m_timer.start();
+ if (status() == Enabled) {
+ // wait for first message indicating whether to trace or not
+ while (!m_messageReceived)
+ waitForMessage();
+ }
+}
+
+void QDeclarativeDebugTrace::addEvent(EventType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->addEventImpl(t);
+}
+
+void QDeclarativeDebugTrace::startRange(RangeType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->startRangeImpl(t);
+}
+
+void QDeclarativeDebugTrace::rangeData(RangeType t, const QString &data)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeDataImpl(t, data);
+}
+
+void QDeclarativeDebugTrace::rangeData(RangeType t, const QUrl &data)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeDataImpl(t, data);
+}
+
+void QDeclarativeDebugTrace::rangeLocation(RangeType t, const QString &fileName, int line)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeLocationImpl(t, fileName, line);
+}
+
+void QDeclarativeDebugTrace::rangeLocation(RangeType t, const QUrl &fileName, int line)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->rangeLocationImpl(t, fileName, line);
+}
+
+void QDeclarativeDebugTrace::endRange(RangeType t)
+{
+ if (QDeclarativeDebugService::isDebuggingEnabled())
+ traceInstance()->endRangeImpl(t);
+}
+
+void QDeclarativeDebugTrace::addEventImpl(EventType event)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData ed = {m_timer.elapsed(), (int)Event, (int)event, QString(), -1};
+ processMessage(ed);
+}
+
+void QDeclarativeDebugTrace::startRangeImpl(RangeType range)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeStart, (int)range, QString(), -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData, -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QUrl &rData)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeLocationImpl(RangeType range, const QString &fileName, int line)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeLocation, (int)range, fileName, line};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::rangeLocationImpl(RangeType range, const QUrl &fileName, int line)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line};
+ processMessage(rd);
+}
+
+void QDeclarativeDebugTrace::endRangeImpl(RangeType range)
+{
+ if (status() != Enabled || !m_enabled)
+ return;
+
+ QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeEnd, (int)range, QString(), -1};
+ processMessage(rd);
+}
+
+/*
+ Either send the message directly, or queue up
+ a list of messages to send later (via sendMessages)
+*/
+void QDeclarativeDebugTrace::processMessage(const QDeclarativeDebugData &message)
+{
+ if (m_deferredSend)
+ m_data.append(message);
+ else
+ sendMessage(message.toByteArray());
+}
+
+/*
+ Send the messages queued up by processMessage
+*/
+void QDeclarativeDebugTrace::sendMessages()
+{
+ if (m_deferredSend) {
+ //### this is a suboptimal way to send batched messages
+ for (int i = 0; i < m_data.count(); ++i)
+ sendMessage(m_data.at(i).toByteArray());
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (qint64)-1 << (int)Complete;
+ sendMessage(data);
+ }
+}
+
+void QDeclarativeDebugTrace::messageReceived(const QByteArray &message)
+{
+ QByteArray rwData = message;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ stream >> m_enabled;
+
+ m_messageReceived = true;
+
+ if (!m_enabled)
+ sendMessages();
+}
diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h
new file mode 100644
index 00000000..3cd73b07
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEDEBUGTRACE_P_H
+#define QDECLARATIVEDEBUGTRACE_P_H
+
+#include <private/qdeclarativedebugservice_p.h>
+#include <private/qperformancetimer_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+struct QDeclarativeDebugData
+{
+ qint64 time;
+ int messageType;
+ int detailType;
+
+ //###
+ QString detailData; //used by RangeData and RangeLocation
+ int line; //used by RangeLocation
+
+ QByteArray toByteArray() const;
+};
+
+class QUrl;
+class Q_AUTOTEST_EXPORT QDeclarativeDebugTrace : public QDeclarativeDebugService
+{
+public:
+ enum Message {
+ Event,
+ RangeStart,
+ RangeData,
+ RangeLocation,
+ RangeEnd,
+ Complete,
+
+ MaximumMessage
+ };
+
+ enum EventType {
+ FramePaint,
+ Mouse,
+ Key,
+
+ MaximumEventType
+ };
+
+ enum RangeType {
+ Painting,
+ Compiling,
+ Creating,
+ Binding, //running a binding
+ HandlingSignal, //running a signal handler
+
+ MaximumRangeType
+ };
+
+ static void addEvent(EventType);
+
+ static void startRange(RangeType);
+ static void rangeData(RangeType, const QString &);
+ static void rangeData(RangeType, const QUrl &);
+ static void rangeLocation(RangeType, const QString &, int);
+ static void rangeLocation(RangeType, const QUrl &, int);
+ static void endRange(RangeType);
+
+ QDeclarativeDebugTrace();
+protected:
+ virtual void messageReceived(const QByteArray &);
+private:
+ void addEventImpl(EventType);
+ void startRangeImpl(RangeType);
+ void rangeDataImpl(RangeType, const QString &);
+ void rangeDataImpl(RangeType, const QUrl &);
+ void rangeLocationImpl(RangeType, const QString &, int);
+ void rangeLocationImpl(RangeType, const QUrl &, int);
+ void endRangeImpl(RangeType);
+ void processMessage(const QDeclarativeDebugData &);
+ void sendMessages();
+ QPerformanceTimer m_timer;
+ bool m_enabled;
+ bool m_deferredSend;
+ bool m_messageReceived;
+ QList<QDeclarativeDebugData> m_data;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEDEBUGTRACE_P_H
+
diff --git a/src/declarative/debugger/qdeclarativeenginedebug.cpp b/src/declarative/debugger/qdeclarativeenginedebug.cpp
new file mode 100644
index 00000000..74316574
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeenginedebug.cpp
@@ -0,0 +1,1068 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeenginedebug_p.h"
+
+#include "private/qdeclarativedebugclient_p.h"
+
+#include <qdeclarativeenginedebugservice_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngineDebugClient : public QDeclarativeDebugClient
+{
+public:
+ QDeclarativeEngineDebugClient(QDeclarativeDebugConnection *client, QDeclarativeEngineDebugPrivate *p);
+
+protected:
+ virtual void statusChanged(Status status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ QDeclarativeEngineDebugPrivate *priv;
+ friend class QDeclarativeEngineDebugPrivate;
+};
+
+class QDeclarativeEngineDebugPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeEngineDebug)
+public:
+ QDeclarativeEngineDebugPrivate(QDeclarativeDebugConnection *);
+ ~QDeclarativeEngineDebugPrivate();
+
+ void statusChanged(QDeclarativeEngineDebug::Status status);
+ void message(const QByteArray &);
+
+ QDeclarativeEngineDebugClient *client;
+ int nextId;
+ int getId();
+
+ void decode(QDataStream &, QDeclarativeDebugContextReference &);
+ void decode(QDataStream &, QDeclarativeDebugObjectReference &, bool simple);
+
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugEnginesQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugRootContextQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugObjectQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugExpressionQuery *);
+ static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugWatch *);
+
+ QHash<int, QDeclarativeDebugEnginesQuery *> enginesQuery;
+ QHash<int, QDeclarativeDebugRootContextQuery *> rootContextQuery;
+ QHash<int, QDeclarativeDebugObjectQuery *> objectQuery;
+ QHash<int, QDeclarativeDebugExpressionQuery *> expressionQuery;
+
+ QHash<int, QDeclarativeDebugWatch *> watched;
+};
+
+QDeclarativeEngineDebugClient::QDeclarativeEngineDebugClient(QDeclarativeDebugConnection *client,
+ QDeclarativeEngineDebugPrivate *p)
+: QDeclarativeDebugClient(QLatin1String("QDeclarativeEngine"), client), priv(p)
+{
+}
+
+void QDeclarativeEngineDebugClient::statusChanged(Status status)
+{
+ if (priv)
+ priv->statusChanged(static_cast<QDeclarativeEngineDebug::Status>(status));
+}
+
+void QDeclarativeEngineDebugClient::messageReceived(const QByteArray &data)
+{
+ if (priv)
+ priv->message(data);
+}
+
+QDeclarativeEngineDebugPrivate::QDeclarativeEngineDebugPrivate(QDeclarativeDebugConnection *c)
+: client(new QDeclarativeEngineDebugClient(c, this)), nextId(0)
+{
+}
+
+QDeclarativeEngineDebugPrivate::~QDeclarativeEngineDebugPrivate()
+{
+ if (client)
+ client->priv = 0;
+ delete client;
+
+ QHash<int, QDeclarativeDebugEnginesQuery*>::iterator enginesIter = enginesQuery.begin();
+ for (; enginesIter != enginesQuery.end(); ++enginesIter) {
+ enginesIter.value()->m_client = 0;
+ if (enginesIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ enginesIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugRootContextQuery*>::iterator rootContextIter = rootContextQuery.begin();
+ for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) {
+ rootContextIter.value()->m_client = 0;
+ if (rootContextIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ rootContextIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugObjectQuery*>::iterator objectIter = objectQuery.begin();
+ for (; objectIter != objectQuery.end(); ++objectIter) {
+ objectIter.value()->m_client = 0;
+ if (objectIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ objectIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugExpressionQuery*>::iterator exprIter = expressionQuery.begin();
+ for (; exprIter != expressionQuery.end(); ++exprIter) {
+ exprIter.value()->m_client = 0;
+ if (exprIter.value()->state() == QDeclarativeDebugQuery::Waiting)
+ exprIter.value()->setState(QDeclarativeDebugQuery::Error);
+ }
+
+ QHash<int, QDeclarativeDebugWatch*>::iterator watchIter = watched.begin();
+ for (; watchIter != watched.end(); ++watchIter) {
+ watchIter.value()->m_client = 0;
+ watchIter.value()->setState(QDeclarativeDebugWatch::Dead);
+ }
+}
+
+int QDeclarativeEngineDebugPrivate::getId()
+{
+ return nextId++;
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugEnginesQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->enginesQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c,
+ QDeclarativeDebugRootContextQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->rootContextQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugObjectQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->objectQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugExpressionQuery *q)
+{
+ if (c && q) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->expressionQuery.remove(q->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugWatch *w)
+{
+ if (c && w) {
+ QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->watched.remove(w->m_queryId);
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugObjectReference &o,
+ bool simple)
+{
+ QDeclarativeEngineDebugService::QDeclarativeObjectData data;
+ ds >> data;
+ o.m_debugId = data.objectId;
+ o.m_class = data.objectType;
+ o.m_idString = data.idString;
+ o.m_name = data.objectName;
+ o.m_source.m_url = data.url;
+ o.m_source.m_lineNumber = data.lineNumber;
+ o.m_source.m_columnNumber = data.columnNumber;
+ o.m_contextDebugId = data.contextId;
+
+ if (simple)
+ return;
+
+ int childCount;
+ bool recur;
+ ds >> childCount >> recur;
+
+ for (int ii = 0; ii < childCount; ++ii) {
+ o.m_children.append(QDeclarativeDebugObjectReference());
+ decode(ds, o.m_children.last(), !recur);
+ }
+
+ int propCount;
+ ds >> propCount;
+
+ for (int ii = 0; ii < propCount; ++ii) {
+ QDeclarativeEngineDebugService::QDeclarativeObjectProperty data;
+ ds >> data;
+ QDeclarativeDebugPropertyReference prop;
+ prop.m_objectDebugId = o.m_debugId;
+ prop.m_name = data.name;
+ prop.m_binding = data.binding;
+ prop.m_hasNotifySignal = data.hasNotifySignal;
+ prop.m_valueTypeName = data.valueTypeName;
+ switch (data.type) {
+ case QDeclarativeEngineDebugService::QDeclarativeObjectProperty::Basic:
+ case QDeclarativeEngineDebugService::QDeclarativeObjectProperty::List:
+ case QDeclarativeEngineDebugService::QDeclarativeObjectProperty::SignalProperty:
+ {
+ prop.m_value = data.value;
+ break;
+ }
+ case QDeclarativeEngineDebugService::QDeclarativeObjectProperty::Object:
+ {
+ QDeclarativeDebugObjectReference obj;
+ obj.m_debugId = prop.m_value.toInt();
+ prop.m_value = QVariant::fromValue(obj);
+ break;
+ }
+ case QDeclarativeEngineDebugService::QDeclarativeObjectProperty::Unknown:
+ break;
+ }
+ o.m_properties << prop;
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugContextReference &c)
+{
+ ds >> c.m_name >> c.m_debugId;
+
+ int contextCount;
+ ds >> contextCount;
+
+ for (int ii = 0; ii < contextCount; ++ii) {
+ c.m_contexts.append(QDeclarativeDebugContextReference());
+ decode(ds, c.m_contexts.last());
+ }
+
+ int objectCount;
+ ds >> objectCount;
+
+ for (int ii = 0; ii < objectCount; ++ii) {
+ QDeclarativeDebugObjectReference obj;
+ decode(ds, obj, true);
+
+ obj.m_contextDebugId = c.m_debugId;
+ c.m_objects << obj;
+ }
+}
+
+void QDeclarativeEngineDebugPrivate::statusChanged(QDeclarativeEngineDebug::Status status)
+{
+ emit q_func()->statusChanged(status);
+}
+
+void QDeclarativeEngineDebugPrivate::message(const QByteArray &data)
+{
+ QDataStream ds(data);
+
+ QByteArray type;
+ ds >> type;
+
+ //qDebug() << "QDeclarativeEngineDebugPrivate::message()" << type;
+
+ if (type == "LIST_ENGINES_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugEnginesQuery *query = enginesQuery.value(queryId);
+ if (!query)
+ return;
+ enginesQuery.remove(queryId);
+
+ int count;
+ ds >> count;
+
+ for (int ii = 0; ii < count; ++ii) {
+ QDeclarativeDebugEngineReference ref;
+ ds >> ref.m_name;
+ ds >> ref.m_debugId;
+ query->m_engines << ref;
+ }
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "LIST_OBJECTS_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugRootContextQuery *query = rootContextQuery.value(queryId);
+ if (!query)
+ return;
+ rootContextQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_context);
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "FETCH_OBJECT_R") {
+ int queryId;
+ ds >> queryId;
+
+ QDeclarativeDebugObjectQuery *query = objectQuery.value(queryId);
+ if (!query)
+ return;
+ objectQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_object, false);
+
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "EVAL_EXPRESSION_R") {
+ int queryId;
+ QVariant result;
+ ds >> queryId >> result;
+
+ QDeclarativeDebugExpressionQuery *query = expressionQuery.value(queryId);
+ if (!query)
+ return;
+ expressionQuery.remove(queryId);
+
+ query->m_result = result;
+ query->m_client = 0;
+ query->setState(QDeclarativeDebugQuery::Completed);
+ } else if (type == "WATCH_PROPERTY_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "WATCH_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "WATCH_EXPR_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QDeclarativeDebugWatch::Active : QDeclarativeDebugWatch::Inactive);
+ } else if (type == "UPDATE_WATCH") {
+ int queryId;
+ int debugId;
+ QByteArray name;
+ QVariant value;
+ ds >> queryId >> debugId >> name >> value;
+
+ QDeclarativeDebugWatch *watch = watched.value(queryId, 0);
+ if (!watch)
+ return;
+ emit watch->valueChanged(name, value);
+ } else if (type == "OBJECT_CREATED") {
+ emit q_func()->newObjects();
+ }
+}
+
+QDeclarativeEngineDebug::QDeclarativeEngineDebug(QDeclarativeDebugConnection *client, QObject *parent)
+: QObject(*(new QDeclarativeEngineDebugPrivate(client)), parent)
+{
+}
+
+QDeclarativeEngineDebug::Status QDeclarativeEngineDebug::status() const
+{
+ Q_D(const QDeclarativeEngineDebug);
+
+ return static_cast<QDeclarativeEngineDebug::Status>(d->client->status());
+}
+
+QDeclarativeDebugPropertyWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugPropertyReference &property, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugPropertyWatch *watch = new QDeclarativeDebugPropertyWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = property.objectDebugId();
+ watch->m_name = property.name();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_PROPERTY") << queryId << property.objectDebugId() << property.name().toUtf8();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugContextReference &, const QString &, QObject *)
+{
+ qWarning("QDeclarativeEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+QDeclarativeDebugObjectExpressionWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugObjectReference &object, const QString &expr, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+ QDeclarativeDebugObjectExpressionWatch *watch = new QDeclarativeDebugObjectExpressionWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ watch->m_expr = expr;
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_EXPR_OBJECT") << queryId << object.debugId() << expr;
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugWatch *watch = new QDeclarativeDebugWatch(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ int queryId = d->getId();
+ watch->m_queryId = queryId;
+ watch->m_client = this;
+ watch->m_objectDebugId = object.debugId();
+ d->watched.insert(queryId, watch);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("WATCH_OBJECT") << queryId << object.debugId();
+ d->client->sendMessage(message);
+ } else {
+ watch->m_state = QDeclarativeDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QDeclarativeDebugWatch *QDeclarativeEngineDebug::addWatch(const QDeclarativeDebugFileReference &, QObject *)
+{
+ qWarning("QDeclarativeEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+void QDeclarativeEngineDebug::removeWatch(QDeclarativeDebugWatch *watch)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (!watch || !watch->m_client)
+ return;
+
+ watch->m_client = 0;
+ watch->setState(QDeclarativeDebugWatch::Inactive);
+
+ d->watched.remove(watch->queryId());
+
+ if (d->client && d->client->status() == QDeclarativeDebugClient::Enabled) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("NO_WATCH") << watch->queryId();
+ d->client->sendMessage(message);
+ }
+}
+
+QDeclarativeDebugEnginesQuery *QDeclarativeEngineDebug::queryAvailableEngines(QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugEnginesQuery *query = new QDeclarativeDebugEnginesQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->enginesQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_ENGINES") << queryId;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugRootContextQuery *QDeclarativeEngineDebug::queryRootContexts(const QDeclarativeDebugEngineReference &engine, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugRootContextQuery *query = new QDeclarativeDebugRootContextQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && engine.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->rootContextQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("LIST_OBJECTS") << queryId << engine.debugId();
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObject(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugObjectQuery *query = new QDeclarativeDebugObjectQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << false << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObjectRecursive(const QDeclarativeDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugObjectQuery *query = new QDeclarativeDebugObjectQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && object.debugId() != -1) {
+ query->m_client = this;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->objectQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
+ << true << true;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QDeclarativeDebugExpressionQuery *QDeclarativeEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ QDeclarativeDebugExpressionQuery *query = new QDeclarativeDebugExpressionQuery(parent);
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ query->m_client = this;
+ query->m_expr = expr;
+ int queryId = d->getId();
+ query->m_queryId = queryId;
+ d->expressionQuery.insert(queryId, query);
+
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("EVAL_EXPRESSION") << queryId << objectDebugId << expr;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QDeclarativeDebugQuery::Error;
+ }
+
+ return query;
+}
+
+bool QDeclarativeEngineDebug::setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression,
+ bool isLiteralValue,
+ QString source, int line)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_BINDING") << objectDebugId << propertyName << bindingExpression << isLiteralValue << source << line;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativeEngineDebug::resetBindingForObject(int objectDebugId, const QString &propertyName)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("RESET_BINDING") << objectDebugId << propertyName;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool QDeclarativeEngineDebug::setMethodBody(int objectDebugId, const QString &methodName,
+ const QString &methodBody)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->status() == QDeclarativeDebugClient::Enabled && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_METHOD_BODY") << objectDebugId << methodName << methodBody;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent)
+: QObject(parent), m_state(Waiting), m_queryId(-1), m_client(0), m_objectDebugId(-1)
+{
+}
+
+QDeclarativeDebugWatch::~QDeclarativeDebugWatch()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+int QDeclarativeDebugWatch::queryId() const
+{
+ return m_queryId;
+}
+
+int QDeclarativeDebugWatch::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QDeclarativeDebugWatch::State QDeclarativeDebugWatch::state() const
+{
+ return m_state;
+}
+
+void QDeclarativeDebugWatch::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QDeclarativeDebugPropertyWatch::QDeclarativeDebugPropertyWatch(QObject *parent)
+ : QDeclarativeDebugWatch(parent)
+{
+}
+
+QString QDeclarativeDebugPropertyWatch::name() const
+{
+ return m_name;
+}
+
+
+QDeclarativeDebugObjectExpressionWatch::QDeclarativeDebugObjectExpressionWatch(QObject *parent)
+ : QDeclarativeDebugWatch(parent)
+{
+}
+
+QString QDeclarativeDebugObjectExpressionWatch::expression() const
+{
+ return m_expr;
+}
+
+
+QDeclarativeDebugQuery::QDeclarativeDebugQuery(QObject *parent)
+: QObject(parent), m_state(Waiting)
+{
+}
+
+QDeclarativeDebugQuery::State QDeclarativeDebugQuery::state() const
+{
+ return m_state;
+}
+
+bool QDeclarativeDebugQuery::isWaiting() const
+{
+ return m_state == Waiting;
+}
+
+void QDeclarativeDebugQuery::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QDeclarativeDebugEnginesQuery::QDeclarativeDebugEnginesQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugEnginesQuery::~QDeclarativeDebugEnginesQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QList<QDeclarativeDebugEngineReference> QDeclarativeDebugEnginesQuery::engines() const
+{
+ return m_engines;
+}
+
+QDeclarativeDebugRootContextQuery::QDeclarativeDebugRootContextQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugRootContextQuery::~QDeclarativeDebugRootContextQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QDeclarativeDebugContextReference QDeclarativeDebugRootContextQuery::rootContext() const
+{
+ return m_context;
+}
+
+QDeclarativeDebugObjectQuery::QDeclarativeDebugObjectQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugObjectQuery::~QDeclarativeDebugObjectQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QDeclarativeDebugObjectReference QDeclarativeDebugObjectQuery::object() const
+{
+ return m_object;
+}
+
+QDeclarativeDebugExpressionQuery::QDeclarativeDebugExpressionQuery(QObject *parent)
+: QDeclarativeDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QDeclarativeDebugExpressionQuery::~QDeclarativeDebugExpressionQuery()
+{
+ if (m_client && m_queryId != -1)
+ QDeclarativeEngineDebugPrivate::remove(m_client, this);
+}
+
+QVariant QDeclarativeDebugExpressionQuery::expression() const
+{
+ return m_expr;
+}
+
+QVariant QDeclarativeDebugExpressionQuery::result() const
+{
+ return m_result;
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference()
+: m_debugId(-1)
+{
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference(int debugId)
+: m_debugId(debugId)
+{
+}
+
+QDeclarativeDebugEngineReference::QDeclarativeDebugEngineReference(const QDeclarativeDebugEngineReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name)
+{
+}
+
+QDeclarativeDebugEngineReference &
+QDeclarativeDebugEngineReference::operator=(const QDeclarativeDebugEngineReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name;
+ return *this;
+}
+
+int QDeclarativeDebugEngineReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugEngineReference::name() const
+{
+ return m_name;
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference()
+: m_debugId(-1), m_contextDebugId(-1)
+{
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference(int debugId)
+: m_debugId(debugId), m_contextDebugId(-1)
+{
+}
+
+QDeclarativeDebugObjectReference::QDeclarativeDebugObjectReference(const QDeclarativeDebugObjectReference &o)
+: m_debugId(o.m_debugId), m_class(o.m_class), m_idString(o.m_idString),
+ m_name(o.m_name), m_source(o.m_source), m_contextDebugId(o.m_contextDebugId),
+ m_properties(o.m_properties), m_children(o.m_children)
+{
+}
+
+QDeclarativeDebugObjectReference &
+QDeclarativeDebugObjectReference::operator=(const QDeclarativeDebugObjectReference &o)
+{
+ m_debugId = o.m_debugId; m_class = o.m_class; m_idString = o.m_idString;
+ m_name = o.m_name; m_source = o.m_source; m_contextDebugId = o.m_contextDebugId;
+ m_properties = o.m_properties; m_children = o.m_children;
+ return *this;
+}
+
+int QDeclarativeDebugObjectReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugObjectReference::className() const
+{
+ return m_class;
+}
+
+QString QDeclarativeDebugObjectReference::idString() const
+{
+ return m_idString;
+}
+
+QString QDeclarativeDebugObjectReference::name() const
+{
+ return m_name;
+}
+
+QDeclarativeDebugFileReference QDeclarativeDebugObjectReference::source() const
+{
+ return m_source;
+}
+
+int QDeclarativeDebugObjectReference::contextDebugId() const
+{
+ return m_contextDebugId;
+}
+
+QList<QDeclarativeDebugPropertyReference> QDeclarativeDebugObjectReference::properties() const
+{
+ return m_properties;
+}
+
+QList<QDeclarativeDebugObjectReference> QDeclarativeDebugObjectReference::children() const
+{
+ return m_children;
+}
+
+QDeclarativeDebugContextReference::QDeclarativeDebugContextReference()
+: m_debugId(-1)
+{
+}
+
+QDeclarativeDebugContextReference::QDeclarativeDebugContextReference(const QDeclarativeDebugContextReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name), m_objects(o.m_objects), m_contexts(o.m_contexts)
+{
+}
+
+QDeclarativeDebugContextReference &QDeclarativeDebugContextReference::operator=(const QDeclarativeDebugContextReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name; m_objects = o.m_objects;
+ m_contexts = o.m_contexts;
+ return *this;
+}
+
+int QDeclarativeDebugContextReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QDeclarativeDebugContextReference::name() const
+{
+ return m_name;
+}
+
+QList<QDeclarativeDebugObjectReference> QDeclarativeDebugContextReference::objects() const
+{
+ return m_objects;
+}
+
+QList<QDeclarativeDebugContextReference> QDeclarativeDebugContextReference::contexts() const
+{
+ return m_contexts;
+}
+
+QDeclarativeDebugFileReference::QDeclarativeDebugFileReference()
+: m_lineNumber(-1), m_columnNumber(-1)
+{
+}
+
+QDeclarativeDebugFileReference::QDeclarativeDebugFileReference(const QDeclarativeDebugFileReference &o)
+: m_url(o.m_url), m_lineNumber(o.m_lineNumber), m_columnNumber(o.m_columnNumber)
+{
+}
+
+QDeclarativeDebugFileReference &QDeclarativeDebugFileReference::operator=(const QDeclarativeDebugFileReference &o)
+{
+ m_url = o.m_url; m_lineNumber = o.m_lineNumber; m_columnNumber = o.m_columnNumber;
+ return *this;
+}
+
+QUrl QDeclarativeDebugFileReference::url() const
+{
+ return m_url;
+}
+
+void QDeclarativeDebugFileReference::setUrl(const QUrl &u)
+{
+ m_url = u;
+}
+
+int QDeclarativeDebugFileReference::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void QDeclarativeDebugFileReference::setLineNumber(int l)
+{
+ m_lineNumber = l;
+}
+
+int QDeclarativeDebugFileReference::columnNumber() const
+{
+ return m_columnNumber;
+}
+
+void QDeclarativeDebugFileReference::setColumnNumber(int c)
+{
+ m_columnNumber = c;
+}
+
+QDeclarativeDebugPropertyReference::QDeclarativeDebugPropertyReference()
+: m_objectDebugId(-1), m_hasNotifySignal(false)
+{
+}
+
+QDeclarativeDebugPropertyReference::QDeclarativeDebugPropertyReference(const QDeclarativeDebugPropertyReference &o)
+: m_objectDebugId(o.m_objectDebugId), m_name(o.m_name), m_value(o.m_value),
+ m_valueTypeName(o.m_valueTypeName), m_binding(o.m_binding),
+ m_hasNotifySignal(o.m_hasNotifySignal)
+{
+}
+
+QDeclarativeDebugPropertyReference &QDeclarativeDebugPropertyReference::operator=(const QDeclarativeDebugPropertyReference &o)
+{
+ m_objectDebugId = o.m_objectDebugId; m_name = o.m_name; m_value = o.m_value;
+ m_valueTypeName = o.m_valueTypeName; m_binding = o.m_binding;
+ m_hasNotifySignal = o.m_hasNotifySignal;
+ return *this;
+}
+
+int QDeclarativeDebugPropertyReference::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QString QDeclarativeDebugPropertyReference::name() const
+{
+ return m_name;
+}
+
+QString QDeclarativeDebugPropertyReference::valueTypeName() const
+{
+ return m_valueTypeName;
+}
+
+QVariant QDeclarativeDebugPropertyReference::value() const
+{
+ return m_value;
+}
+
+QString QDeclarativeDebugPropertyReference::binding() const
+{
+ return m_binding;
+}
+
+bool QDeclarativeDebugPropertyReference::hasNotifySignal() const
+{
+ return m_hasNotifySignal;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/debugger/qdeclarativeenginedebug_p.h b/src/declarative/debugger/qdeclarativeenginedebug_p.h
new file mode 100644
index 00000000..6c00efca
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeenginedebug_p.h
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QDECLARATIVEENGINEDEBUG_H
+#define QDECLARATIVEENGINEDEBUG_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeDebugConnection;
+class QDeclarativeDebugWatch;
+class QDeclarativeDebugPropertyWatch;
+class QDeclarativeDebugObjectExpressionWatch;
+class QDeclarativeDebugEnginesQuery;
+class QDeclarativeDebugRootContextQuery;
+class QDeclarativeDebugObjectQuery;
+class QDeclarativeDebugExpressionQuery;
+class QDeclarativeDebugPropertyReference;
+class QDeclarativeDebugContextReference;
+class QDeclarativeDebugObjectReference;
+class QDeclarativeDebugFileReference;
+class QDeclarativeDebugEngineReference;
+class QDeclarativeEngineDebugPrivate;
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeEngineDebug : public QObject
+{
+Q_OBJECT
+public:
+ enum Status { NotConnected, Unavailable, Enabled };
+
+ explicit QDeclarativeEngineDebug(QDeclarativeDebugConnection *, QObject * = 0);
+
+ Status status() const;
+
+ QDeclarativeDebugPropertyWatch *addWatch(const QDeclarativeDebugPropertyReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugContextReference &, const QString &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectExpressionWatch *addWatch(const QDeclarativeDebugObjectReference &, const QString &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugWatch *addWatch(const QDeclarativeDebugFileReference &,
+ QObject *parent = 0);
+
+ void removeWatch(QDeclarativeDebugWatch *watch);
+
+ QDeclarativeDebugEnginesQuery *queryAvailableEngines(QObject *parent = 0);
+ QDeclarativeDebugRootContextQuery *queryRootContexts(const QDeclarativeDebugEngineReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectQuery *queryObject(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugObjectQuery *queryObjectRecursive(const QDeclarativeDebugObjectReference &,
+ QObject *parent = 0);
+ QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId,
+ const QString &expr,
+ QObject *parent = 0);
+ bool setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression, bool isLiteralValue,
+ QString source = QString(), int line = -1);
+ bool resetBindingForObject(int objectDebugId, const QString &propertyName);
+ bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody);
+
+Q_SIGNALS:
+ void newObjects();
+ void statusChanged(Status status);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeEngineDebug)
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugWatch : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Active, Inactive, Dead };
+
+ QDeclarativeDebugWatch(QObject *);
+ ~QDeclarativeDebugWatch();
+
+ int queryId() const;
+ int objectDebugId() const;
+ State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QDeclarativeDebugWatch::State);
+ //void objectChanged(int, const QDeclarativeDebugObjectReference &);
+ //void valueChanged(int, const QVariant &);
+
+ // Server sends value as string if it is a user-type variant
+ void valueChanged(const QByteArray &name, const QVariant &value);
+
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+ int m_queryId;
+ QDeclarativeEngineDebug *m_client;
+ int m_objectDebugId;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugPropertyWatch : public QDeclarativeDebugWatch
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugPropertyWatch(QObject *parent);
+
+ QString name() const;
+
+private:
+ friend class QDeclarativeEngineDebug;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectExpressionWatch : public QDeclarativeDebugWatch
+{
+ Q_OBJECT
+public:
+ QDeclarativeDebugObjectExpressionWatch(QObject *parent);
+
+ QString expression() const;
+
+private:
+ friend class QDeclarativeEngineDebug;
+ QString m_expr;
+ int m_debugId;
+};
+
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugQuery : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Error, Completed };
+
+ State state() const;
+ bool isWaiting() const;
+
+// bool waitUntilCompleted();
+
+Q_SIGNALS:
+ void stateChanged(QDeclarativeDebugQuery::State);
+
+protected:
+ QDeclarativeDebugQuery(QObject *);
+
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugFileReference
+{
+public:
+ QDeclarativeDebugFileReference();
+ QDeclarativeDebugFileReference(const QDeclarativeDebugFileReference &);
+ QDeclarativeDebugFileReference &operator=(const QDeclarativeDebugFileReference &);
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ int lineNumber() const;
+ void setLineNumber(int);
+ int columnNumber() const;
+ void setColumnNumber(int);
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ QUrl m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugEngineReference
+{
+public:
+ QDeclarativeDebugEngineReference();
+ QDeclarativeDebugEngineReference(int);
+ QDeclarativeDebugEngineReference(const QDeclarativeDebugEngineReference &);
+ QDeclarativeDebugEngineReference &operator=(const QDeclarativeDebugEngineReference &);
+
+ int debugId() const;
+ QString name() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectReference
+{
+public:
+ QDeclarativeDebugObjectReference();
+ QDeclarativeDebugObjectReference(int);
+ QDeclarativeDebugObjectReference(const QDeclarativeDebugObjectReference &);
+ QDeclarativeDebugObjectReference &operator=(const QDeclarativeDebugObjectReference &);
+
+ int debugId() const;
+ QString className() const;
+ QString idString() const;
+ QString name() const;
+
+ QDeclarativeDebugFileReference source() const;
+ int contextDebugId() const;
+
+ QList<QDeclarativeDebugPropertyReference> properties() const;
+ QList<QDeclarativeDebugObjectReference> children() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_class;
+ QString m_idString;
+ QString m_name;
+ QDeclarativeDebugFileReference m_source;
+ int m_contextDebugId;
+ QList<QDeclarativeDebugPropertyReference> m_properties;
+ QList<QDeclarativeDebugObjectReference> m_children;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugContextReference
+{
+public:
+ QDeclarativeDebugContextReference();
+ QDeclarativeDebugContextReference(const QDeclarativeDebugContextReference &);
+ QDeclarativeDebugContextReference &operator=(const QDeclarativeDebugContextReference &);
+
+ int debugId() const;
+ QString name() const;
+
+ QList<QDeclarativeDebugObjectReference> objects() const;
+ QList<QDeclarativeDebugContextReference> contexts() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+ QList<QDeclarativeDebugObjectReference> m_objects;
+ QList<QDeclarativeDebugContextReference> m_contexts;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugPropertyReference
+{
+public:
+ QDeclarativeDebugPropertyReference();
+ QDeclarativeDebugPropertyReference(const QDeclarativeDebugPropertyReference &);
+ QDeclarativeDebugPropertyReference &operator=(const QDeclarativeDebugPropertyReference &);
+
+ int objectDebugId() const;
+ QString name() const;
+ QVariant value() const;
+ QString valueTypeName() const;
+ QString binding() const;
+ bool hasNotifySignal() const;
+
+private:
+ friend class QDeclarativeEngineDebugPrivate;
+ int m_objectDebugId;
+ QString m_name;
+ QVariant m_value;
+ QString m_valueTypeName;
+ QString m_binding;
+ bool m_hasNotifySignal;
+};
+
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugEnginesQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugEnginesQuery();
+ QList<QDeclarativeDebugEngineReference> engines() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugEnginesQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QList<QDeclarativeDebugEngineReference> m_engines;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugRootContextQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugRootContextQuery();
+ QDeclarativeDebugContextReference rootContext() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugRootContextQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QDeclarativeDebugContextReference m_context;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugObjectQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugObjectQuery();
+ QDeclarativeDebugObjectReference object() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugObjectQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QDeclarativeDebugObjectReference m_object;
+
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugExpressionQuery : public QDeclarativeDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QDeclarativeDebugExpressionQuery();
+ QVariant expression() const;
+ QVariant result() const;
+private:
+ friend class QDeclarativeEngineDebug;
+ friend class QDeclarativeEngineDebugPrivate;
+ QDeclarativeDebugExpressionQuery(QObject *);
+ QDeclarativeEngineDebug *m_client;
+ int m_queryId;
+ QVariant m_expr;
+ QVariant m_result;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeDebugEngineReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugObjectReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugContextReference)
+Q_DECLARE_METATYPE(QDeclarativeDebugPropertyReference)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEENGINEDEBUG_H
diff --git a/src/declarative/debugger/qdeclarativeenginedebugservice.cpp b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp
new file mode 100644
index 00000000..421e3994
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp
@@ -0,0 +1,747 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeenginedebugservice_p.h"
+
+#include "private/qdeclarativeboundsignal_p.h"
+#include "qdeclarativeengine.h"
+#include "private/qdeclarativemetatype_p.h"
+#include "qdeclarativeproperty.h"
+#include "private/qdeclarativeproperty_p.h"
+#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativecontext_p.h"
+#include "private/qdeclarativewatcher_p.h"
+#include "private/qdeclarativevaluetype_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativeexpression_p.h"
+#include "private/qdeclarativepropertychanges_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDeclarativeEngineDebugService, qmlEngineDebugService);
+
+QDeclarativeEngineDebugService *QDeclarativeEngineDebugService::instance()
+{
+ return qmlEngineDebugService();
+}
+
+QDeclarativeEngineDebugService::QDeclarativeEngineDebugService(QObject *parent)
+: QDeclarativeDebugService(QLatin1String("QDeclarativeEngine"), parent),
+ m_watch(new QDeclarativeWatcher(this))
+{
+ QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)),
+ this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant)));
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QDeclarativeEngineDebugService::QDeclarativeObjectData &data)
+{
+ ds << data.url << data.lineNumber << data.columnNumber << data.idString
+ << data.objectName << data.objectType << data.objectId << data.contextId;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QDeclarativeEngineDebugService::QDeclarativeObjectData &data)
+{
+ ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
+ >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds,
+ const QDeclarativeEngineDebugService::QDeclarativeObjectProperty &data)
+{
+ ds << (int)data.type << data.name << data.value << data.valueTypeName
+ << data.binding << data.hasNotifySignal;
+ return ds;
+}
+
+QDataStream &operator>>(QDataStream &ds,
+ QDeclarativeEngineDebugService::QDeclarativeObjectProperty &data)
+{
+ int type;
+ ds >> type >> data.name >> data.value >> data.valueTypeName
+ >> data.binding >> data.hasNotifySignal;
+ data.type = (QDeclarativeEngineDebugService::QDeclarativeObjectProperty::Type)type;
+ return ds;
+}
+
+static inline bool isSignalPropertyName(const QString &signalName)
+{
+ // see QmlCompiler::isSignalPropertyName
+ return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
+ signalName.at(2).isLetter() && signalName.at(2).isUpper();
+}
+
+static bool hasValidSignal(QObject *object, const QString &propertyName)
+{
+ if (!isSignalPropertyName(propertyName))
+ return false;
+
+ QString signalName = propertyName.mid(2);
+ signalName[0] = signalName.at(0).toLower();
+
+ int sigIdx = QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex();
+
+ if (sigIdx == -1)
+ return false;
+
+ return true;
+}
+
+QDeclarativeEngineDebugService::QDeclarativeObjectProperty
+QDeclarativeEngineDebugService::propertyData(QObject *obj, int propIdx)
+{
+ QDeclarativeObjectProperty rv;
+
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
+
+ rv.type = QDeclarativeObjectProperty::Unknown;
+ rv.valueTypeName = QString::fromUtf8(prop.typeName());
+ rv.name = QString::fromUtf8(prop.name());
+ rv.hasNotifySignal = prop.hasNotifySignal();
+ QDeclarativeAbstractBinding *binding =
+ QDeclarativePropertyPrivate::binding(QDeclarativeProperty(obj, rv.name));
+ if (binding)
+ rv.binding = binding->expression();
+
+ if (QDeclarativeValueTypeFactory::isValueType(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::Basic;
+ } else if (QDeclarativeMetaType::isQObject(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::Object;
+ } else if (QDeclarativeMetaType::isList(prop.userType())) {
+ rv.type = QDeclarativeObjectProperty::List;
+ }
+
+ QVariant value;
+ if (rv.type != QDeclarativeObjectProperty::Unknown && prop.userType() != 0) {
+ value = prop.read(obj);
+ }
+ rv.value = valueContents(value);
+
+ return rv;
+}
+
+QVariant QDeclarativeEngineDebugService::valueContents(const QVariant &value) const
+{
+ int userType = value.userType();
+
+ if (value.type() == QVariant::List) {
+ QVariantList contents;
+ QVariantList list = value.toList();
+ int count = list.size();
+ for (int i = 0; i < count; i++)
+ contents << valueContents(list.at(i));
+ return contents;
+ }
+
+ if (QDeclarativeValueTypeFactory::isValueType(userType))
+ return value;
+
+ if (QDeclarativeMetaType::isQObject(userType)) {
+ QObject *o = QDeclarativeMetaType::toQObject(value);
+ if (o) {
+ QString name = o->objectName();
+ if (name.isEmpty())
+ name = QLatin1String("<unnamed object>");
+ return name;
+ }
+ }
+
+ return QLatin1String("<unknown value>");
+}
+
+void QDeclarativeEngineDebugService::buildObjectDump(QDataStream &message,
+ QObject *object, bool recur, bool dumpProperties)
+{
+ message << objectData(object);
+
+ QObjectList children = object->children();
+
+ int childrenCount = children.count();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ if (qobject_cast<QDeclarativeContext*>(children[ii]) || QDeclarativeBoundSignal::cast(children[ii]))
+ --childrenCount;
+ }
+
+ message << childrenCount << recur;
+
+ QList<QDeclarativeObjectProperty> fakeProperties;
+
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ if (qobject_cast<QDeclarativeContext*>(child))
+ continue;
+ QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
+ if (signal) {
+ if (!dumpProperties)
+ continue;
+ QDeclarativeObjectProperty prop;
+ prop.type = QDeclarativeObjectProperty::SignalProperty;
+ prop.hasNotifySignal = false;
+ QDeclarativeExpression *expr = signal->expression();
+ if (expr) {
+ prop.value = expr->expression();
+ QObject *scope = expr->scopeObject();
+ if (scope) {
+ QString sig = QLatin1String(scope->metaObject()->method(signal->index()).signature());
+ int lparen = sig.indexOf(QLatin1Char('('));
+ if (lparen >= 0) {
+ QString methodName = sig.mid(0, lparen);
+ prop.name = QLatin1String("on") + methodName[0].toUpper()
+ + methodName.mid(1);
+ }
+ }
+ }
+ fakeProperties << prop;
+ } else {
+ if (recur)
+ buildObjectDump(message, child, recur, dumpProperties);
+ else
+ message << objectData(child);
+ }
+ }
+
+ if (!dumpProperties) {
+ message << 0;
+ return;
+ }
+
+ QList<int> propertyIndexes;
+ for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) {
+ if (object->metaObject()->property(ii).isScriptable())
+ propertyIndexes << ii;
+ }
+
+ message << propertyIndexes.size() + fakeProperties.count();
+
+ for (int ii = 0; ii < propertyIndexes.size(); ++ii)
+ message << propertyData(object, propertyIndexes.at(ii));
+
+ for (int ii = 0; ii < fakeProperties.count(); ++ii)
+ message << fakeProperties[ii];
+}
+
+void QDeclarativeEngineDebugService::prepareDeferredObjects(QObject *obj)
+{
+ qmlExecuteDeferred(obj);
+
+ QObjectList children = obj->children();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QObject *child = children.at(ii);
+ prepareDeferredObjects(child);
+ }
+
+}
+
+void QDeclarativeEngineDebugService::buildObjectList(QDataStream &message, QDeclarativeContext *ctxt)
+{
+ QDeclarativeContextData *p = QDeclarativeContextData::get(ctxt);
+
+ QString ctxtName = ctxt->objectName();
+ int ctxtId = QDeclarativeDebugService::idForObject(ctxt);
+
+ message << ctxtName << ctxtId;
+
+ int count = 0;
+
+ QDeclarativeContextData *child = p->childContexts;
+ while (child) {
+ ++count;
+ child = child->nextChild;
+ }
+
+ message << count;
+
+ child = p->childContexts;
+ while (child) {
+ buildObjectList(message, child->asQDeclarativeContext());
+ child = child->nextChild;
+ }
+
+ // Clean deleted objects
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ if (!ctxtPriv->instances.at(ii)) {
+ ctxtPriv->instances.removeAt(ii);
+ --ii;
+ }
+ }
+
+ message << ctxtPriv->instances.count();
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ message << objectData(ctxtPriv->instances.at(ii));
+ }
+}
+
+void QDeclarativeEngineDebugService::buildStatesList(QDeclarativeContext *ctxt, bool cleanList=false)
+{
+ if (cleanList)
+ m_allStates.clear();
+
+ QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt);
+ for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
+ buildStatesList(ctxtPriv->instances.at(ii));
+ }
+
+ QDeclarativeContextData *child = QDeclarativeContextData::get(ctxt)->childContexts;
+ while (child) {
+ buildStatesList(child->asQDeclarativeContext());
+ child = child->nextChild;
+ }
+}
+
+void QDeclarativeEngineDebugService::buildStatesList(QObject *obj)
+{
+ if (QDeclarativeState *state = qobject_cast<QDeclarativeState *>(obj)) {
+ m_allStates.append(state);
+ }
+
+ QObjectList children = obj->children();
+ for (int ii = 0; ii < children.count(); ++ii) {
+ buildStatesList(children.at(ii));
+ }
+}
+
+QDeclarativeEngineDebugService::QDeclarativeObjectData
+QDeclarativeEngineDebugService::objectData(QObject *object)
+{
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ QDeclarativeObjectData rv;
+ if (ddata && ddata->outerContext) {
+ rv.url = ddata->outerContext->url;
+ rv.lineNumber = ddata->lineNumber;
+ rv.columnNumber = ddata->columnNumber;
+ } else {
+ rv.lineNumber = -1;
+ rv.columnNumber = -1;
+ }
+
+ QDeclarativeContext *context = qmlContext(object);
+ if (context) {
+ QDeclarativeContextData *cdata = QDeclarativeContextData::get(context);
+ if (cdata)
+ rv.idString = cdata->findObjectId(object);
+ }
+
+ rv.objectName = object->objectName();
+ rv.objectId = QDeclarativeDebugService::idForObject(object);
+ rv.contextId = QDeclarativeDebugService::idForObject(qmlContext(object));
+
+ QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject());
+ if (type) {
+ QString typeName = QLatin1String(type->qmlTypeName());
+ int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
+ } else {
+ rv.objectType = QString::fromUtf8(object->metaObject()->className());
+ int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
+ if (marker != -1)
+ rv.objectType = rv.objectType.left(marker);
+ }
+
+ return rv;
+}
+
+void QDeclarativeEngineDebugService::messageReceived(const QByteArray &message)
+{
+ QDataStream ds(message);
+
+ QByteArray type;
+ ds >> type;
+
+ if (type == "LIST_ENGINES") {
+ int queryId;
+ ds >> queryId;
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_ENGINES_R");
+ rs << queryId << m_engines.count();
+
+ for (int ii = 0; ii < m_engines.count(); ++ii) {
+ QDeclarativeEngine *engine = m_engines.at(ii);
+
+ QString engineName = engine->objectName();
+ int engineId = QDeclarativeDebugService::idForObject(engine);
+
+ rs << engineName << engineId;
+ }
+
+ sendMessage(reply);
+ } else if (type == "LIST_OBJECTS") {
+ int queryId;
+ int engineId = -1;
+ ds >> queryId >> engineId;
+
+ QDeclarativeEngine *engine =
+ qobject_cast<QDeclarativeEngine *>(QDeclarativeDebugService::objectForId(engineId));
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LIST_OBJECTS_R") << queryId;
+
+ if (engine) {
+ buildObjectList(rs, engine->rootContext());
+ buildStatesList(engine->rootContext(), true);
+ }
+
+ sendMessage(reply);
+ } else if (type == "FETCH_OBJECT") {
+ int queryId;
+ int objectId;
+ bool recurse;
+ bool dumpProperties = true;
+
+ ds >> queryId >> objectId >> recurse >> dumpProperties;
+
+ QObject *object = QDeclarativeDebugService::objectForId(objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("FETCH_OBJECT_R") << queryId;
+
+ if (object) {
+ if (recurse)
+ prepareDeferredObjects(object);
+ buildObjectDump(rs, object, recurse, dumpProperties);
+ }
+
+ sendMessage(reply);
+ } else if (type == "WATCH_OBJECT") {
+ int queryId;
+ int objectId;
+
+ ds >> queryId >> objectId;
+ bool ok = m_watch->addWatch(queryId, objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_OBJECT_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_PROPERTY") {
+ int queryId;
+ int objectId;
+ QByteArray property;
+
+ ds >> queryId >> objectId >> property;
+ bool ok = m_watch->addWatch(queryId, objectId, property);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok;
+
+ sendMessage(reply);
+ } else if (type == "WATCH_EXPR_OBJECT") {
+ int queryId;
+ int debugId;
+ QString expr;
+
+ ds >> queryId >> debugId >> expr;
+ bool ok = m_watch->addWatch(queryId, debugId, expr);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok;
+ sendMessage(reply);
+ } else if (type == "NO_WATCH") {
+ int queryId;
+
+ ds >> queryId;
+ m_watch->removeWatch(queryId);
+ } else if (type == "EVAL_EXPRESSION") {
+ int queryId;
+ int objectId;
+ QString expr;
+
+ ds >> queryId >> objectId >> expr;
+
+ QObject *object = QDeclarativeDebugService::objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ QVariant result;
+ if (object && context) {
+ QDeclarativeExpression exprObj(context, object, expr);
+ bool undefined = false;
+ QVariant value = exprObj.evaluate(&undefined);
+ if (undefined)
+ result = QLatin1String("<undefined>");
+ else
+ result = valueContents(value);
+ } else {
+ result = QLatin1String("<unknown context>");
+ }
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result;
+
+ sendMessage(reply);
+ } else if (type == "SET_BINDING") {
+ int objectId;
+ QString propertyName;
+ QVariant expr;
+ bool isLiteralValue;
+ QString filename;
+ int line;
+ ds >> objectId >> propertyName >> expr >> isLiteralValue;
+ if (!ds.atEnd()) { // backward compatibility from 2.1, 2.2
+ ds >> filename >> line;
+ }
+ setBinding(objectId, propertyName, expr, isLiteralValue, filename, line);
+ } else if (type == "RESET_BINDING") {
+ int objectId;
+ QString propertyName;
+ ds >> objectId >> propertyName;
+ resetBinding(objectId, propertyName);
+ } else if (type == "SET_METHOD_BODY") {
+ int objectId;
+ QString methodName;
+ QString methodBody;
+ ds >> objectId >> methodName >> methodBody;
+ setMethodBody(objectId, methodName, methodBody);
+ }
+}
+
+void QDeclarativeEngineDebugService::setBinding(int objectId,
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue,
+ QString filename,
+ int line)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+
+ if (object && context) {
+ QDeclarativeProperty property(object, propertyName, context);
+ if (property.isValid()) {
+
+ bool inBaseState = true;
+
+ foreach(QWeakPointer<QDeclarativeState> statePointer, m_allStates) {
+ if (QDeclarativeState *state = statePointer.data()) {
+ // here we assume that the revert list on itself defines the base state
+ if (state->isStateActive() && state->containsPropertyInRevertList(object, propertyName)) {
+ inBaseState = false;
+
+ QDeclarativeBinding *newBinding = 0;
+ if (!isLiteralValue) {
+ newBinding = new QDeclarativeBinding(expression.toString(), object, context);
+ newBinding->setTarget(property);
+ newBinding->setNotifyOnValueChanged(true);
+ newBinding->setSourceLocation(filename, line);
+ }
+
+ state->changeBindingInRevertList(object, propertyName, newBinding);
+
+ if (isLiteralValue)
+ state->changeValueInRevertList(object, propertyName, expression);
+ }
+ }
+ }
+
+ if (inBaseState) {
+ if (isLiteralValue) {
+ property.write(expression);
+ } else if (hasValidSignal(object, propertyName)) {
+ QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString());
+ QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression);
+ declarativeExpression->setSourceLocation(filename, line);
+ } else if (property.isProperty()) {
+ QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context);
+ binding->setTarget(property);
+ binding->setSourceLocation(filename, line);
+ binding->setNotifyOnValueChanged(true);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding);
+ if (oldBinding)
+ oldBinding->destroy();
+ binding->update();
+ } else {
+ qWarning() << "QDeclarativeEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+
+ } else {
+ // not a valid property
+ if (QDeclarativePropertyChanges *propertyChanges = qobject_cast<QDeclarativePropertyChanges *>(object)) {
+ if (isLiteralValue) {
+ propertyChanges->changeValue(propertyName, expression);
+ } else {
+ propertyChanges->changeExpression(propertyName, expression.toString());
+ }
+ } else {
+ qWarning() << "QDeclarativeEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object;
+ }
+ }
+ }
+}
+
+void QDeclarativeEngineDebugService::resetBinding(int objectId, const QString &propertyName)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+
+ if (object && context) {
+ if (object->property(propertyName.toLatin1()).isValid()) {
+ QDeclarativeProperty property(object, propertyName);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(property);
+ if (oldBinding) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, 0);
+ if (oldBinding)
+ oldBinding->destroy();
+ }
+ if (property.isResettable()) {
+ // Note: this will reset the property in any case, without regard to states
+ // Right now almost no QDeclarativeItem has reset methods for its properties (with the
+ // notable exception of QDeclarativeAnchors), so this is not a big issue
+ // later on, setBinding does take states into account
+ property.reset();
+ } else {
+ // overwrite with default value
+ if (QDeclarativeType *objType = QDeclarativeMetaType::qmlType(object->metaObject())) {
+ if (QObject *emptyObject = objType->create()) {
+ if (emptyObject->property(propertyName.toLatin1()).isValid()) {
+ QVariant defaultValue = QDeclarativeProperty(emptyObject, propertyName).read();
+ if (defaultValue.isValid()) {
+ setBinding(objectId, propertyName, defaultValue, true);
+ }
+ }
+ delete emptyObject;
+ }
+ }
+ }
+ } else if (hasValidSignal(object, propertyName)) {
+ QDeclarativeProperty property(object, propertyName, context);
+ QDeclarativePropertyPrivate::setSignalExpression(property, 0);
+ } else {
+ if (QDeclarativePropertyChanges *propertyChanges = qobject_cast<QDeclarativePropertyChanges *>(object)) {
+ propertyChanges->removeProperty(propertyName);
+ }
+ }
+ }
+}
+
+void QDeclarativeEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ if (!object || !context || !context->engine())
+ return;
+ QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
+ if (!contextData)
+ return;
+
+ QDeclarativePropertyCache::Data dummy;
+ QDeclarativePropertyCache::Data *prop =
+ QDeclarativePropertyCache::property(context->engine(), object, method, dummy);
+
+ if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction))
+ return;
+
+ QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
+ QList<QByteArray> paramNames = metaMethod.parameterNames();
+
+ QString paramStr;
+ for (int ii = 0; ii < paramNames.count(); ++ii) {
+ if (ii != 0) paramStr.append(QLatin1String(","));
+ paramStr.append(QString::fromUtf8(paramNames.at(ii)));
+ }
+
+ QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr +
+ QLatin1String(") {");
+ jsfunction += body;
+ jsfunction += QLatin1String("\n})");
+
+ QDeclarativeVMEMetaObject *vmeMetaObject =
+ static_cast<QDeclarativeVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
+ vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0));
+}
+
+void QDeclarativeEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value);
+
+ sendMessage(reply);
+}
+
+void QDeclarativeEngineDebugService::addEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(!m_engines.contains(engine));
+
+ m_engines.append(engine);
+}
+
+void QDeclarativeEngineDebugService::remEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ m_engines.removeAll(engine);
+}
+
+void QDeclarativeEngineDebugService::objectCreated(QDeclarativeEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ int engineId = QDeclarativeDebugService::idForObject(engine);
+ int objectId = QDeclarativeDebugService::idForObject(object);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+
+ rs << QByteArray("OBJECT_CREATED") << engineId << objectId;
+ sendMessage(reply);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativeenginedebugservice_p.h b/src/declarative/debugger/qdeclarativeenginedebugservice_p.h
new file mode 100644
index 00000000..864fa13a
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeenginedebugservice_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEENGINEDEBUGSERVICE_P_H
+#define QDECLARATIVEENGINEDEBUGSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qdeclarativedebugservice_p.h>
+
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QWeakPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativeContext;
+class QDeclarativeWatcher;
+class QDataStream;
+class QDeclarativeState;
+
+class QDeclarativeEngineDebugService : public QDeclarativeDebugService
+{
+ Q_OBJECT
+public:
+ QDeclarativeEngineDebugService(QObject * = 0);
+
+ struct QDeclarativeObjectData {
+ QUrl url;
+ int lineNumber;
+ int columnNumber;
+ QString idString;
+ QString objectName;
+ QString objectType;
+ int objectId;
+ int contextId;
+ };
+
+ struct QDeclarativeObjectProperty {
+ enum Type { Unknown, Basic, Object, List, SignalProperty };
+ Type type;
+ QString name;
+ QVariant value;
+ QString valueTypeName;
+ QString binding;
+ bool hasNotifySignal;
+ };
+
+ void addEngine(QDeclarativeEngine *);
+ void remEngine(QDeclarativeEngine *);
+ void objectCreated(QDeclarativeEngine *, QObject *);
+
+ static QDeclarativeEngineDebugService *instance();
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value);
+
+private:
+ void prepareDeferredObjects(QObject *);
+ void buildObjectList(QDataStream &, QDeclarativeContext *);
+ void buildObjectDump(QDataStream &, QObject *, bool, bool);
+ void buildStatesList(QDeclarativeContext *, bool);
+ void buildStatesList(QObject *obj);
+ QDeclarativeObjectData objectData(QObject *);
+ QDeclarativeObjectProperty propertyData(QObject *, int);
+ QVariant valueContents(const QVariant &defaultValue) const;
+ void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1);
+ void resetBinding(int objectId, const QString &propertyName);
+ void setMethodBody(int objectId, const QString &method, const QString &body);
+
+ QList<QDeclarativeEngine *> m_engines;
+ QDeclarativeWatcher *m_watch;
+ QList<QWeakPointer<QDeclarativeState> > m_allStates;
+};
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugService::QDeclarativeObjectData &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QDeclarativeEngineDebugService::QDeclarativeObjectData &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugService::QDeclarativeObjectProperty &);
+Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QDeclarativeEngineDebugService::QDeclarativeObjectProperty &);
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEENGINEDEBUGSERVICE_P_H
+
diff --git a/src/declarative/debugger/qdeclarativeinspectorinterface_p.h b/src/declarative/debugger/qdeclarativeinspectorinterface_p.h
new file mode 100644
index 00000000..bd7cd954
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeinspectorinterface_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEOBSERVERINTERFACE_H
+#define QDECLARATIVEOBSERVERINTERFACE_H
+
+#include <QtDeclarative/private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QDeclarativeInspectorInterface
+{
+public:
+ QDeclarativeInspectorInterface() {}
+ virtual ~QDeclarativeInspectorInterface() {}
+
+ virtual void activate() = 0;
+ virtual void deactivate() = 0;
+};
+
+Q_DECLARE_INTERFACE(QDeclarativeInspectorInterface, "com.trolltech.Qt.QDeclarativeInspectorInterface/1.0")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEOBSERVERINTERFACE_H
diff --git a/src/declarative/debugger/qdeclarativeinspectorservice.cpp b/src/declarative/debugger/qdeclarativeinspectorservice.cpp
new file mode 100644
index 00000000..b651b259
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeinspectorservice.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qdeclarativeinspectorservice_p.h"
+#include "private/qdeclarativeinspectorinterface_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+
+#include <QtDeclarative/QDeclarativeView>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDeclarativeInspectorService, serviceInstance)
+
+QDeclarativeInspectorService::QDeclarativeInspectorService()
+ : QDeclarativeDebugService(QLatin1String("QDeclarativeObserverMode"))
+ , m_inspectorPlugin(0)
+{
+}
+
+QDeclarativeInspectorService *QDeclarativeInspectorService::instance()
+{
+ return serviceInstance();
+}
+
+void QDeclarativeInspectorService::addView(QDeclarativeView *view)
+{
+ m_views.append(view);
+ updateStatus();
+}
+
+void QDeclarativeInspectorService::removeView(QDeclarativeView *view)
+{
+ m_views.removeAll(view);
+ updateStatus();
+}
+
+void QDeclarativeInspectorService::sendMessage(const QByteArray &message)
+{
+ if (status() != Enabled)
+ return;
+
+ QDeclarativeDebugService::sendMessage(message);
+}
+
+void QDeclarativeInspectorService::statusChanged(Status status)
+{
+ updateStatus();
+}
+
+void QDeclarativeInspectorService::updateStatus()
+{
+ if (m_views.isEmpty()) {
+ if (m_inspectorPlugin)
+ m_inspectorPlugin->deactivate();
+ return;
+ }
+
+ if (status() == Enabled) {
+ if (!m_inspectorPlugin)
+ m_inspectorPlugin = loadInspectorPlugin();
+
+ if (!m_inspectorPlugin) {
+ qWarning() << "Error while loading inspector plugin";
+ return;
+ }
+
+ m_inspectorPlugin->activate();
+ } else {
+ if (m_inspectorPlugin)
+ m_inspectorPlugin->deactivate();
+ }
+}
+
+void QDeclarativeInspectorService::messageReceived(const QByteArray &message)
+{
+ emit gotMessage(message);
+}
+
+QDeclarativeInspectorInterface *QDeclarativeInspectorService::loadInspectorPlugin()
+{
+ QStringList pluginCandidates;
+ const QStringList paths = QCoreApplication::libraryPaths();
+ foreach (const QString &libPath, paths) {
+ const QDir dir(libPath + QLatin1String("/qmltooling"));
+ if (dir.exists())
+ foreach (const QString &pluginPath, dir.entryList(QDir::Files))
+ pluginCandidates << dir.absoluteFilePath(pluginPath);
+ }
+
+ foreach (const QString &pluginPath, pluginCandidates) {
+ QPluginLoader loader(pluginPath);
+ if (!loader.load())
+ continue;
+
+ QDeclarativeInspectorInterface *inspector =
+ qobject_cast<QDeclarativeInspectorInterface*>(loader.instance());
+
+ if (inspector)
+ return inspector;
+ loader.unload();
+ }
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qdeclarativeinspectorservice_p.h b/src/declarative/debugger/qdeclarativeinspectorservice_p.h
new file mode 100644
index 00000000..623e850a
--- /dev/null
+++ b/src/declarative/debugger/qdeclarativeinspectorservice_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEOBSERVERSERVICE_H
+#define QDECLARATIVEOBSERVERSERVICE_H
+
+#include "private/qdeclarativedebugservice_p.h"
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtCore/QList>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeView;
+class QDeclarativeInspectorInterface;
+
+class Q_DECLARATIVE_EXPORT QDeclarativeInspectorService : public QDeclarativeDebugService
+{
+ Q_OBJECT
+
+public:
+ QDeclarativeInspectorService();
+ static QDeclarativeInspectorService *instance();
+
+ void addView(QDeclarativeView *);
+ void removeView(QDeclarativeView *);
+ QList<QDeclarativeView*> views() const { return m_views; }
+
+ void sendMessage(const QByteArray &message);
+
+Q_SIGNALS:
+ void gotMessage(const QByteArray &message);
+
+protected:
+ virtual void statusChanged(Status status);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ void updateStatus();
+
+ static QDeclarativeInspectorInterface *loadInspectorPlugin();
+
+ QList<QDeclarativeView*> m_views;
+ QDeclarativeInspectorInterface *m_inspectorPlugin;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEOBSERVERSERVICE_H
diff --git a/src/declarative/debugger/qjsdebuggeragent.cpp b/src/declarative/debugger/qjsdebuggeragent.cpp
new file mode 100644
index 00000000..9935ab11
--- /dev/null
+++ b/src/declarative/debugger/qjsdebuggeragent.cpp
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qjsdebuggeragent_p.h"
+#include "private/qdeclarativedebughelper_p.h"
+#include "private/qjsdebugservice_p.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qset.h>
+#include <QtCore/qurl.h>
+#include <QtScript/qscriptcontextinfo.h>
+#include <QtScript/qscriptengine.h>
+#include <QtScript/qscriptvalueiterator.h>
+
+QT_BEGIN_NAMESPACE
+
+class QJSDebuggerAgentPrivate
+{
+public:
+ QJSDebuggerAgentPrivate(QJSDebuggerAgent *q)
+ : q(q), state(NoState), isInitialized(false), coverageEnabled(false)
+ {}
+
+ void continueExec();
+ void recordKnownObjects(const QList<JSAgentWatchData> &);
+ QList<JSAgentWatchData> getLocals(QScriptContext *);
+ void positionChange(qint64 scriptId, int lineNumber, int columnNumber);
+ QScriptEngine *engine() { return q->engine(); }
+ void stopped();
+
+public:
+ QJSDebuggerAgent *q;
+ JSDebuggerState state;
+ int stepDepth;
+ int stepCount;
+
+ QEventLoop loop;
+ QHash<qint64, QString> filenames;
+ JSAgentBreakpoints breakpoints;
+ // breakpoints by filename (without path)
+ QHash<QString, JSAgentBreakpointData> fileNameToBreakpoints;
+ QStringList watchExpressions;
+ QSet<qint64> knownObjectIds;
+ bool isInitialized;
+ bool coverageEnabled;
+};
+
+namespace {
+
+class SetupExecEnv
+{
+public:
+ SetupExecEnv(QJSDebuggerAgentPrivate *a)
+ : agent(a),
+ previousState(a->state),
+ hadException(a->engine()->hasUncaughtException())
+ {
+ agent->state = StoppedState;
+ }
+
+ ~SetupExecEnv()
+ {
+ if (!hadException && agent->engine()->hasUncaughtException())
+ agent->engine()->clearExceptions();
+ agent->state = previousState;
+ }
+
+private:
+ QJSDebuggerAgentPrivate *agent;
+ JSDebuggerState previousState;
+ bool hadException;
+};
+
+} // anonymous namespace
+
+static JSAgentWatchData fromScriptValue(const QString &expression,
+ const QScriptValue &value)
+{
+ static const QString arrayStr = QCoreApplication::translate
+ ("Debugger::JSAgentWatchData", "[Array of length %1]");
+ static const QString undefinedStr = QCoreApplication::translate
+ ("Debugger::JSAgentWatchData", "<undefined>");
+
+ JSAgentWatchData data;
+ data.exp = expression.toUtf8();
+ data.name = data.exp;
+ data.hasChildren = false;
+ data.value = value.toString().toUtf8();
+ data.objectId = value.objectId();
+ if (value.isArray()) {
+ data.type = "Array";
+ data.value = arrayStr.arg(value.property(QLatin1String("length")).toString()).toUtf8();
+ data.hasChildren = true;
+ } else if (value.isBool()) {
+ data.type = "Bool";
+ // data.value = value.toBool() ? "true" : "false";
+ } else if (value.isDate()) {
+ data.type = "Date";
+ data.value = value.toDateTime().toString().toUtf8();
+ } else if (value.isError()) {
+ data.type = "Error";
+ } else if (value.isFunction()) {
+ data.type = "Function";
+ } else if (value.isUndefined()) {
+ data.type = undefinedStr.toUtf8();
+ } else if (value.isNumber()) {
+ data.type = "Number";
+ } else if (value.isRegExp()) {
+ data.type = "RegExp";
+ } else if (value.isString()) {
+ data.type = "String";
+ } else if (value.isVariant()) {
+ data.type = "Variant";
+ } else if (value.isQObject()) {
+ const QObject *obj = value.toQObject();
+ data.type = "Object";
+ data.value += '[';
+ data.value += obj->metaObject()->className();
+ data.value += ']';
+ data.hasChildren = true;
+ } else if (value.isObject()) {
+ data.type = "Object";
+ data.hasChildren = true;
+ data.value = "[Object]";
+ } else if (value.isNull()) {
+ data.type = "<null>";
+ } else {
+ data.type = "<unknown>";
+ }
+ return data;
+}
+
+static QList<JSAgentWatchData> expandObject(const QScriptValue &object)
+{
+ QList<JSAgentWatchData> result;
+ QScriptValueIterator it(object);
+ while (it.hasNext()) {
+ it.next();
+ if (it.flags() & QScriptValue::SkipInEnumeration)
+ continue;
+ if (/*object.isQObject() &&*/ it.value().isFunction()) {
+ // Cosmetics: skip all functions and slot, there are too many of them,
+ // and it is not useful information in the debugger.
+ continue;
+ }
+ JSAgentWatchData data = fromScriptValue(it.name(), it.value());
+ result.append(data);
+ }
+ if (result.isEmpty()) {
+ JSAgentWatchData data;
+ data.name = "<no initialized data>";
+ data.hasChildren = false;
+ data.value = " ";
+ data.objectId = 0;
+ result.append(data);
+ }
+ return result;
+}
+
+static QString fileName(const QString &fileUrl)
+{
+ int lastDelimiterPos = fileUrl.lastIndexOf(QLatin1Char('/'));
+ return fileUrl.mid(lastDelimiterPos, fileUrl.size() - lastDelimiterPos);
+}
+
+void QJSDebuggerAgentPrivate::recordKnownObjects(const QList<JSAgentWatchData>& list)
+{
+ foreach (const JSAgentWatchData &data, list)
+ knownObjectIds << data.objectId;
+}
+
+QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(QScriptContext *ctx)
+{
+ QList<JSAgentWatchData> locals;
+ if (ctx) {
+ QScriptValue activationObject = ctx->activationObject();
+ QScriptValue thisObject = ctx->thisObject();
+ locals = expandObject(activationObject);
+ if (thisObject.isObject()
+ && thisObject.objectId() != engine()->globalObject().objectId()
+ && QScriptValueIterator(thisObject).hasNext())
+ locals.prepend(fromScriptValue(QLatin1String("this"), thisObject));
+ recordKnownObjects(locals);
+ knownObjectIds << activationObject.objectId();
+ }
+ return locals;
+}
+
+/*!
+ Constructs a new agent for the given \a engine. The agent will
+ report debugging-related events (e.g. step completion) to the given
+ \a backend.
+*/
+QJSDebuggerAgent::QJSDebuggerAgent(QScriptEngine *engine, QObject *parent)
+ : QObject(parent)
+ , QScriptEngineAgent(engine)
+ , d(new QJSDebuggerAgentPrivate(this))
+{
+ QJSDebuggerAgent::engine()->setAgent(this);
+}
+
+QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent)
+ : QObject(parent)
+ , QScriptEngineAgent(QDeclarativeDebugHelper::getScriptEngine(engine))
+ , d(new QJSDebuggerAgentPrivate(this))
+{
+ QJSDebuggerAgent::engine()->setAgent(this);
+}
+
+/*!
+ Destroys this QJSDebuggerAgent.
+*/
+QJSDebuggerAgent::~QJSDebuggerAgent()
+{
+ engine()->setAgent(0);
+ delete d;
+}
+
+/*!
+ Indicates whether the agent got the list of breakpoints.
+ */
+bool QJSDebuggerAgent::isInitialized() const
+{
+ return d->isInitialized;
+}
+
+void QJSDebuggerAgent::setCoverageEnabled(bool enabled)
+{
+ d->isInitialized = true;
+ d->coverageEnabled = enabled;
+}
+
+void QJSDebuggerAgent::setBreakpoints(const JSAgentBreakpoints &breakpoints)
+{
+ d->breakpoints = breakpoints;
+
+ d->fileNameToBreakpoints.clear();
+ foreach (const JSAgentBreakpointData &bp, breakpoints)
+ d->fileNameToBreakpoints.insertMulti(fileName(QString::fromUtf8(bp.fileUrl)), bp);
+
+ d->isInitialized = true;
+}
+
+void QJSDebuggerAgent::setWatchExpressions(const QStringList &watchExpressions)
+{
+ d->watchExpressions = watchExpressions;
+}
+
+void QJSDebuggerAgent::stepOver()
+{
+ d->stepDepth = 0;
+ d->state = SteppingOverState;
+ d->continueExec();
+}
+
+void QJSDebuggerAgent::stepInto()
+{
+ d->stepDepth = 0;
+ d->state = SteppingIntoState;
+ d->continueExec();
+}
+
+void QJSDebuggerAgent::stepOut()
+{
+ d->stepDepth = 0;
+ d->state = SteppingOutState;
+ d->continueExec();
+}
+
+void QJSDebuggerAgent::continueExecution()
+{
+ d->state = NoState;
+ d->continueExec();
+}
+
+JSAgentWatchData QJSDebuggerAgent::executeExpression(const QString &expr)
+{
+ SetupExecEnv execEnv(d);
+
+ JSAgentWatchData data = fromScriptValue(expr, engine()->evaluate(expr));
+ d->knownObjectIds << data.objectId;
+ return data;
+}
+
+QList<JSAgentWatchData> QJSDebuggerAgent::expandObjectById(quint64 objectId)
+{
+ SetupExecEnv execEnv(d);
+
+ QScriptValue v;
+ if (d->knownObjectIds.contains(objectId))
+ v = engine()->objectById(objectId);
+
+ QList<JSAgentWatchData> result = expandObject(v);
+ d->recordKnownObjects(result);
+ return result;
+}
+
+QList<JSAgentWatchData> QJSDebuggerAgent::locals()
+{
+ SetupExecEnv execEnv(d);
+ return d->getLocals(engine()->currentContext());
+}
+
+QList<JSAgentWatchData> QJSDebuggerAgent::localsAtFrame(int frameId)
+{
+ SetupExecEnv execEnv(d);
+
+ int deep = 0;
+ QScriptContext *ctx = engine()->currentContext();
+ while (ctx && deep < frameId) {
+ ctx = ctx->parentContext();
+ deep++;
+ }
+
+ return d->getLocals(ctx);
+}
+
+QList<JSAgentStackData> QJSDebuggerAgent::backtrace()
+{
+ SetupExecEnv execEnv(d);
+
+ QList<JSAgentStackData> backtrace;
+
+ for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) {
+ QScriptContextInfo info(ctx);
+
+ JSAgentStackData frame;
+ frame.functionName = info.functionName().toUtf8();
+ if (frame.functionName.isEmpty()) {
+ if (ctx->parentContext()) {
+ switch (info.functionType()) {
+ case QScriptContextInfo::ScriptFunction:
+ frame.functionName = "<anonymous>";
+ break;
+ case QScriptContextInfo::NativeFunction:
+ frame.functionName = "<native>";
+ break;
+ case QScriptContextInfo::QtFunction:
+ case QScriptContextInfo::QtPropertyFunction:
+ frame.functionName = "<native slot>";
+ break;
+ }
+ } else {
+ frame.functionName = "<global>";
+ }
+ }
+ frame.lineNumber = info.lineNumber();
+ // if the line number is unknown, fallback to the function line number
+ if (frame.lineNumber == -1)
+ frame.lineNumber = info.functionStartLineNumber();
+
+ frame.fileUrl = info.fileName().toUtf8();
+ backtrace.append(frame);
+ }
+
+ return backtrace;
+}
+
+QList<JSAgentWatchData> QJSDebuggerAgent::watches()
+{
+ SetupExecEnv execEnv(d);
+
+ QList<JSAgentWatchData> watches;
+ foreach (const QString &expr, d->watchExpressions)
+ watches << fromScriptValue(expr, engine()->evaluate(expr));
+ d->recordKnownObjects(watches);
+ return watches;
+}
+
+void QJSDebuggerAgent::setProperty(qint64 objectId,
+ const QString &property,
+ const QString &value)
+{
+ SetupExecEnv execEnv(d);
+
+ if (d->knownObjectIds.contains(objectId)) {
+ QScriptValue object = engine()->objectById(objectId);
+ if (object.isObject()) {
+ QScriptValue result = engine()->evaluate(value);
+ object.setProperty(property, result);
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::scriptLoad(qint64 id, const QString &program,
+ const QString &fileName, int baseLineNumber)
+{
+ d->filenames.insert(id, fileName);
+
+ if (d->coverageEnabled) {
+ JSAgentCoverageData rd = {"COVERAGE", QJSDebugService::instance()->m_timer.elapsed(), (int)CoverageScriptLoad,
+ id, program, fileName, baseLineNumber,
+ 0, 0, QString()};
+ QJSDebugService::instance()->processMessage(rd);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::scriptUnload(qint64 id)
+{
+ d->filenames.remove(id);
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::contextPush()
+{
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::contextPop()
+{
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::functionEntry(qint64 scriptId)
+{
+ d->stepDepth++;
+
+ if (d->coverageEnabled) {
+ JSAgentCoverageData rd = {"COVERAGE", QJSDebugService::instance()->m_timer.elapsed(), (int)CoverageFuncEntry,
+ scriptId, QString(), QString(), 0, 0, 0, QString()};
+ QJSDebugService::instance()->processMessage(rd);
+ QJSDebugService::instance()->m_timer.restart();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::functionExit(qint64 scriptId, const QScriptValue &returnValue)
+{
+ d->stepDepth--;
+
+ if (d->coverageEnabled) {
+ JSAgentCoverageData rd = {"COVERAGE", QJSDebugService::instance()->m_timer.elapsed(), (int)CoverageFuncExit,
+ scriptId, QString(), QString(), 0, 0, 0, returnValue.toString()};
+ QJSDebugService::instance()->processMessage(rd);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::positionChange(qint64 scriptId, int lineNumber, int columnNumber)
+{
+ d->positionChange(scriptId, lineNumber, columnNumber);
+
+ if (d->coverageEnabled) {
+ JSAgentCoverageData rd = {"COVERAGE", QJSDebugService::instance()->m_timer.elapsed(), (int)CoveragePosChange,
+ scriptId, QString(), QString(), 0, lineNumber, columnNumber, QString()};
+ QJSDebugService::instance()->processMessage(rd);
+ }
+}
+
+void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, int columnNumber)
+{
+ Q_UNUSED(columnNumber);
+
+ if (state == StoppedState)
+ return; //no re-entrency
+
+ // check breakpoints
+ if (!breakpoints.isEmpty()) {
+ const QScriptContext *ctx = engine()->currentContext();
+ const QScriptContextInfo info(ctx);
+
+ if (info.functionType() == QScriptContextInfo::ScriptFunction) {
+ QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId);
+ // It is possible that the scripts are loaded before the agent is attached
+ if (it == filenames.constEnd()) {
+ it = filenames.insert(scriptId, info.fileName());
+ }
+
+ const QString filePath = it.value();
+ const JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet();
+
+ foreach (const JSAgentBreakpointData &bp, bps) {
+ if (bp.lineNumber == lineNumber) {
+ stopped();
+ return;
+ }
+ }
+ }
+ }
+
+ switch (state) {
+ case NoState:
+ case StoppedState:
+ // Do nothing
+ break;
+ case SteppingOutState:
+ if (stepDepth >= 0)
+ break;
+ //fallthough
+ case SteppingOverState:
+ if (stepDepth > 0)
+ break;
+ //fallthough
+ case SteppingIntoState:
+ stopped();
+ break;
+ }
+
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::exceptionThrow(qint64 scriptId,
+ const QScriptValue &exception,
+ bool hasHandler)
+{
+ Q_UNUSED(scriptId);
+ Q_UNUSED(exception);
+ Q_UNUSED(hasHandler);
+// qDebug() << Q_FUNC_INFO << exception.toString() << hasHandler;
+#if 0 //sometimes, we get exceptions that we should just ignore.
+ if (!hasHandler && state != StoppedState)
+ stopped(true, exception);
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QScriptValue &exception)
+{
+ Q_UNUSED(scriptId);
+ Q_UNUSED(exception);
+}
+
+bool QJSDebuggerAgent::supportsExtension(Extension extension) const
+{
+ return extension == QScriptEngineAgent::DebuggerInvocationRequest;
+}
+
+QVariant QJSDebuggerAgent::extension(Extension extension, const QVariant &argument)
+{
+ if (extension == QScriptEngineAgent::DebuggerInvocationRequest) {
+ d->stopped();
+ return QVariant();
+ }
+ return QScriptEngineAgent::extension(extension, argument);
+}
+
+void QJSDebuggerAgentPrivate::stopped()
+{
+ bool becauseOfException = false;
+ const QScriptValue &exception = QScriptValue();
+
+ knownObjectIds.clear();
+ state = StoppedState;
+
+ emit q->stopped(becauseOfException, exception.toString());
+
+ loop.exec(QEventLoop::ExcludeUserInputEvents);
+}
+
+void QJSDebuggerAgentPrivate::continueExec()
+{
+ loop.quit();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qjsdebuggeragent_p.h b/src/declarative/debugger/qjsdebuggeragent_p.h
new file mode 100644
index 00000000..a4ffc187
--- /dev/null
+++ b/src/declarative/debugger/qjsdebuggeragent_p.h
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSDEBUGGERAGENT_P_H
+#define QJSDEBUGGERAGENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtScript/qscriptengineagent.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_NAMESPACE
+class QScriptValue;
+class QDeclarativeEngine;
+QT_END_NAMESPACE
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QJSDebuggerAgentPrivate;
+
+enum JSDebuggerState
+{
+ NoState,
+ SteppingIntoState,
+ SteppingOverState,
+ SteppingOutState,
+ StoppedState
+};
+
+enum JSCoverageMessage {
+ CoverageLocation,
+ CoverageScriptLoad,
+ CoveragePosChange,
+ CoverageFuncEntry,
+ CoverageFuncExit,
+ CoverageComplete,
+
+ CoverageMaximumMessage
+};
+
+struct JSAgentWatchData
+{
+ QByteArray exp;
+ QByteArray name;
+ QByteArray value;
+ QByteArray type;
+ bool hasChildren;
+ quint64 objectId;
+};
+
+inline QDataStream &operator<<(QDataStream &s, const JSAgentWatchData &data)
+{
+ return s << data.exp << data.name << data.value
+ << data.type << data.hasChildren << data.objectId;
+}
+
+inline QDataStream &operator>>(QDataStream &s, JSAgentWatchData &data)
+{
+ return s >> data.exp >> data.name >> data.value
+ >> data.type >> data.hasChildren >> data.objectId;
+}
+
+struct JSAgentStackData
+{
+ QByteArray functionName;
+ QByteArray fileUrl;
+ qint32 lineNumber;
+};
+
+inline QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
+{
+ return s << data.functionName << data.fileUrl << data.lineNumber;
+}
+
+inline QDataStream &operator>>(QDataStream &s, JSAgentStackData &data)
+{
+ return s >> data.functionName >> data.fileUrl >> data.lineNumber;
+}
+
+struct JSAgentBreakpointData
+{
+ QByteArray functionName;
+ QByteArray fileUrl;
+ qint32 lineNumber;
+};
+
+typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
+
+inline QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
+{
+ return s << data.functionName << data.fileUrl << data.lineNumber;
+}
+
+inline QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
+{
+ return s >> data.functionName >> data.fileUrl >> data.lineNumber;
+}
+
+inline bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
+{
+ return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl;
+}
+
+inline uint qHash(const JSAgentBreakpointData &b)
+{
+ return b.lineNumber ^ qHash(b.fileUrl);
+}
+
+
+class QJSDebuggerAgent : public QObject, public QScriptEngineAgent
+{
+ Q_OBJECT
+
+public:
+ QJSDebuggerAgent(QScriptEngine *engine, QObject *parent = 0);
+ QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent = 0);
+ ~QJSDebuggerAgent();
+
+ bool isInitialized() const;
+
+ void setBreakpoints(const JSAgentBreakpoints &);
+ void setWatchExpressions(const QStringList &);
+
+ void stepOver();
+ void stepInto();
+ void stepOut();
+ void continueExecution();
+ void setCoverageEnabled(bool enabled);
+
+ JSAgentWatchData executeExpression(const QString &expr);
+ QList<JSAgentWatchData> expandObjectById(quint64 objectId);
+ QList<JSAgentWatchData> locals();
+ QList<JSAgentWatchData> localsAtFrame(int frameId);
+ QList<JSAgentStackData> backtrace();
+ QList<JSAgentWatchData> watches();
+ void setProperty(qint64 objectId,
+ const QString &property,
+ const QString &value);
+
+ // reimplemented
+ void scriptLoad(qint64 id, const QString &program,
+ const QString &fileName, int baseLineNumber);
+ void scriptUnload(qint64 id);
+
+ void contextPush();
+ void contextPop();
+
+ void functionEntry(qint64 scriptId);
+ void functionExit(qint64 scriptId,
+ const QScriptValue &returnValue);
+
+ void positionChange(qint64 scriptId,
+ int lineNumber, int columnNumber);
+
+ void exceptionThrow(qint64 scriptId,
+ const QScriptValue &exception,
+ bool hasHandler);
+ void exceptionCatch(qint64 scriptId,
+ const QScriptValue &exception);
+
+ bool supportsExtension(Extension extension) const;
+ QVariant extension(Extension extension,
+ const QVariant &argument = QVariant());
+
+Q_SIGNALS:
+ void stopped(bool becauseOfException,
+ const QString &exception);
+
+private:
+ friend class QJSDebuggerAgentPrivate;
+ QJSDebuggerAgentPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QJSDEBUGGERAGENT_P_H
diff --git a/src/declarative/debugger/qjsdebugservice.cpp b/src/declarative/debugger/qjsdebugservice.cpp
new file mode 100644
index 00000000..686710dc
--- /dev/null
+++ b/src/declarative/debugger/qjsdebugservice.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qjsdebugservice_p.h"
+#include "private/qjsdebuggeragent_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+
+Q_GLOBAL_STATIC(QJSDebugService, serviceInstance)
+
+// convert to a QByteArray that can be sent to the debug client
+QByteArray JSAgentCoverageData::toByteArray() const
+{
+ QByteArray data;
+ //### using QDataStream is relatively expensive
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << prefix << time << messageType << scriptId << program << fileName << baseLineNumber
+ << lineNumber << columnNumber << returnValue;
+ return data;
+}
+
+QJSDebugService::QJSDebugService(QObject *parent)
+ : QDeclarativeDebugService(QLatin1String("JSDebugger"), parent)
+ , m_agent(0), m_deferredSend(true)
+{
+ m_timer.start();
+}
+
+QJSDebugService::~QJSDebugService()
+{
+ delete m_agent;
+}
+
+QJSDebugService *QJSDebugService::instance()
+{
+ return serviceInstance();
+}
+
+void QJSDebugService::addEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(!m_engines.contains(engine));
+
+ m_engines.append(engine);
+
+ if (status() == Enabled && !m_engines.isEmpty() && !m_agent) {
+ m_agent = new QJSDebuggerAgent(engine, engine);
+ connect(m_agent, SIGNAL(stopped(bool,QString)),
+ this, SLOT(executionStopped(bool,QString)));
+
+ while (!m_agent->isInitialized()) {
+ waitForMessage();
+ }
+ }
+}
+
+void QJSDebugService::removeEngine(QDeclarativeEngine *engine)
+{
+ Q_ASSERT(engine);
+ Q_ASSERT(m_engines.contains(engine));
+
+ m_engines.removeAll(engine);
+}
+
+void QJSDebugService::statusChanged(Status status)
+{
+ if (status == Enabled && !m_engines.isEmpty() && !m_agent) {
+ // Multiple engines are currently unsupported
+ QDeclarativeEngine *engine = m_engines.first();
+ m_agent = new QJSDebuggerAgent(engine, engine);
+
+ connect(m_agent, SIGNAL(stopped(bool,QString)),
+ this, SLOT(executionStopped(bool,QString)));
+
+ } else if (status != Enabled && m_agent) {
+ delete m_agent;
+ m_agent = 0;
+ }
+}
+
+void QJSDebugService::messageReceived(const QByteArray &message)
+{
+ if (!m_agent) {
+ qWarning() << "QJSDebugService::messageReceived: No QJSDebuggerAgent available";
+ return;
+ }
+
+ QDataStream ds(message);
+ QByteArray command;
+ ds >> command;
+ if (command == "BREAKPOINTS") {
+ JSAgentBreakpoints breakpoints;
+ ds >> breakpoints;
+ m_agent->setBreakpoints(breakpoints);
+
+ //qDebug() << "BREAKPOINTS";
+ //foreach (const JSAgentBreakpointData &bp, breakpoints)
+ // qDebug() << "BREAKPOINT: " << bp.fileUrl << bp.lineNumber;
+ } else if (command == "WATCH_EXPRESSIONS") {
+ QStringList watchExpressions;
+ ds >> watchExpressions;
+ m_agent->setWatchExpressions(watchExpressions);
+ } else if (command == "STEPOVER") {
+ m_agent->stepOver();
+ } else if (command == "STEPINTO" || command == "INTERRUPT") {
+ m_agent->stepInto();
+ } else if (command == "STEPOUT") {
+ m_agent->stepOut();
+ } else if (command == "CONTINUE") {
+ m_agent->continueExecution();
+ } else if (command == "EXEC") {
+ QByteArray id;
+ QString expr;
+ ds >> id >> expr;
+
+ JSAgentWatchData data = m_agent->executeExpression(expr);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("RESULT") << id << data;
+ sendMessage(reply);
+ } else if (command == "EXPAND") {
+ QByteArray requestId;
+ quint64 objectId;
+ ds >> requestId >> objectId;
+
+ QList<JSAgentWatchData> result = m_agent->expandObjectById(objectId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("EXPANDED") << requestId << result;
+ sendMessage(reply);
+ } else if (command == "ACTIVATE_FRAME") {
+ int frameId;
+ ds >> frameId;
+
+ QList<JSAgentWatchData> locals = m_agent->localsAtFrame(frameId);
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("LOCALS") << frameId << locals;
+ sendMessage(reply);
+ } else if (command == "SET_PROPERTY") {
+ QByteArray id;
+ qint64 objectId;
+ QString property;
+ QString value;
+ ds >> id >> objectId >> property >> value;
+
+ m_agent->setProperty(objectId, property, value);
+
+ //TODO: feedback
+ } else if (command == "PING") {
+ int ping;
+ ds >> ping;
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("PONG") << ping;
+ sendMessage(reply);
+ } else if (command == "COVERAGE") {
+ bool enabled;
+ ds >> enabled;
+ m_agent->setCoverageEnabled(enabled);
+ if (!enabled) {
+ sendMessages();
+ }
+ } else {
+ qDebug() << Q_FUNC_INFO << "Unknown command" << command;
+ }
+
+ QDeclarativeDebugService::messageReceived(message);
+}
+
+void QJSDebugService::executionStopped(bool becauseOfException,
+ const QString &exception)
+{
+ const QList<JSAgentStackData> backtrace = m_agent->backtrace();
+ const QList<JSAgentWatchData> watches = m_agent->watches();
+ const QList<JSAgentWatchData> locals = m_agent->locals();
+
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << QByteArray("STOPPED") << backtrace << watches << locals
+ << becauseOfException << exception;
+ sendMessage(reply);
+}
+
+/*
+ Either send the message directly, or queue up
+ a list of messages to send later (via sendMessages)
+*/
+void QJSDebugService::processMessage(const JSAgentCoverageData &message)
+{
+ if (m_deferredSend)
+ m_data.append(message);
+ else
+ sendMessage(message.toByteArray());
+}
+
+/*
+ Send the messages queued up by processMessage
+*/
+void QJSDebugService::sendMessages()
+{
+ if (m_deferredSend) {
+ //### this is a suboptimal way to send batched messages
+ for (int i = 0; i < m_data.count(); ++i)
+ sendMessage(m_data.at(i).toByteArray());
+ m_data.clear();
+
+ //indicate completion
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << QByteArray("COVERAGE") << (qint64)-1 << (int)CoverageComplete;
+ sendMessage(data);
+ }
+}
+
diff --git a/src/declarative/debugger/qjsdebugservice_p.h b/src/declarative/debugger/qjsdebugservice_p.h
new file mode 100644
index 00000000..399b0fba
--- /dev/null
+++ b/src/declarative/debugger/qjsdebugservice_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJSDEBUGSERVICE_P_H
+#define QJSDEBUGSERVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QPointer>
+#include <QElapsedTimer>
+
+#include "private/qdeclarativedebugservice_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeEngine;
+class QJSDebuggerAgent;
+
+struct JSAgentCoverageData
+{
+ QByteArray prefix;
+ qint64 time;
+ int messageType;
+
+ qint64 scriptId;
+ QString program;
+ QString fileName;
+ int baseLineNumber;
+ int lineNumber;
+ int columnNumber;
+ QString returnValue;
+
+ QByteArray toByteArray() const;
+};
+
+class QJSDebugService : public QDeclarativeDebugService
+{
+ Q_OBJECT
+
+public:
+ QJSDebugService(QObject *parent = 0);
+ ~QJSDebugService();
+
+ static QJSDebugService *instance();
+
+ void addEngine(QDeclarativeEngine *);
+ void removeEngine(QDeclarativeEngine *);
+ void processMessage(const JSAgentCoverageData &message);
+
+ QElapsedTimer m_timer;
+
+protected:
+ void statusChanged(Status status);
+ void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void executionStopped(bool becauseOfException,
+ const QString &exception);
+
+private:
+ void sendMessages();
+ QList<QDeclarativeEngine *> m_engines;
+ QPointer<QJSDebuggerAgent> m_agent;
+ bool m_deferredSend;
+ QList<JSAgentCoverageData> m_data;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QJSDEBUGSERVICE_P_H
diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp
new file mode 100644
index 00000000..6732c850
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol.cpp
@@ -0,0 +1,557 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qpacketprotocol_p.h"
+
+#include <QBuffer>
+#include <QElapsedTimer>
+
+QT_BEGIN_NAMESPACE
+
+#define MAX_PACKET_SIZE 0x7FFFFFFF
+
+/*!
+ \class QPacketProtocol
+ \internal
+
+ \brief The QPacketProtocol class encapsulates communicating discrete packets
+ across fragmented IO channels, such as TCP sockets.
+
+ QPacketProtocol makes it simple to send arbitrary sized data "packets" across
+ fragmented transports such as TCP and UDP.
+
+ As transmission boundaries are not respected, sending packets over protocols
+ like TCP frequently involves "stitching" them back together at the receiver.
+ QPacketProtocol makes this easier by performing this task for you. Packet
+ data sent using QPacketProtocol is prepended with a 4-byte size header
+ allowing the receiving QPacketProtocol to buffer the packet internally until
+ it has all been received. QPacketProtocol does not perform any sanity
+ checking on the size or on the data, so this class should only be used in
+ prototyping or trusted situations where DOS attacks are unlikely.
+
+ QPacketProtocol does not perform any communications itself. Instead it can
+ operate on any QIODevice that supports the QIODevice::readyRead() signal. A
+ logical "packet" is encapsulated by the companion QPacket class. The
+ following example shows two ways to send data using QPacketProtocol. The
+ transmitted data is equivalent in both.
+
+ \code
+ QTcpSocket socket;
+ // ... connect socket ...
+
+ QPacketProtocol protocol(&socket);
+
+ // Send packet the quick way
+ protocol.send() << "Hello world" << 123;
+
+ // Send packet the longer way
+ QPacket packet;
+ packet << "Hello world" << 123;
+ protocol.send(packet);
+ \endcode
+
+ Likewise, the following shows how to read data from QPacketProtocol, assuming
+ that the QPacketProtocol::readyRead() signal has been emitted.
+
+ \code
+ // ... QPacketProtocol::readyRead() is emitted ...
+
+ int a;
+ QByteArray b;
+
+ // Receive packet the quick way
+ protocol.read() >> a >> b;
+
+ // Receive packet the longer way
+ QPacket packet = protocol.read();
+ p >> a >> b;
+ \endcode
+
+ \ingroup io
+ \sa QPacket
+*/
+
+class QPacketProtocolPrivate : public QObject
+{
+Q_OBJECT
+public:
+ QPacketProtocolPrivate(QPacketProtocol * parent, QIODevice * _dev)
+ : QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE),
+ waitingForPacket(false), dev(_dev)
+ {
+ Q_ASSERT(4 == sizeof(qint32));
+
+ QObject::connect(this, SIGNAL(readyRead()),
+ parent, SIGNAL(readyRead()));
+ QObject::connect(this, SIGNAL(packetWritten()),
+ parent, SIGNAL(packetWritten()));
+ QObject::connect(this, SIGNAL(invalidPacket()),
+ parent, SIGNAL(invalidPacket()));
+ QObject::connect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()));
+ QObject::connect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::connect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ }
+
+Q_SIGNALS:
+ void readyRead();
+ void packetWritten();
+ void invalidPacket();
+
+public Q_SLOTS:
+ void aboutToClose()
+ {
+ inProgress.clear();
+ sendingPackets.clear();
+ inProgressSize = -1;
+ }
+
+ void bytesWritten(qint64 bytes)
+ {
+ Q_ASSERT(!sendingPackets.isEmpty());
+
+ while(bytes) {
+ if(sendingPackets.at(0) > bytes) {
+ sendingPackets[0] -= bytes;
+ bytes = 0;
+ } else {
+ bytes -= sendingPackets.at(0);
+ sendingPackets.removeFirst();
+ emit packetWritten();
+ }
+ }
+ }
+
+ void readyToRead()
+ {
+ bool gotPackets = false;
+ while (true) {
+ // Get size header (if not in progress)
+ if (-1 == inProgressSize) {
+ // We need a size header of sizeof(qint32)
+ if (sizeof(qint32) > (uint)dev->bytesAvailable()) {
+ if (gotPackets)
+ emit readyRead();
+ return; // no more data available
+ }
+
+ // Read size header
+ int read = dev->read((char *)&inProgressSize, sizeof(qint32));
+ Q_ASSERT(read == sizeof(qint32));
+ Q_UNUSED(read);
+
+ // Check sizing constraints
+ if (inProgressSize > maxPacketSize) {
+ QObject::disconnect(dev, SIGNAL(readyRead()),
+ this, SLOT(readyToRead()));
+ QObject::disconnect(dev, SIGNAL(aboutToClose()),
+ this, SLOT(aboutToClose()));
+ QObject::disconnect(dev, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)));
+ dev = 0;
+ emit invalidPacket();
+ return;
+ }
+
+ inProgressSize -= sizeof(qint32);
+ } else {
+ inProgress.append(dev->read(inProgressSize - inProgress.size()));
+
+ if (inProgressSize == inProgress.size()) {
+ // Packet has arrived!
+ packets.append(inProgress);
+ inProgressSize = -1;
+ inProgress.clear();
+
+ waitingForPacket = false;
+ gotPackets = true;
+ } else {
+ if (gotPackets)
+ emit readyRead();
+ return; // packet in progress is not yet complete
+ }
+ }
+ }
+ }
+
+public:
+ QList<qint64> sendingPackets;
+ QList<QByteArray> packets;
+ QByteArray inProgress;
+ qint32 inProgressSize;
+ qint32 maxPacketSize;
+ bool waitingForPacket;
+ QIODevice * dev;
+};
+
+/*!
+ Construct a QPacketProtocol instance that works on \a dev with the
+ specified \a parent.
+ */
+QPacketProtocol::QPacketProtocol(QIODevice * dev, QObject * parent)
+: QObject(parent), d(new QPacketProtocolPrivate(this, dev))
+{
+ Q_ASSERT(dev);
+}
+
+/*!
+ Destroys the QPacketProtocol instance.
+ */
+QPacketProtocol::~QPacketProtocol()
+{
+}
+
+/*!
+ Returns the maximum packet size allowed. By default this is
+ 2,147,483,647 bytes.
+
+ If a packet claiming to be larger than the maximum packet size is received,
+ the QPacketProtocol::invalidPacket() signal is emitted.
+
+ \sa QPacketProtocol::setMaximumPacketSize()
+ */
+qint32 QPacketProtocol::maximumPacketSize() const
+{
+ return d->maxPacketSize;
+}
+
+/*!
+ Sets the maximum allowable packet size to \a max.
+
+ \sa QPacketProtocol::maximumPacketSize()
+ */
+qint32 QPacketProtocol::setMaximumPacketSize(qint32 max)
+{
+ if(max > (signed)sizeof(qint32))
+ d->maxPacketSize = max;
+ return d->maxPacketSize;
+}
+
+/*!
+ Returns a streamable object that is transmitted on destruction. For example
+
+ \code
+ protocol.send() << "Hello world" << 123;
+ \endcode
+
+ will send a packet containing "Hello world" and 123. To construct more
+ complex packets, explicitly construct a QPacket instance.
+ */
+QPacketAutoSend QPacketProtocol::send()
+{
+ return QPacketAutoSend(this);
+}
+
+/*!
+ \fn void QPacketProtocol::send(const QPacket & packet)
+
+ Transmit the \a packet.
+ */
+void QPacketProtocol::send(const QPacket & p)
+{
+ if(p.b.isEmpty())
+ return; // We don't send empty packets
+
+ qint64 sendSize = p.b.size() + sizeof(qint32);
+
+ d->sendingPackets.append(sendSize);
+ qint32 sendSize32 = sendSize;
+ qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32));
+ Q_ASSERT(writeBytes == sizeof(qint32));
+ writeBytes = d->dev->write(p.b);
+ Q_ASSERT(writeBytes == p.b.size());
+}
+
+/*!
+ Returns the number of received packets yet to be read.
+ */
+qint64 QPacketProtocol::packetsAvailable() const
+{
+ return d->packets.count();
+}
+
+/*!
+ Discard any unread packets.
+ */
+void QPacketProtocol::clear()
+{
+ d->packets.clear();
+}
+
+/*!
+ Return the next unread packet, or an invalid QPacket instance if no packets
+ are available. This method does NOT block.
+ */
+QPacket QPacketProtocol::read()
+{
+ if(0 == d->packets.count())
+ return QPacket();
+
+ QPacket rv(d->packets.at(0));
+ d->packets.removeFirst();
+ return rv;
+}
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+/*!
+ This function locks until a new packet is available for reading and the
+ \l{QIODevice::}{readyRead()} signal has been emitted. The function
+ will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns true if the readyRead() signal is emitted and
+ there is new data available for reading; otherwise it returns false
+ (if an error occurred or the operation timed out).
+ */
+
+bool QPacketProtocol::waitForReadyRead(int msecs)
+{
+ if (!d->packets.isEmpty())
+ return true;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ d->waitingForPacket = true;
+ do {
+ if (!d->dev->waitForReadyRead(msecs))
+ return false;
+ if (!d->waitingForPacket)
+ return true;
+ msecs = qt_timeout_value(msecs, stopWatch.elapsed());
+ } while (true);
+}
+
+/*!
+ Return the QIODevice passed to the QPacketProtocol constructor.
+*/
+QIODevice * QPacketProtocol::device()
+{
+ return d->dev;
+}
+
+/*!
+ \fn void QPacketProtocol::readyRead()
+
+ Emitted whenever a new packet is received. Applications may use
+ QPacketProtocol::read() to retrieve this packet.
+ */
+
+/*!
+ \fn void QPacketProtocol::invalidPacket()
+
+ A packet larger than the maximum allowable packet size was received. The
+ packet will be discarded and, as it indicates corruption in the protocol, no
+ further packets will be received.
+ */
+
+/*!
+ \fn void QPacketProtocol::packetWritten()
+
+ Emitted each time a packet is completing written to the device. This signal
+ may be used for communications flow control.
+ */
+
+/*!
+ \class QPacket
+ \internal
+
+ \brief The QPacket class encapsulates an unfragmentable packet of data to be
+ transmitted by QPacketProtocol.
+
+ The QPacket class works together with QPacketProtocol to make it simple to
+ send arbitrary sized data "packets" across fragmented transports such as TCP
+ and UDP.
+
+ QPacket provides a QDataStream interface to an unfragmentable packet.
+ Applications should construct a QPacket, propagate it with data and then
+ transmit it over a QPacketProtocol instance. For example:
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket myPacket;
+ myPacket << "Hello world!" << 123;
+ protocol.send(myPacket);
+ \endcode
+
+ As long as both ends of the connection are using the QPacketProtocol class,
+ the data within this packet will be delivered unfragmented at the other end,
+ ready for extraction.
+
+ \code
+ QByteArray greeting;
+ int count;
+
+ QPacket myPacket = protocol.read();
+
+ myPacket >> greeting >> count;
+ \endcode
+
+ Only packets returned from QPacketProtocol::read() may be read from. QPacket
+ instances constructed by directly by applications are for transmission only
+ and are considered "write only". Attempting to read data from them will
+ result in undefined behavior.
+
+ \ingroup io
+ \sa QPacketProtocol
+ */
+
+/*!
+ Constructs an empty write-only packet.
+ */
+QPacket::QPacket()
+: QDataStream(), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::WriteOnly);
+ setDevice(buf);
+ setVersion(QDataStream::Qt_4_7);
+}
+
+/*!
+ Destroys the QPacket instance.
+ */
+QPacket::~QPacket()
+{
+ if(buf) {
+ delete buf;
+ buf = 0;
+ }
+}
+
+/*!
+ Creates a copy of \a other. The initial stream positions are shared, but the
+ two packets are otherwise independent.
+ */
+QPacket::QPacket(const QPacket & other)
+: QDataStream(), b(other.b), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(other.buf->openMode());
+ setDevice(buf);
+}
+
+/*!
+ \internal
+ */
+QPacket::QPacket(const QByteArray & ba)
+: QDataStream(), b(ba), buf(0)
+{
+ buf = new QBuffer(&b);
+ buf->open(QIODevice::ReadOnly);
+ setDevice(buf);
+}
+
+/*!
+ Returns true if this packet is empty - that is, contains no data.
+ */
+bool QPacket::isEmpty() const
+{
+ return b.isEmpty();
+}
+
+/*!
+ Returns raw packet data.
+ */
+QByteArray QPacket::data() const
+{
+ return b;
+}
+
+/*!
+ Clears data in the packet. This is useful for reusing one writable packet.
+ For example
+ \code
+ QPacketProtocol protocol(...);
+
+ QPacket packet;
+
+ packet << "Hello world!" << 123;
+ protocol.send(packet);
+
+ packet.clear();
+ packet << "Goodbyte world!" << 789;
+ protocol.send(packet);
+ \endcode
+ */
+void QPacket::clear()
+{
+ QBuffer::OpenMode oldMode = buf->openMode();
+ buf->close();
+ b.clear();
+ buf->setBuffer(&b); // reset QBuffer internals with new size of b.
+ buf->open(oldMode);
+}
+
+/*!
+ \class QPacketAutoSend
+ \internal
+
+ \internal
+ */
+QPacketAutoSend::QPacketAutoSend(QPacketProtocol * _p)
+: QPacket(), p(_p)
+{
+}
+
+QPacketAutoSend::~QPacketAutoSend()
+{
+ if(!b.isEmpty())
+ p->send(*this);
+}
+
+QT_END_NAMESPACE
+
+#include <qpacketprotocol.moc>
diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h
new file mode 100644
index 00000000..62dedf4d
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** 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.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPACKETPROTOCOL_H
+#define QPACKETPROTOCOL_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatastream.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QIODevice;
+class QBuffer;
+class QPacket;
+class QPacketAutoSend;
+class QPacketProtocolPrivate;
+
+class Q_DECLARATIVE_EXPORT QPacketProtocol : public QObject
+{
+Q_OBJECT
+public:
+ explicit QPacketProtocol(QIODevice * dev, QObject * parent = 0);
+ virtual ~QPacketProtocol();
+
+ qint32 maximumPacketSize() const;
+ qint32 setMaximumPacketSize(qint32);
+
+ QPacketAutoSend send();
+ void send(const QPacket &);
+
+ qint64 packetsAvailable() const;
+ QPacket read();
+
+ bool waitForReadyRead(int msecs = 3000);
+
+ void clear();
+
+ QIODevice * device();
+
+Q_SIGNALS:
+ void readyRead();
+ void invalidPacket();
+ void packetWritten();
+
+private:
+ QPacketProtocolPrivate * d;
+};
+
+
+class Q_DECLARATIVE_EXPORT QPacket : public QDataStream
+{
+public:
+ QPacket();
+ QPacket(const QPacket &);
+ virtual ~QPacket();
+
+ void clear();
+ bool isEmpty() const;
+ QByteArray data() const;
+
+protected:
+ friend class QPacketProtocol;
+ QPacket(const QByteArray & ba);
+ QByteArray b;
+ QBuffer * buf;
+};
+
+class Q_DECLARATIVE_PRIVATE_EXPORT QPacketAutoSend : public QPacket
+{
+public:
+ virtual ~QPacketAutoSend();
+
+private:
+ friend class QPacketProtocol;
+ QPacketAutoSend(QPacketProtocol *);
+ QPacketProtocol * p;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif