summaryrefslogtreecommitdiffstats
path: root/src/declarative/debugger
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/debugger')
-rw-r--r--src/declarative/debugger/debugger.pri15
-rw-r--r--src/declarative/debugger/qmldebug.cpp934
-rw-r--r--src/declarative/debugger/qmldebug_p.h366
-rw-r--r--src/declarative/debugger/qmldebugclient.cpp207
-rw-r--r--src/declarative/debugger/qmldebugclient_p.h99
-rw-r--r--src/declarative/debugger/qmldebuggerstatus.cpp54
-rw-r--r--src/declarative/debugger/qmldebuggerstatus_p.h66
-rw-r--r--src/declarative/debugger/qmldebugservice.cpp393
-rw-r--r--src/declarative/debugger/qmldebugservice_p.h90
-rw-r--r--src/declarative/debugger/qpacketprotocol.cpp498
-rw-r--r--src/declarative/debugger/qpacketprotocol_p.h122
11 files changed, 2844 insertions, 0 deletions
diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri
new file mode 100644
index 0000000..261b2ff
--- /dev/null
+++ b/src/declarative/debugger/debugger.pri
@@ -0,0 +1,15 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qmldebuggerstatus.cpp \
+ $$PWD/qpacketprotocol.cpp \
+ $$PWD/qmldebugservice.cpp \
+ $$PWD/qmldebugclient.cpp \
+ $$PWD/qmldebug.cpp
+
+HEADERS += \
+ $$PWD/qmldebuggerstatus_p.h \
+ $$PWD/qpacketprotocol_p.h \
+ $$PWD/qmldebugservice_p.h \
+ $$PWD/qmldebugclient_p.h \
+ $$PWD/qmldebug_p.h
diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp
new file mode 100644
index 0000000..dc779ac
--- /dev/null
+++ b/src/declarative/debugger/qmldebug.cpp
@@ -0,0 +1,934 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmldebug_p.h"
+
+#include "qmldebugclient_p.h"
+
+#include <qmlenginedebug_p.h>
+
+#include <private/qobject_p.h>
+
+class QmlEngineDebugClient : public QmlDebugClient
+{
+public:
+ QmlEngineDebugClient(QmlDebugConnection *client, QmlEngineDebugPrivate *p);
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ QmlEngineDebugPrivate *priv;
+};
+
+class QmlEngineDebugPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlEngineDebug)
+public:
+ QmlEngineDebugPrivate(QmlDebugConnection *);
+
+ void message(const QByteArray &);
+
+ QmlEngineDebugClient *client;
+ int nextId;
+ int getId();
+
+ void decode(QDataStream &, QmlDebugContextReference &);
+ void decode(QDataStream &, QmlDebugObjectReference &, bool simple);
+
+ static void remove(QmlEngineDebug *, QmlDebugEnginesQuery *);
+ static void remove(QmlEngineDebug *, QmlDebugRootContextQuery *);
+ static void remove(QmlEngineDebug *, QmlDebugObjectQuery *);
+ static void remove(QmlEngineDebug *, QmlDebugExpressionQuery *);
+
+ QHash<int, QmlDebugEnginesQuery *> enginesQuery;
+ QHash<int, QmlDebugRootContextQuery *> rootContextQuery;
+ QHash<int, QmlDebugObjectQuery *> objectQuery;
+ QHash<int, QmlDebugExpressionQuery *> expressionQuery;
+
+ QHash<int, QmlDebugWatch *> watched;
+};
+
+QmlEngineDebugClient::QmlEngineDebugClient(QmlDebugConnection *client,
+ QmlEngineDebugPrivate *p)
+: QmlDebugClient(QLatin1String("QmlEngine"), client), priv(p)
+{
+ setEnabled(true);
+}
+
+void QmlEngineDebugClient::messageReceived(const QByteArray &data)
+{
+ priv->message(data);
+}
+
+QmlEngineDebugPrivate::QmlEngineDebugPrivate(QmlDebugConnection *c)
+: client(new QmlEngineDebugClient(c, this)), nextId(0)
+{
+}
+
+int QmlEngineDebugPrivate::getId()
+{
+ return nextId++;
+}
+
+void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugEnginesQuery *q)
+{
+ if (c && q) {
+ QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->enginesQuery.remove(q->m_queryId);
+ }
+}
+
+void QmlEngineDebugPrivate::remove(QmlEngineDebug *c,
+ QmlDebugRootContextQuery *q)
+{
+ if (c && q) {
+ QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->rootContextQuery.remove(q->m_queryId);
+ }
+}
+
+void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugObjectQuery *q)
+{
+ if (c && q) {
+ QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->objectQuery.remove(q->m_queryId);
+ }
+}
+
+void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugExpressionQuery *q)
+{
+ if (c && q) {
+ QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c);
+ p->expressionQuery.remove(q->m_queryId);
+ }
+}
+
+
+Q_DECLARE_METATYPE(QmlDebugObjectReference);
+void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o,
+ bool simple)
+{
+ QmlEngineDebugServer::QmlObjectData data;
+ ds >> data;
+ o.m_debugId = data.objectId;
+ o.m_class = data.objectType;
+ 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(QmlDebugObjectReference());
+ decode(ds, o.m_children.last(), !recur);
+ }
+
+ int propCount;
+ ds >> propCount;
+
+ for (int ii = 0; ii < propCount; ++ii) {
+ QmlEngineDebugServer::QmlObjectProperty data;
+ ds >> data;
+ QmlDebugPropertyReference 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 QmlEngineDebugServer::QmlObjectProperty::Basic:
+ case QmlEngineDebugServer::QmlObjectProperty::List:
+ case QmlEngineDebugServer::QmlObjectProperty::SignalProperty:
+ {
+ prop.m_value = data.value;
+ break;
+ }
+ case QmlEngineDebugServer::QmlObjectProperty::Object:
+ {
+ QmlDebugObjectReference obj;
+ obj.m_debugId = prop.m_value.toInt();
+ prop.m_value = qVariantFromValue(obj);
+ break;
+ }
+ case QmlEngineDebugServer::QmlObjectProperty::Unknown:
+ break;
+ }
+ o.m_properties << prop;
+ }
+}
+
+void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugContextReference &c)
+{
+ ds >> c.m_name >> c.m_debugId;
+
+ int contextCount;
+ ds >> contextCount;
+
+ for (int ii = 0; ii < contextCount; ++ii) {
+ c.m_contexts.append(QmlDebugContextReference());
+ decode(ds, c.m_contexts.last());
+ }
+
+ int objectCount;
+ ds >> objectCount;
+
+ for (int ii = 0; ii < objectCount; ++ii) {
+ QmlDebugObjectReference obj;
+ decode(ds, obj, true);
+
+ obj.m_contextDebugId = c.m_debugId;
+ c.m_objects << obj;
+ }
+}
+
+void QmlEngineDebugPrivate::message(const QByteArray &data)
+{
+ QDataStream ds(data);
+
+ QByteArray type;
+ ds >> type;
+
+ //qDebug() << "QmlEngineDebugPrivate::message()" << type;
+
+ if (type == "LIST_ENGINES_R") {
+ int queryId;
+ ds >> queryId;
+
+ QmlDebugEnginesQuery *query = enginesQuery.value(queryId);
+ if (!query)
+ return;
+ enginesQuery.remove(queryId);
+
+ int count;
+ ds >> count;
+
+ for (int ii = 0; ii < count; ++ii) {
+ QmlDebugEngineReference ref;
+ ds >> ref.m_name;
+ ds >> ref.m_debugId;
+ query->m_engines << ref;
+ }
+
+ query->m_client = 0;
+ query->setState(QmlDebugQuery::Completed);
+ } else if (type == "LIST_OBJECTS_R") {
+ int queryId;
+ ds >> queryId;
+
+ QmlDebugRootContextQuery *query = rootContextQuery.value(queryId);
+ if (!query)
+ return;
+ rootContextQuery.remove(queryId);
+
+ if (!ds.atEnd())
+ decode(ds, query->m_context);
+
+ query->m_client = 0;
+ query->setState(QmlDebugQuery::Completed);
+ } else if (type == "FETCH_OBJECT_R") {
+ int queryId;
+ ds >> queryId;
+
+ QmlDebugObjectQuery *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(QmlDebugQuery::Completed);
+ } else if (type == "EVAL_EXPRESSION_R") {
+ int queryId;
+ QVariant result;
+ ds >> queryId >> result;
+
+ QmlDebugExpressionQuery *query = expressionQuery.value(queryId);
+ if (!query)
+ return;
+ expressionQuery.remove(queryId);
+
+ query->m_result = result;
+ query->m_client = 0;
+ query->setState(QmlDebugQuery::Completed);
+ } else if (type == "WATCH_PROPERTY_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QmlDebugWatch::Active : QmlDebugWatch::Inactive);
+ } else if (type == "WATCH_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QmlDebugWatch::Active : QmlDebugWatch::Inactive);
+ } else if (type == "WATCH_EXPR_OBJECT_R") {
+ int queryId;
+ bool ok;
+ ds >> queryId >> ok;
+
+ QmlDebugWatch *watch = watched.value(queryId);
+ if (!watch)
+ return;
+
+ watch->setState(ok ? QmlDebugWatch::Active : QmlDebugWatch::Inactive);
+ } else if (type == "UPDATE_WATCH") {
+ int queryId;
+ int debugId;
+ QByteArray name;
+ QVariant value;
+ ds >> queryId >> debugId >> name >> value;
+
+ QmlDebugWatch *watch = watched.value(queryId, 0);
+ if (!watch)
+ return;
+ emit watch->valueChanged(name, value);
+ }
+}
+
+QmlEngineDebug::QmlEngineDebug(QmlDebugConnection *client, QObject *parent)
+: QObject(*(new QmlEngineDebugPrivate(client)), parent)
+{
+}
+
+QmlDebugPropertyWatch *QmlEngineDebug::addWatch(const QmlDebugPropertyReference &property, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugPropertyWatch *watch = new QmlDebugPropertyWatch(parent);
+ if (d->client->isConnected()) {
+ 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 = QmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QmlDebugWatch *QmlEngineDebug::addWatch(const QmlDebugContextReference &, const QString &, QObject *)
+{
+ qWarning("QmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+QmlDebugObjectExpressionWatch *QmlEngineDebug::addWatch(const QmlDebugObjectReference &object, const QString &expr, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+ QmlDebugObjectExpressionWatch *watch = new QmlDebugObjectExpressionWatch(parent);
+ if (d->client->isConnected()) {
+ 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 = QmlDebugWatch::Dead;
+ }
+ return watch;
+}
+
+QmlDebugWatch *QmlEngineDebug::addWatch(const QmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugWatch *watch = new QmlDebugWatch(parent);
+ if (d->client->isConnected()) {
+ 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 = QmlDebugWatch::Dead;
+ }
+
+ return watch;
+}
+
+QmlDebugWatch *QmlEngineDebug::addWatch(const QmlDebugFileReference &, QObject *)
+{
+ qWarning("QmlEngineDebug::addWatch(): Not implemented");
+ return 0;
+}
+
+void QmlEngineDebug::removeWatch(QmlDebugWatch *watch)
+{
+ Q_D(QmlEngineDebug);
+
+ if (!watch || !watch->m_client)
+ return;
+
+ watch->m_client = 0;
+ watch->setState(QmlDebugWatch::Inactive);
+
+ d->watched.remove(watch->queryId());
+
+ if (d->client && d->client->isConnected()) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("NO_WATCH") << watch->queryId();
+ d->client->sendMessage(message);
+ }
+}
+
+QmlDebugEnginesQuery *QmlEngineDebug::queryAvailableEngines(QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugEnginesQuery *query = new QmlDebugEnginesQuery(parent);
+ if (d->client->isConnected()) {
+ 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 = QmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QmlDebugRootContextQuery *QmlEngineDebug::queryRootContexts(const QmlDebugEngineReference &engine, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugRootContextQuery *query = new QmlDebugRootContextQuery(parent);
+ if (d->client->isConnected() && 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 = QmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QmlDebugObjectQuery *QmlEngineDebug::queryObject(const QmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugObjectQuery *query = new QmlDebugObjectQuery(parent);
+ if (d->client->isConnected() && 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;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QmlDebugObjectQuery *QmlEngineDebug::queryObjectRecursive(const QmlDebugObjectReference &object, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugObjectQuery *query = new QmlDebugObjectQuery(parent);
+ if (d->client->isConnected() && 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;
+ d->client->sendMessage(message);
+ } else {
+ query->m_state = QmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QmlDebugExpressionQuery *QmlEngineDebug::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
+{
+ Q_D(QmlEngineDebug);
+
+ QmlDebugExpressionQuery *query = new QmlDebugExpressionQuery(parent);
+ if (d->client->isConnected() && 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 = QmlDebugQuery::Error;
+ }
+
+ return query;
+}
+
+QmlDebugWatch::QmlDebugWatch(QObject *parent)
+: QObject(parent), m_state(Waiting), m_queryId(-1), m_client(0), m_objectDebugId(-1)
+{
+}
+
+QmlDebugWatch::~QmlDebugWatch()
+{
+}
+
+int QmlDebugWatch::queryId() const
+{
+ return m_queryId;
+}
+
+int QmlDebugWatch::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QmlDebugWatch::State QmlDebugWatch::state() const
+{
+ return m_state;
+}
+
+void QmlDebugWatch::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QmlDebugPropertyWatch::QmlDebugPropertyWatch(QObject *parent)
+ : QmlDebugWatch(parent)
+{
+}
+
+QString QmlDebugPropertyWatch::name() const
+{
+ return m_name;
+}
+
+
+QmlDebugObjectExpressionWatch::QmlDebugObjectExpressionWatch(QObject *parent)
+ : QmlDebugWatch(parent)
+{
+}
+
+QString QmlDebugObjectExpressionWatch::expression() const
+{
+ return m_expr;
+}
+
+
+QmlDebugQuery::QmlDebugQuery(QObject *parent)
+: QObject(parent), m_state(Waiting)
+{
+}
+
+QmlDebugQuery::State QmlDebugQuery::state() const
+{
+ return m_state;
+}
+
+bool QmlDebugQuery::isWaiting() const
+{
+ return m_state == Waiting;
+}
+
+void QmlDebugQuery::setState(State s)
+{
+ if (m_state == s)
+ return;
+ m_state = s;
+ emit stateChanged(m_state);
+}
+
+QmlDebugEnginesQuery::QmlDebugEnginesQuery(QObject *parent)
+: QmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QmlDebugEnginesQuery::~QmlDebugEnginesQuery()
+{
+ if (m_client && m_queryId != -1)
+ QmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QList<QmlDebugEngineReference> QmlDebugEnginesQuery::engines() const
+{
+ return m_engines;
+}
+
+QmlDebugRootContextQuery::QmlDebugRootContextQuery(QObject *parent)
+: QmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QmlDebugRootContextQuery::~QmlDebugRootContextQuery()
+{
+ if (m_client && m_queryId != -1)
+ QmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QmlDebugContextReference QmlDebugRootContextQuery::rootContext() const
+{
+ return m_context;
+}
+
+QmlDebugObjectQuery::QmlDebugObjectQuery(QObject *parent)
+: QmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QmlDebugObjectQuery::~QmlDebugObjectQuery()
+{
+ if (m_client && m_queryId != -1)
+ QmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QmlDebugObjectReference QmlDebugObjectQuery::object() const
+{
+ return m_object;
+}
+
+QmlDebugExpressionQuery::QmlDebugExpressionQuery(QObject *parent)
+: QmlDebugQuery(parent), m_client(0), m_queryId(-1)
+{
+}
+
+QmlDebugExpressionQuery::~QmlDebugExpressionQuery()
+{
+ if (m_client && m_queryId != -1)
+ QmlEngineDebugPrivate::remove(m_client, this);
+}
+
+QString QmlDebugExpressionQuery::expression() const
+{
+ return m_expr;
+}
+
+QVariant QmlDebugExpressionQuery::result() const
+{
+ return m_result;
+}
+
+QmlDebugEngineReference::QmlDebugEngineReference()
+: m_debugId(-1)
+{
+}
+
+QmlDebugEngineReference::QmlDebugEngineReference(int debugId)
+: m_debugId(debugId)
+{
+}
+
+QmlDebugEngineReference::QmlDebugEngineReference(const QmlDebugEngineReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name)
+{
+}
+
+QmlDebugEngineReference &
+QmlDebugEngineReference::operator=(const QmlDebugEngineReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name;
+ return *this;
+}
+
+int QmlDebugEngineReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QmlDebugEngineReference::name() const
+{
+ return m_name;
+}
+
+QmlDebugObjectReference::QmlDebugObjectReference()
+: m_debugId(-1), m_contextDebugId(-1)
+{
+}
+
+QmlDebugObjectReference::QmlDebugObjectReference(int debugId)
+: m_debugId(debugId), m_contextDebugId(-1)
+{
+}
+
+QmlDebugObjectReference::QmlDebugObjectReference(const QmlDebugObjectReference &o)
+: m_debugId(o.m_debugId), m_class(o.m_class), 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)
+{
+}
+
+QmlDebugObjectReference &
+QmlDebugObjectReference::operator=(const QmlDebugObjectReference &o)
+{
+ m_debugId = o.m_debugId; m_class = o.m_class; 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 QmlDebugObjectReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QmlDebugObjectReference::className() const
+{
+ return m_class;
+}
+
+QString QmlDebugObjectReference::name() const
+{
+ return m_name;
+}
+
+QmlDebugFileReference QmlDebugObjectReference::source() const
+{
+ return m_source;
+}
+
+int QmlDebugObjectReference::contextDebugId() const
+{
+ return m_contextDebugId;
+}
+
+QList<QmlDebugPropertyReference> QmlDebugObjectReference::properties() const
+{
+ return m_properties;
+}
+
+QList<QmlDebugObjectReference> QmlDebugObjectReference::children() const
+{
+ return m_children;
+}
+
+QmlDebugContextReference::QmlDebugContextReference()
+: m_debugId(-1)
+{
+}
+
+QmlDebugContextReference::QmlDebugContextReference(const QmlDebugContextReference &o)
+: m_debugId(o.m_debugId), m_name(o.m_name), m_objects(o.m_objects), m_contexts(o.m_contexts)
+{
+}
+
+QmlDebugContextReference &QmlDebugContextReference::operator=(const QmlDebugContextReference &o)
+{
+ m_debugId = o.m_debugId; m_name = o.m_name; m_objects = o.m_objects;
+ m_contexts = o.m_contexts;
+ return *this;
+}
+
+int QmlDebugContextReference::debugId() const
+{
+ return m_debugId;
+}
+
+QString QmlDebugContextReference::name() const
+{
+ return m_name;
+}
+
+QList<QmlDebugObjectReference> QmlDebugContextReference::objects() const
+{
+ return m_objects;
+}
+
+QList<QmlDebugContextReference> QmlDebugContextReference::contexts() const
+{
+ return m_contexts;
+}
+
+QmlDebugFileReference::QmlDebugFileReference()
+: m_lineNumber(-1), m_columnNumber(-1)
+{
+}
+
+QmlDebugFileReference::QmlDebugFileReference(const QmlDebugFileReference &o)
+: m_url(o.m_url), m_lineNumber(o.m_lineNumber), m_columnNumber(o.m_columnNumber)
+{
+}
+
+QmlDebugFileReference &QmlDebugFileReference::operator=(const QmlDebugFileReference &o)
+{
+ m_url = o.m_url; m_lineNumber = o.m_lineNumber; m_columnNumber = o.m_columnNumber;
+ return *this;
+}
+
+QUrl QmlDebugFileReference::url() const
+{
+ return m_url;
+}
+
+void QmlDebugFileReference::setUrl(const QUrl &u)
+{
+ m_url = u;
+}
+
+int QmlDebugFileReference::lineNumber() const
+{
+ return m_lineNumber;
+}
+
+void QmlDebugFileReference::setLineNumber(int l)
+{
+ m_lineNumber = l;
+}
+
+int QmlDebugFileReference::columnNumber() const
+{
+ return m_columnNumber;
+}
+
+void QmlDebugFileReference::setColumnNumber(int c)
+{
+ m_columnNumber = c;
+}
+
+QmlDebugPropertyReference::QmlDebugPropertyReference()
+: m_objectDebugId(-1), m_hasNotifySignal(false)
+{
+}
+
+QmlDebugPropertyReference::QmlDebugPropertyReference(const QmlDebugPropertyReference &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)
+{
+}
+
+QmlDebugPropertyReference &QmlDebugPropertyReference::operator=(const QmlDebugPropertyReference &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 QmlDebugPropertyReference::objectDebugId() const
+{
+ return m_objectDebugId;
+}
+
+QString QmlDebugPropertyReference::name() const
+{
+ return m_name;
+}
+
+QString QmlDebugPropertyReference::valueTypeName() const
+{
+ return m_valueTypeName;
+}
+
+QVariant QmlDebugPropertyReference::value() const
+{
+ return m_value;
+}
+
+QString QmlDebugPropertyReference::binding() const
+{
+ return m_binding;
+}
+
+bool QmlDebugPropertyReference::hasNotifySignal() const
+{
+ return m_hasNotifySignal;
+}
diff --git a/src/declarative/debugger/qmldebug_p.h b/src/declarative/debugger/qmldebug_p.h
new file mode 100644
index 0000000..cd2adf6
--- /dev/null
+++ b/src/declarative/debugger/qmldebug_p.h
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLDEBUG_H
+#define QMLDEBUG_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlDebugConnection;
+class QmlDebugWatch;
+class QmlDebugPropertyWatch;
+class QmlDebugObjectExpressionWatch;
+class QmlDebugEnginesQuery;
+class QmlDebugRootContextQuery;
+class QmlDebugObjectQuery;
+class QmlDebugExpressionQuery;
+class QmlDebugPropertyReference;
+class QmlDebugContextReference;
+class QmlDebugObjectReference;
+class QmlDebugFileReference;
+class QmlDebugEngineReference;
+class QmlEngineDebugPrivate;
+class Q_DECLARATIVE_EXPORT QmlEngineDebug : public QObject
+{
+Q_OBJECT
+public:
+ QmlEngineDebug(QmlDebugConnection *, QObject * = 0);
+
+ QmlDebugPropertyWatch *addWatch(const QmlDebugPropertyReference &,
+ QObject *parent = 0);
+ QmlDebugWatch *addWatch(const QmlDebugContextReference &, const QString &,
+ QObject *parent = 0);
+ QmlDebugObjectExpressionWatch *addWatch(const QmlDebugObjectReference &, const QString &,
+ QObject *parent = 0);
+ QmlDebugWatch *addWatch(const QmlDebugObjectReference &,
+ QObject *parent = 0);
+ QmlDebugWatch *addWatch(const QmlDebugFileReference &,
+ QObject *parent = 0);
+
+ void removeWatch(QmlDebugWatch *watch);
+
+ QmlDebugEnginesQuery *queryAvailableEngines(QObject *parent = 0);
+ QmlDebugRootContextQuery *queryRootContexts(const QmlDebugEngineReference &,
+ QObject *parent = 0);
+ QmlDebugObjectQuery *queryObject(const QmlDebugObjectReference &,
+ QObject *parent = 0);
+ QmlDebugObjectQuery *queryObjectRecursive(const QmlDebugObjectReference &,
+ QObject *parent = 0);
+ QmlDebugExpressionQuery *queryExpressionResult(int objectDebugId,
+ const QString &expr,
+ QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QmlEngineDebug)
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugWatch : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Active, Inactive, Dead };
+
+ QmlDebugWatch(QObject *);
+ ~QmlDebugWatch();
+
+ int queryId() const;
+ int objectDebugId() const;
+ State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QmlDebugWatch::State);
+ //void objectChanged(int, const QmlDebugObjectReference &);
+ //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 QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+ int m_queryId;
+ QmlEngineDebug *m_client;
+ int m_objectDebugId;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugPropertyWatch : public QmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QmlDebugPropertyWatch(QObject *parent);
+
+ QString name() const;
+
+private:
+ friend class QmlEngineDebug;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugObjectExpressionWatch : public QmlDebugWatch
+{
+ Q_OBJECT
+public:
+ QmlDebugObjectExpressionWatch(QObject *parent);
+
+ QString expression() const;
+
+private:
+ friend class QmlEngineDebug;
+ QString m_expr;
+ int m_debugId;
+};
+
+
+class Q_DECLARATIVE_EXPORT QmlDebugQuery : public QObject
+{
+Q_OBJECT
+public:
+ enum State { Waiting, Error, Completed };
+
+ State state() const;
+ bool isWaiting() const;
+
+// bool waitUntilCompleted();
+
+Q_SIGNALS:
+ void stateChanged(QmlDebugQuery::State);
+
+protected:
+ QmlDebugQuery(QObject *);
+
+private:
+ friend class QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ void setState(State);
+ State m_state;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugFileReference
+{
+public:
+ QmlDebugFileReference();
+ QmlDebugFileReference(const QmlDebugFileReference &);
+ QmlDebugFileReference &operator=(const QmlDebugFileReference &);
+
+ QUrl url() const;
+ void setUrl(const QUrl &);
+ int lineNumber() const;
+ void setLineNumber(int);
+ int columnNumber() const;
+ void setColumnNumber(int);
+
+private:
+ friend class QmlEngineDebugPrivate;
+ QUrl m_url;
+ int m_lineNumber;
+ int m_columnNumber;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugEngineReference
+{
+public:
+ QmlDebugEngineReference();
+ QmlDebugEngineReference(int);
+ QmlDebugEngineReference(const QmlDebugEngineReference &);
+ QmlDebugEngineReference &operator=(const QmlDebugEngineReference &);
+
+ int debugId() const;
+ QString name() const;
+
+private:
+ friend class QmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugObjectReference
+{
+public:
+ QmlDebugObjectReference();
+ QmlDebugObjectReference(int);
+ QmlDebugObjectReference(const QmlDebugObjectReference &);
+ QmlDebugObjectReference &operator=(const QmlDebugObjectReference &);
+
+ int debugId() const;
+ QString className() const;
+ QString name() const;
+
+ QmlDebugFileReference source() const;
+ int contextDebugId() const;
+
+ QList<QmlDebugPropertyReference> properties() const;
+ QList<QmlDebugObjectReference> children() const;
+
+private:
+ friend class QmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_class;
+ QString m_name;
+ QmlDebugFileReference m_source;
+ int m_contextDebugId;
+ QList<QmlDebugPropertyReference> m_properties;
+ QList<QmlDebugObjectReference> m_children;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugContextReference
+{
+public:
+ QmlDebugContextReference();
+ QmlDebugContextReference(const QmlDebugContextReference &);
+ QmlDebugContextReference &operator=(const QmlDebugContextReference &);
+
+ int debugId() const;
+ QString name() const;
+
+ QList<QmlDebugObjectReference> objects() const;
+ QList<QmlDebugContextReference> contexts() const;
+
+private:
+ friend class QmlEngineDebugPrivate;
+ int m_debugId;
+ QString m_name;
+ QList<QmlDebugObjectReference> m_objects;
+ QList<QmlDebugContextReference> m_contexts;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugPropertyReference
+{
+public:
+ QmlDebugPropertyReference();
+ QmlDebugPropertyReference(const QmlDebugPropertyReference &);
+ QmlDebugPropertyReference &operator=(const QmlDebugPropertyReference &);
+
+ int objectDebugId() const;
+ QString name() const;
+ QVariant value() const;
+ QString valueTypeName() const;
+ QString binding() const;
+ bool hasNotifySignal() const;
+
+private:
+ friend class QmlEngineDebugPrivate;
+ int m_objectDebugId;
+ QString m_name;
+ QVariant m_value;
+ QString m_valueTypeName;
+ QString m_binding;
+ bool m_hasNotifySignal;
+};
+
+
+class Q_DECLARATIVE_EXPORT QmlDebugEnginesQuery : public QmlDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QmlDebugEnginesQuery();
+ QList<QmlDebugEngineReference> engines() const;
+private:
+ friend class QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ QmlDebugEnginesQuery(QObject *);
+ QmlEngineDebug *m_client;
+ int m_queryId;
+ QList<QmlDebugEngineReference> m_engines;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugRootContextQuery : public QmlDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QmlDebugRootContextQuery();
+ QmlDebugContextReference rootContext() const;
+private:
+ friend class QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ QmlDebugRootContextQuery(QObject *);
+ QmlEngineDebug *m_client;
+ int m_queryId;
+ QmlDebugContextReference m_context;
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugObjectQuery : public QmlDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QmlDebugObjectQuery();
+ QmlDebugObjectReference object() const;
+private:
+ friend class QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ QmlDebugObjectQuery(QObject *);
+ QmlEngineDebug *m_client;
+ int m_queryId;
+ QmlDebugObjectReference m_object;
+
+};
+
+class Q_DECLARATIVE_EXPORT QmlDebugExpressionQuery : public QmlDebugQuery
+{
+Q_OBJECT
+public:
+ virtual ~QmlDebugExpressionQuery();
+ QString expression() const;
+ QVariant result() const;
+private:
+ friend class QmlEngineDebug;
+ friend class QmlEngineDebugPrivate;
+ QmlDebugExpressionQuery(QObject *);
+ QmlEngineDebug *m_client;
+ int m_queryId;
+ QString m_expr;
+ QVariant m_result;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLDEBUG_H
diff --git a/src/declarative/debugger/qmldebugclient.cpp b/src/declarative/debugger/qmldebugclient.cpp
new file mode 100644
index 0000000..68e14c2
--- /dev/null
+++ b/src/declarative/debugger/qmldebugclient.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmldebugclient_p.h"
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugConnectionPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QmlDebugConnectionPrivate(QmlDebugConnection *c);
+ QmlDebugConnection *q;
+ QPacketProtocol *protocol;
+
+ QStringList enabled;
+ QHash<QString, QmlDebugClient *> plugins;
+public Q_SLOTS:
+ void connected();
+ void readyRead();
+};
+
+QmlDebugConnectionPrivate::QmlDebugConnectionPrivate(QmlDebugConnection *c)
+: QObject(c), q(c), protocol(0)
+{
+ protocol = new QPacketProtocol(q, this);
+ QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
+ QObject::connect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+void QmlDebugConnectionPrivate::connected()
+{
+ QPacket pack;
+ pack << QString(QLatin1String("QmlDebugServer")) << enabled;
+ protocol->send(pack);
+}
+
+void QmlDebugConnectionPrivate::readyRead()
+{
+ QPacket pack = protocol->read();
+ QString name; QByteArray message;
+ pack >> name >> message;
+
+ QHash<QString, QmlDebugClient *>::Iterator iter =
+ plugins.find(name);
+ if (iter == plugins.end()) {
+ qWarning() << "QmlDebugConnection: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+}
+
+QmlDebugConnection::QmlDebugConnection(QObject *parent)
+: QTcpSocket(parent), d(new QmlDebugConnectionPrivate(this))
+{
+}
+
+bool QmlDebugConnection::isConnected() const
+{
+ return state() == ConnectedState;
+}
+
+class QmlDebugClientPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlDebugClient)
+public:
+ QmlDebugClientPrivate();
+
+ QString name;
+ QmlDebugConnection *client;
+ bool enabled;
+};
+
+QmlDebugClientPrivate::QmlDebugClientPrivate()
+: client(0), enabled(false)
+{
+}
+
+QmlDebugClient::QmlDebugClient(const QString &name,
+ QmlDebugConnection *parent)
+: QObject(*(new QmlDebugClientPrivate), parent)
+{
+ Q_D(QmlDebugClient);
+ d->name = name;
+ d->client = parent;
+
+ if (!d->client)
+ return;
+
+ if (d->client->d->plugins.contains(name)) {
+ qWarning() << "QmlDebugClient: Conflicting plugin name" << name;
+ d->client = 0;
+ } else {
+ d->client->d->plugins.insert(name, this);
+ }
+}
+
+QString QmlDebugClient::name() const
+{
+ Q_D(const QmlDebugClient);
+ return d->name;
+}
+
+bool QmlDebugClient::isEnabled() const
+{
+ Q_D(const QmlDebugClient);
+ return d->enabled;
+}
+
+void QmlDebugClient::setEnabled(bool e)
+{
+ Q_D(QmlDebugClient);
+ if (e == d->enabled)
+ return;
+
+ d->enabled = e;
+
+ if (d->client) {
+ if (e)
+ d->client->d->enabled.append(d->name);
+ else
+ d->client->d->enabled.removeAll(d->name);
+
+ if (d->client->state() == QTcpSocket::ConnectedState) {
+ QPacket pack;
+ pack << QString(QLatin1String("QmlDebugServer"));
+ if (e) pack << (int)1;
+ else pack << (int)2;
+ pack << d->name;
+ d->client->d->protocol->send(pack);
+ }
+ }
+}
+
+bool QmlDebugClient::isConnected() const
+{
+ Q_D(const QmlDebugClient);
+
+ if (!d->client)
+ return false;
+ return d->client->isConnected();
+}
+
+void QmlDebugClient::sendMessage(const QByteArray &message)
+{
+ Q_D(QmlDebugClient);
+
+ if (!d->client || !d->client->isConnected())
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->client->d->protocol->send(pack);
+}
+
+void QmlDebugClient::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qmldebugclient.moc>
diff --git a/src/declarative/debugger/qmldebugclient_p.h b/src/declarative/debugger/qmldebugclient_p.h
new file mode 100644
index 0000000..d64541b
--- /dev/null
+++ b/src/declarative/debugger/qmldebugclient_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLDEBUGCLIENT_H
+#define QMLDEBUGCLIENT_H
+
+#include <QtNetwork/qtcpsocket.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlDebugConnectionPrivate;
+class Q_DECLARATIVE_EXPORT QmlDebugConnection : public QTcpSocket
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QmlDebugConnection)
+public:
+ QmlDebugConnection(QObject * = 0);
+
+ bool isConnected() const;
+private:
+ QmlDebugConnectionPrivate *d;
+ friend class QmlDebugClient;
+ friend class QmlDebugClientPrivate;
+};
+
+class QmlDebugClientPrivate;
+class Q_DECLARATIVE_EXPORT QmlDebugClient : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlDebugClient)
+ Q_DISABLE_COPY(QmlDebugClient)
+
+public:
+ QmlDebugClient(const QString &, QmlDebugConnection *parent);
+
+ QString name() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool isConnected() const;
+
+ void sendMessage(const QByteArray &);
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QmlDebugConnection;
+ friend class QmlDebugConnectionPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLDEBUGCLIENT_H
diff --git a/src/declarative/debugger/qmldebuggerstatus.cpp b/src/declarative/debugger/qmldebuggerstatus.cpp
new file mode 100644
index 0000000..dc1cfb0
--- /dev/null
+++ b/src/declarative/debugger/qmldebuggerstatus.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmldebuggerstatus_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QmlDebuggerStatus::~QmlDebuggerStatus()
+{
+}
+
+void QmlDebuggerStatus::setSelectedState(bool)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/debugger/qmldebuggerstatus_p.h b/src/declarative/debugger/qmldebuggerstatus_p.h
new file mode 100644
index 0000000..7c8070b
--- /dev/null
+++ b/src/declarative/debugger/qmldebuggerstatus_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLDEBUGGERSTATUS_P_H
+#define QMLDEBUGGERSTATUS_P_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QmlDebuggerStatus
+{
+public:
+ virtual ~QmlDebuggerStatus();
+
+ virtual void setSelectedState(bool);
+};
+Q_DECLARE_INTERFACE(QmlDebuggerStatus, "com.trolltech.qml.QmlDebuggerStatus")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QLMDEBUGGERSTATUS_P_H
diff --git a/src/declarative/debugger/qmldebugservice.cpp b/src/declarative/debugger/qmldebugservice.cpp
new file mode 100644
index 0000000..810fbed
--- /dev/null
+++ b/src/declarative/debugger/qmldebugservice.cpp
@@ -0,0 +1,393 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmldebugservice_p.h"
+
+#include "qpacketprotocol_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugServerPrivate;
+class QmlDebugServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlDebugServer)
+ Q_DISABLE_COPY(QmlDebugServer)
+public:
+ static QmlDebugServer *instance();
+ void wait();
+
+private Q_SLOTS:
+ void readyRead();
+
+private:
+ friend class QmlDebugService;
+ friend class QmlDebugServicePrivate;
+ QmlDebugServer(int);
+};
+
+class QmlDebugServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlDebugServer)
+public:
+ QmlDebugServerPrivate();
+ void wait();
+
+ int port;
+ QTcpSocket *connection;
+ QPacketProtocol *protocol;
+ QHash<QString, QmlDebugService *> plugins;
+ QStringList enabledPlugins;
+};
+
+class QmlDebugServicePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlDebugService)
+public:
+ QmlDebugServicePrivate();
+
+ QString name;
+ QmlDebugServer *server;
+};
+
+QmlDebugServerPrivate::QmlDebugServerPrivate()
+: connection(0), protocol(0)
+{
+}
+
+void QmlDebugServerPrivate::wait()
+{
+ Q_Q(QmlDebugServer);
+ QTcpServer server;
+
+ if (!server.listen(QHostAddress::Any, port)) {
+ qWarning("QmlDebugServer: Unable to listen on port %d", port);
+ return;
+ }
+
+ qWarning("QmlDebugServer: Waiting for connection on port %d...", port);
+
+ if (!server.waitForNewConnection(-1)) {
+ qWarning("QmlDebugServer: Connection error");
+ return;
+ }
+
+ connection = server.nextPendingConnection();
+ connection->setParent(q);
+ protocol = new QPacketProtocol(connection, q);
+
+ // ### Wait for hello
+ while (!protocol->packetsAvailable()) {
+ connection->waitForReadyRead();
+ }
+ QPacket hello = protocol->read();
+ QString name;
+ hello >> name >> enabledPlugins;
+ if (name != QLatin1String("QmlDebugServer")) {
+ qWarning("QmlDebugServer: Invalid hello message");
+ delete protocol; delete connection; connection = 0; protocol = 0;
+ return;
+ }
+
+ QObject::connect(protocol, SIGNAL(readyRead()), q, SLOT(readyRead()));
+ q->readyRead();
+
+ qWarning("QmlDebugServer: Connection established");
+}
+
+QmlDebugServer *QmlDebugServer::instance()
+{
+ static bool envTested = false;
+ static QmlDebugServer *server = 0;
+
+ if (!envTested) {
+ envTested = true;
+ QByteArray env = qgetenv("QML_DEBUG_SERVER_PORT");
+
+ bool ok = false;
+ int port = env.toInt(&ok);
+
+ if (ok && port > 1024)
+ server = new QmlDebugServer(port);
+ }
+
+ return server;
+}
+
+void QmlDebugServer::wait()
+{
+ Q_D(QmlDebugServer);
+ d->wait();
+}
+
+QmlDebugServer::QmlDebugServer(int port)
+: QObject(*(new QmlDebugServerPrivate))
+{
+ Q_D(QmlDebugServer);
+ d->port = port;
+}
+
+void QmlDebugServer::readyRead()
+{
+ Q_D(QmlDebugServer);
+
+ QString debugServer(QLatin1String("QmlDebugServer"));
+
+ while (d->protocol->packetsAvailable()) {
+ QPacket pack = d->protocol->read();
+
+ QString name;
+ pack >> name;
+
+ if (name == debugServer) {
+ int op = -1; QString plugin;
+ pack >> op >> plugin;
+
+ if (op == 1) {
+ // Enable
+ if (!d->enabledPlugins.contains(plugin)) {
+ d->enabledPlugins.append(plugin);
+ QHash<QString, QmlDebugService *>::Iterator iter =
+ d->plugins.find(plugin);
+ if (iter != d->plugins.end())
+ (*iter)->enabledChanged(true);
+ }
+
+ } else if (op == 2) {
+ // Disable
+ if (d->enabledPlugins.contains(plugin)) {
+ d->enabledPlugins.removeAll(plugin);
+ QHash<QString, QmlDebugService *>::Iterator iter =
+ d->plugins.find(plugin);
+ if (iter != d->plugins.end())
+ (*iter)->enabledChanged(false);
+ }
+ } else {
+ qWarning("QmlDebugServer: Invalid control message %d", op);
+ }
+
+ } else {
+ QByteArray message;
+ pack >> message;
+
+ QHash<QString, QmlDebugService *>::Iterator iter =
+ d->plugins.find(name);
+ if (iter == d->plugins.end()) {
+ qWarning() << "QmlDebugServer: Message received for missing plugin" << name;
+ } else {
+ (*iter)->messageReceived(message);
+ }
+ }
+ }
+}
+
+QmlDebugServicePrivate::QmlDebugServicePrivate()
+: server(0)
+{
+}
+
+QmlDebugService::QmlDebugService(const QString &name, QObject *parent)
+: QObject(*(new QmlDebugServicePrivate), parent)
+{
+ Q_D(QmlDebugService);
+ d->name = name;
+ d->server = QmlDebugServer::instance();
+
+ if (!d->server)
+ return;
+
+ if (d->server->d_func()->plugins.contains(name)) {
+ qWarning() << "QmlDebugService: Conflicting plugin name" << name;
+ d->server = 0;
+ } else {
+ d->server->d_func()->plugins.insert(name, this);
+ }
+}
+
+QString QmlDebugService::name() const
+{
+ Q_D(const QmlDebugService);
+ return d->name;
+}
+
+bool QmlDebugService::isEnabled() const
+{
+ Q_D(const QmlDebugService);
+ return (d->server && d->server->d_func()->enabledPlugins.contains(d->name));
+}
+
+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 QmlDebugService::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 *QmlDebugService::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 QmlDebugService::isDebuggingEnabled()
+{
+ return QmlDebugServer::instance() != 0;
+}
+
+QString QmlDebugService::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 QmlDebugService::waitForClients()
+{
+ QmlDebugServer::instance()->wait();
+}
+
+void QmlDebugService::sendMessage(const QByteArray &message)
+{
+ Q_D(QmlDebugService);
+
+ if (!d->server || !d->server->d_func()->connection)
+ return;
+
+ QPacket pack;
+ pack << d->name << message;
+ d->server->d_func()->protocol->send(pack);
+ d->server->d_func()->connection->flush();
+}
+
+void QmlDebugService::enabledChanged(bool)
+{
+}
+
+void QmlDebugService::messageReceived(const QByteArray &)
+{
+}
+
+QT_END_NAMESPACE
+
+#include <qmldebugservice.moc>
diff --git a/src/declarative/debugger/qmldebugservice_p.h b/src/declarative/debugger/qmldebugservice_p.h
new file mode 100644
index 0000000..b406a3c
--- /dev/null
+++ b/src/declarative/debugger/qmldebugservice_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLDEBUGSERVICE_H
+#define QMLDEBUGSERVICE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlDebugServicePrivate;
+class Q_DECLARATIVE_EXPORT QmlDebugService : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlDebugService)
+ Q_DISABLE_COPY(QmlDebugService)
+public:
+ QmlDebugService(const QString &, QObject *parent = 0);
+
+ QString name() const;
+
+ bool isEnabled() const;
+
+ void sendMessage(const QByteArray &);
+
+ static int idForObject(QObject *);
+ static QObject *objectForId(int);
+
+
+ static bool isDebuggingEnabled();
+ static QString objectToString(QObject *obj);
+
+ static void waitForClients();
+
+protected:
+ virtual void enabledChanged(bool);
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ friend class QmlDebugServer;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLDEBUGSERVICE_H
+
diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp
new file mode 100644
index 0000000..b76c461
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol.cpp
@@ -0,0 +1,498 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpacketprotocol_p.h"
+
+#include <QBuffer>
+
+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),
+ 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()
+ {
+ if(-1 == inProgressSize) {
+ // We need a size header of sizeof(qint32)
+ if(sizeof(qint32) > dev->bytesAvailable())
+ return;
+
+ // 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);
+
+ // Need to get trailing data
+ readyToRead();
+ } else {
+ inProgress.append(dev->read(inProgressSize - inProgress.size()));
+
+ if(inProgressSize == inProgress.size()) {
+ // Packet has arrived!
+ packets.append(inProgress);
+ inProgressSize = -1;
+ inProgress.clear();
+
+ emit readyRead();
+
+ // Need to get trailing data
+ readyToRead();
+ }
+ }
+ }
+
+public:
+ QList<qint64> sendingPackets;
+ QList<QByteArray> packets;
+ QByteArray inProgress;
+ qint32 inProgressSize;
+ qint32 maxPacketSize;
+ 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;
+}
+
+/*!
+ 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);
+}
+
+/*!
+ 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 independant.
+ */
+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();
+}
+
+/*!
+ 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 0000000..265af81
--- /dev/null
+++ b/src/declarative/debugger/qpacketprotocol_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPACKETPROTOCOL_H
+#define QPACKETPROTOCOL_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qdatastream.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();
+
+ 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;
+
+protected:
+ friend class QPacketProtocol;
+ QPacket(const QByteArray & ba);
+ QByteArray b;
+ QBuffer * buf;
+};
+
+class Q_DECLARATIVE_EXPORT QPacketAutoSend : public QPacket
+{
+public:
+ virtual ~QPacketAutoSend();
+
+private:
+ friend class QPacketProtocol;
+ QPacketAutoSend(QPacketProtocol *);
+ QPacketProtocol * p;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif