diff options
22 files changed, 1816 insertions, 454 deletions
diff --git a/src/declarative/canvas/canvas.pri b/src/declarative/canvas/canvas.pri index 8abfd99..9bdd3fa 100644 --- a/src/declarative/canvas/canvas.pri +++ b/src/declarative/canvas/canvas.pri @@ -2,7 +2,7 @@ SOURCES += \ canvas/qsimplecanvas.cpp \ canvas/qsimplecanvasitem.cpp \ canvas/qsimplecanvasfilter.cpp \ - canvas/qsimplecanvasserver.cpp + canvas/qsimplecanvasdebugplugin.cpp HEADERS += \ canvas/qsimplecanvas.h \ @@ -11,7 +11,7 @@ HEADERS += \ canvas/qsimplecanvas_p.h \ canvas/qsimplecanvasitem_p.h \ canvas/qsimplecanvasfilter_p.h \ - canvas/qsimplecanvasserver_p.h + canvas/qsimplecanvasdebugplugin_p.h contains(QT_CONFIG, opengles2): SOURCES += canvas/qsimplecanvas_opengl.cpp else:contains(QT_CONFIG, opengles1): SOURCES += canvas/qsimplecanvas_opengl1.cpp diff --git a/src/declarative/canvas/monitor/monitor.pro b/src/declarative/canvas/monitor/monitor.pro deleted file mode 100644 index e3b0a29..0000000 --- a/src/declarative/canvas/monitor/monitor.pro +++ /dev/null @@ -1,8 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -QT += network - -# Input -SOURCES += main.cpp diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp index fbd5014..e582226 100644 --- a/src/declarative/canvas/qsimplecanvas.cpp +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -53,7 +53,7 @@ #include <glheaders.h> #endif #include "qboxlayout.h" -#include "qsimplecanvasserver_p.h" +#include "qsimplecanvasdebugplugin_p.h" #include "qsimplecanvas.h" @@ -533,8 +533,8 @@ void QSimpleCanvasGraphicsView::paintEvent(QPaintEvent *pe) int frametimer = canvas->frameTimer.elapsed(); gfxCanvasTiming.append(QSimpleCanvasTiming(r, frametimer, canvas->lrpTime, tbf)); canvas->lrpTime = 0; - if (canvas->canvasServer) - canvas->canvasServer->addTiming(canvas->lrpTime, frametimer, tbf); + if (canvas->debugPlugin) + canvas->debugPlugin->addTiming(canvas->lrpTime, frametimer, tbf); } void QSimpleCanvasGraphicsView::focusInEvent(QFocusEvent *) @@ -573,11 +573,9 @@ void QSimpleCanvasPrivate::init(QSimpleCanvas::CanvasMode mode) if (continuousUpdate()) qWarning("QSimpleCanvas: Continuous update enabled"); - QByteArray env = qgetenv("GFX_CANVAS_SERVER_PORT"); - if (!env.isEmpty()){ - int port = env.toInt(); - if (port >= 1024) - canvasServer = new QSimpleCanvasServer(port, q); + if (QmlDebugServerPlugin::isDebuggingEnabled()) { + debugPlugin = new QSimpleCanvasDebugPlugin(q); + new QSimpleCanvasSceneDebugPlugin(q); } root = new QSimpleCanvasRootLayer(q); @@ -950,8 +948,8 @@ bool QSimpleCanvas::event(QEvent *e) int frametimer = d->frameTimer.elapsed(); gfxCanvasTiming.append(QSimpleCanvasTiming(r, frametimer, d->lrpTime, tbf)); - if (d->canvasServer) - d->canvasServer->addTiming(d->lrpTime, frametimer, tbf); + if (d->debugPlugin) + d->debugPlugin->addTiming(d->lrpTime, frametimer, tbf); d->lrpTime = 0; if (continuousUpdate()) queueUpdate(); diff --git a/src/declarative/canvas/qsimplecanvas_p.h b/src/declarative/canvas/qsimplecanvas_p.h index 9c3408e..d9ed4ac 100644 --- a/src/declarative/canvas/qsimplecanvas_p.h +++ b/src/declarative/canvas/qsimplecanvas_p.h @@ -101,12 +101,12 @@ private: }; class QGLFramebufferObject; -class QSimpleCanvasServer; +class QSimpleCanvasDebugPlugin; class QSimpleCanvasPrivate { public: QSimpleCanvasPrivate(QSimpleCanvas *canvas) - : q(canvas), timer(0), root(0), lrpTime(0), canvasServer(0), focusItem(0), + : q(canvas), timer(0), root(0), lrpTime(0), debugPlugin(0), focusItem(0), lastFocusItem(0), lastMouseItem(0), isSetup(false), view(0) #if defined(QFX_RENDER_OPENGL) @@ -139,7 +139,7 @@ public: QTime frameTimer; QTime lrpTimer; - QSimpleCanvasServer *canvasServer; + QSimpleCanvasDebugPlugin *debugPlugin; QStack<QSimpleCanvasItem *> focusPanels; QHash<QSimpleCanvasItem *, QSimpleCanvasItem *> focusPanelData; diff --git a/src/declarative/canvas/qsimplecanvasserver.cpp b/src/declarative/canvas/qsimplecanvasdebugplugin.cpp index ed781b8..f5f4f53 100644 --- a/src/declarative/canvas/qsimplecanvasserver.cpp +++ b/src/declarative/canvas/qsimplecanvasdebugplugin.cpp @@ -39,19 +39,18 @@ ** ****************************************************************************/ -#include "qsimplecanvasserver_p.h" +#include "qsimplecanvasdebugplugin_p.h" #include "qdebug.h" -#ifndef Q_OS_WIN32 -#include <arpa/inet.h> -#endif #include <QtCore/qabstractanimation.h> +#include <qsimplecanvas.h> +#include <qsimplecanvasitem.h> QT_BEGIN_NAMESPACE class FrameBreakAnimation : public QAbstractAnimation { public: - FrameBreakAnimation(QSimpleCanvasServer *s) + FrameBreakAnimation(QSimpleCanvasDebugPlugin *s) : QAbstractAnimation(s), server(s) { start(); @@ -63,72 +62,88 @@ public: } private: - QSimpleCanvasServer *server; + QSimpleCanvasDebugPlugin *server; }; -QSimpleCanvasServer::QSimpleCanvasServer(int port, QObject *parent) -: QObject(parent), _breaks(0), _tcpServer(new QTcpServer(this)) +QSimpleCanvasDebugPlugin::QSimpleCanvasDebugPlugin(QObject *parent) +: QmlDebugServerPlugin("CanvasFrameRate", parent), _breaks(0) { - QObject::connect(_tcpServer, SIGNAL(newConnection()), - this, SLOT(newConnection())); - _time.start(); - new FrameBreakAnimation(this); - if (!_tcpServer->listen(QHostAddress::Any, port)) { - qWarning() << "QSimpleCanvasServer: Cannot listen on port" << port; - return; - } -} - -void QSimpleCanvasServer::newConnection() -{ - QTcpSocket *socket = _tcpServer->nextPendingConnection(); - QObject::connect(socket, SIGNAL(disconnected()), - this, SLOT(disconnected())); - _tcpClients << socket; } -void QSimpleCanvasServer::addTiming(quint32 paint, - quint32 repaint, - quint32 timeBetweenFrames) +void QSimpleCanvasDebugPlugin::addTiming(quint32 paint, + quint32 repaint, + quint32 timeBetweenFrames) { - /* - quint32 data[3]; - data[0] = ::htonl(paint); - data[1] = ::htonl(repaint); - data[2] = ::htonl(timeBetweenFrames); - */ + if (!isEnabled()) + return; bool isFrameBreak = _breaks > 1; _breaks = 0; int e = _time.elapsed(); - QString d = QString::number(paint) + QLatin1String(" ") + QString::number(repaint) + QLatin1String(" ") + QString::number(timeBetweenFrames) + QLatin1String(" ") + QString::number(e) + QLatin1String(" ") + QString::number(isFrameBreak) + QLatin1String("\n"); - QByteArray ba = d.toLatin1(); - - // XXX - for (int ii = 0; ii < _tcpClients.count(); ++ii) -// _tcpClients.at(ii)->write((const char *)data, 12); - _tcpClients.at(ii)->write(ba.constData(), ba.length()); + QByteArray data; + QDataStream ds(&data, QIODevice::WriteOnly); + ds << (int)paint << (int)repaint << (int)timeBetweenFrames << (int)e + << (bool)isFrameBreak; + sendMessage(data); } -void QSimpleCanvasServer::frameBreak() +void QSimpleCanvasDebugPlugin::frameBreak() { _breaks++; } -void QSimpleCanvasServer::disconnected() +QSimpleCanvasSceneDebugPlugin::QSimpleCanvasSceneDebugPlugin(QSimpleCanvas *parent) +: QmlDebugServerPlugin("CanvasScene", parent), m_canvas(parent) +{ +} + +void QSimpleCanvasSceneDebugPlugin::messageReceived(const QByteArray &) +{ + refresh(); +} + +void QSimpleCanvasSceneDebugPlugin::refresh() { - QTcpSocket *socket = static_cast<QTcpSocket *>(sender()); - - for (int ii = 0; ii < _tcpClients.count(); ++ii) { - if (_tcpClients.at(ii) == socket) { - socket->disconnect(); - socket->deleteLater(); - _tcpClients.removeAt(ii); - return; - } + QByteArray data; + QDataStream ds(&data, QIODevice::WriteOnly); + const QList<QSimpleCanvasItem *> &children = m_canvas->root()->children(); + ds << children.count(); + for (int ii = 0; ii < children.count(); ++ii) + refresh(ds, children.at(ii)); + + sendMessage(data); +} + +void QSimpleCanvasSceneDebugPlugin::refresh(QDataStream &ds, + QSimpleCanvasItem *item) +{ + ds << QmlDebugServerPlugin::objectToString(item) << item->x() << item->y() + << item->z() << item->width() << item->height() + << (int)item->transformOrigin() << item->scale() << (int)item->flip() + << item->transform() << item->hasActiveFocus() << (int)item->options(); + + QPixmap pix; + + if(item->options() & QSimpleCanvasItem::HasContents && + item->width() > 0 && item->height() > 0) { + + pix = QPixmap(item->width(), item->height()); + pix.fill(QColor(0,0,0,0)); + QPainter p(&pix); + item->paintContents(p); + } + + ds << pix; + + const QList<QSimpleCanvasItem *> &children = item->children(); + ds << children.count(); + + for(int ii = 0; ii < children.count(); ++ii) + refresh(ds, children.at(ii)); } QT_END_NAMESPACE + diff --git a/src/declarative/canvas/qsimplecanvasserver_p.h b/src/declarative/canvas/qsimplecanvasdebugplugin_p.h index ce04e8d..270b78c 100644 --- a/src/declarative/canvas/qsimplecanvasserver_p.h +++ b/src/declarative/canvas/qsimplecanvasdebugplugin_p.h @@ -39,37 +39,47 @@ ** ****************************************************************************/ -#ifndef QSIMPLECANVASSERVER_P_H -#define QSIMPLECANVASSERVER_P_H +#ifndef QSIMPLECANVASDEBUGPLUGIN_P_H +#define QSIMPLECANVASDEBUGPLUGIN_P_H #include "qobject.h" #include "qtcpserver.h" #include "qtcpsocket.h" #include "qdatetime.h" - +#include <QtDeclarative/qmldebugserver.h> QT_BEGIN_NAMESPACE -class QSimpleCanvasServer : public QObject +class QSimpleCanvasDebugPlugin : public QmlDebugServerPlugin { -Q_OBJECT public: - QSimpleCanvasServer(int port, QObject *parent); + QSimpleCanvasDebugPlugin(QObject *parent = 0); void addTiming(quint32, quint32, quint32); -private Q_SLOTS: - void newConnection(); - void disconnected(); - private: friend class FrameBreakAnimation; void frameBreak(); int _breaks; - - QTcpServer *_tcpServer; - QList<QTcpSocket *> _tcpClients; QTime _time; }; +class QSimpleCanvas; +class QSimpleCanvasItem; +class QSimpleCanvasSceneDebugPlugin : public QmlDebugServerPlugin +{ +public: + QSimpleCanvasSceneDebugPlugin(QSimpleCanvas *parent = 0); + + virtual void messageReceived(const QByteArray &); + +private: + void refresh(); + void refresh(QDataStream &, QSimpleCanvasItem *); + QSimpleCanvas *m_canvas; +}; + + QT_END_NAMESPACE -#endif // GFXCANVASSERVER_P_H + +#endif // QSIMPLECANVASDEBUGPLUGIN_P_H + diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index c386d74..aa36675 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -3,11 +3,15 @@ SOURCES += debugger/qmldebugger.cpp \ debugger/qmlpropertyview.cpp \ debugger/qmlwatches.cpp \ debugger/qmlobjecttree.cpp \ - debugger/qmlcanvasdebugger.cpp + debugger/qpacketprotocol.cpp \ + debugger/qmldebugserver.cpp \ + debugger/qmldebugclient.cpp HEADERS += debugger/qmldebugger.h \ debugger/qmldebuggerstatus.h \ debugger/qmlpropertyview_p.h \ debugger/qmlwatches_p.h \ debugger/qmlobjecttree_p.h \ - debugger/qmlcanvasdebugger_p.h + debugger/qpacketprotocol.h \ + debugger/qmldebugserver.h \ + debugger/qmldebugclient.h diff --git a/src/declarative/debugger/qmlcanvasdebugger.cpp b/src/declarative/debugger/qmlcanvasdebugger.cpp deleted file mode 100644 index 21abd2d..0000000 --- a/src/declarative/debugger/qmlcanvasdebugger.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <private/qmlcanvasdebugger_p.h> -#include <private/qmlwatches_p.h> -#include <QtDeclarative/qsimplecanvas.h> -#include <QtGui/qboxlayout.h> -#include <QtGui/qpushbutton.h> -#include <QtGui/qspinbox.h> -#include <QtGui/qsplitter.h> -#include <QtGui/qtreewidget.h> - -#include <QtDeclarative/qfxrect.h> -#include <QtDeclarative/qfximage.h> - -QmlCanvasDebugger::QmlCanvasDebugger(QmlWatches *w, QWidget *parent) -: QWidget(parent), m_watches(w), m_tree(0), m_canvas(0), m_canvasRoot(0), m_debugCanvas(0), - m_selected(0) -{ - QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins(0,0,0,0); - layout->setSpacing(0); - setLayout(layout); - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->setContentsMargins(0,0,0,0); - hlayout->addStretch(2); - hlayout->setSpacing(0); - layout->addLayout(hlayout); - QSpinBox *x = new QSpinBox(this); - x->setSingleStep(50); - x->setMaximum(10000); - x->setMinimum(-10000); - QObject::connect(x, SIGNAL(valueChanged(int)), this, SLOT(setX(int))); - QSpinBox *y = new QSpinBox(this); - y->setSingleStep(50); - y->setMaximum(10000); - y->setMinimum(-10000); - QObject::connect(y, SIGNAL(valueChanged(int)), this, SLOT(setY(int))); - hlayout->addWidget(x); - hlayout->addWidget(y); - QPushButton *pb = new QPushButton(tr("Refresh"), this); - QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh())); - hlayout->addWidget(pb); - - QSplitter *splitter = new QSplitter(this); - - m_tree = new QTreeWidget(this); - QObject::connect(m_tree, SIGNAL(itemExpanded(QTreeWidgetItem*)), - this, SLOT(itemExpanded(QTreeWidgetItem*))); - QObject::connect(m_tree, SIGNAL(itemCollapsed(QTreeWidgetItem*)), - this, SLOT(itemCollapsed(QTreeWidgetItem*))); - QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), - this, SLOT(itemClicked(QTreeWidgetItem*))); - m_canvas = new QSimpleCanvas(QSimpleCanvas::SimpleCanvas, this); - m_canvasRoot = new QSimpleCanvasItem; - m_canvasRoot->setParent(m_canvas->root()); - splitter->addWidget(m_tree); - splitter->addWidget(m_canvas); - splitter->setStretchFactor(1, 2); - layout->addWidget(splitter); -} - -void QmlCanvasDebugger::refresh() -{ - setCanvas(m_debugCanvas); -} - -class QmlCanvasDebuggerItem : public QTreeWidgetItem -{ -public: - QmlCanvasDebuggerItem(QTreeWidget *tree) - : QTreeWidgetItem(tree), me(0), img(0) - { - } - - QmlCanvasDebuggerItem(QTreeWidgetItem *item) - : QTreeWidgetItem(item), me(0), img(0) - { - } - - QPointer<QObject> them; - QFxRect *me; - QFxImage *img; -}; - -void QmlCanvasDebugger::itemExpanded(QTreeWidgetItem *i) -{ - QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); - if(item->me) - item->me->setOpacity(1); -} - -void QmlCanvasDebugger::setOpacityRecur(QTreeWidgetItem *i, qreal op) -{ - QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); - if(item->img) - item->img->setOpacity(op); - - for(int ii = 0; ii < item->childCount(); ++ii) - setOpacityRecur(item->child(ii), op); -} - -void QmlCanvasDebugger::itemClicked(QTreeWidgetItem *i) -{ - QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); - if(item->them) - emit objectClicked(m_watches->objectId(item->them)); - - if(m_selected) { - setOpacityRecur(m_selected, 0); - m_selected = 0; - } - - m_selected = item; - setOpacityRecur(m_selected, 1); -} - -void QmlCanvasDebugger::itemCollapsed(QTreeWidgetItem *i) -{ - QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); - if(item->me) - item->me->setOpacity(0); -} - -void QmlCanvasDebugger::clone(QTreeWidgetItem *item, QSimpleCanvasItem *me, QSimpleCanvasItem *them) -{ - const QList<QSimpleCanvasItem *> &children = them->children(); - - foreach(QSimpleCanvasItem *child, children) { - QmlCanvasDebuggerItem *childItem = new QmlCanvasDebuggerItem(item); - childItem->setText(0, QmlWatches::objectToString(child)); - childItem->setExpanded(true); - - QFxRect *rect = new QFxRect; - rect->setParent(me); - rect->setX(child->x()); - rect->setY(child->y()); - rect->setZ(child->z()); - rect->setWidth(child->width()); - rect->setHeight(child->height()); - rect->setTransformOrigin(child->transformOrigin()); - rect->setScale(child->scale()); - rect->setFlip(child->flip()); - rect->setTransform(child->transform()); - - if(child->hasActiveFocus()) - rect->setColor(QColor(0, 0, 0, 10)); - else if(child->options() & QSimpleCanvasItem::IsFocusPanel) - rect->setColor(QColor(0, 255, 0, 10)); - else if(child->options() & QSimpleCanvasItem::IsFocusRealm) - rect->setColor(QColor(0, 0, 255, 10)); - else - rect->setColor(QColor(255, 0, 0, 10)); - - if(child->width() > 0 && child->height() > 0) { - QPixmap pix(child->width(), child->height()); - pix.fill(QColor(0,0,0,0)); - QPainter p(&pix); - child->paintContents(p); - QFxImage *img = new QFxImage; - img->setParent(rect); - img->setWidth(child->width()); - img->setHeight(child->height()); - img->setPixmap(pix); - img->setOpacity(0); - childItem->img = img; - } - - childItem->them = child; - childItem->me = rect; - - clone(childItem, rect, child); - } -} - -void QmlCanvasDebugger::setX(int x) -{ - m_canvasRoot->setX(x); -} - -void QmlCanvasDebugger::setY(int y) -{ - m_canvasRoot->setY(y); -} - -void QmlCanvasDebugger::setCanvas(QSimpleCanvas *canvas) -{ - QList<QSimpleCanvasItem *> children = m_canvasRoot->children(); - qDeleteAll(children); - m_tree->clear(); - m_selected = 0; - - m_debugCanvas = canvas; - if(!m_debugCanvas) - return; - - QTreeWidgetItem *root = new QmlCanvasDebuggerItem(m_tree); - root->setText(0, tr("Root")); - root->setExpanded(true); - clone(root, m_canvasRoot, m_debugCanvas->root()); -} - diff --git a/src/declarative/debugger/qmldebugclient.cpp b/src/declarative/debugger/qmldebugclient.cpp new file mode 100644 index 0000000..85ccf0b --- /dev/null +++ b/src/declarative/debugger/qmldebugclient.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmldebugclient.h" +#include <private/qtcpsocket_p.h> +#include <QtDeclarative/qpacketprotocol.h> +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +class QmlDebugClientPrivate : public QObject +{ + Q_OBJECT +public: + QmlDebugClientPrivate(QmlDebugClient *c); + QmlDebugClient *q; + QPacketProtocol *protocol; + + QStringList enabled; + QHash<QString, QmlDebugClientPlugin *> plugins; +public slots: + void connected(); + void readyRead(); +}; + +QmlDebugClientPrivate::QmlDebugClientPrivate(QmlDebugClient *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 QmlDebugClientPrivate::connected() +{ + QPacket pack; + pack << QString(QLatin1String("QmlDebugServer")) << enabled; + protocol->send(pack); +} + +void QmlDebugClientPrivate::readyRead() +{ + QPacket pack = protocol->read(); + QString name; QByteArray message; + pack >> name >> message; + + QHash<QString, QmlDebugClientPlugin *>::Iterator iter = + plugins.find(name); + if (iter == plugins.end()) { + qWarning() << "QmlDebugClient: Message received for missing plugin" << name; + } else { + (*iter)->messageReceived(message); + } +} + +QmlDebugClient::QmlDebugClient(QObject *parent) +: QTcpSocket(parent), d(new QmlDebugClientPrivate(this)) +{ +} + +class QmlDebugClientPluginPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlDebugClientPlugin); +public: + QmlDebugClientPluginPrivate(); + + QString name; + QmlDebugClient *client; + bool enabled; +}; + +QmlDebugClientPluginPrivate::QmlDebugClientPluginPrivate() +: client(0), enabled(false) +{ +} + +QmlDebugClientPlugin::QmlDebugClientPlugin(const QString &name, + QmlDebugClient *parent) +: QObject(*(new QmlDebugClientPluginPrivate), parent) +{ + Q_D(QmlDebugClientPlugin); + d->name = name; + d->client = parent; + + if (!d->client) + return; + + if (d->client->d->plugins.contains(name)) { + qWarning() << "QmlDebugClientPlugin: Conflicting plugin name" << name; + d->client = 0; + } else { + d->client->d->plugins.insert(name, this); + } +} + +QString QmlDebugClientPlugin::name() const +{ + Q_D(const QmlDebugClientPlugin); + return d->name; +} + +bool QmlDebugClientPlugin::isEnabled() const +{ + Q_D(const QmlDebugClientPlugin); + return d->enabled; +} + +void QmlDebugClientPlugin::setEnabled(bool e) +{ + Q_D(QmlDebugClientPlugin); + 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); + } + } +} + +void QmlDebugClientPlugin::sendMessage(const QByteArray &message) +{ + Q_D(QmlDebugClientPlugin); + + if (!d->client || d->client->state() != QTcpSocket::ConnectedState) + return; + + QPacket pack; + pack << d->name << message; + d->client->d->protocol->send(pack); +} + +void QmlDebugClientPlugin::messageReceived(const QByteArray &) +{ +} + +#include "qmldebugclient.moc" + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qmldebugclient.h b/src/declarative/debugger/qmldebugclient.h new file mode 100644 index 0000000..3fbf534 --- /dev/null +++ b/src/declarative/debugger/qmldebugclient.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 QmlDebugClientPrivate; +class Q_DECLARATIVE_EXPORT QmlDebugClient : public QTcpSocket +{ + Q_OBJECT + Q_DISABLE_COPY(QmlDebugClient) +public: + QmlDebugClient(QObject * = 0); + +private: + QmlDebugClientPrivate *d; + friend class QmlDebugClientPlugin; + friend class QmlDebugClientPluginPrivate; +}; + +class QmlDebugClientPluginPrivate; +class Q_DECLARATIVE_EXPORT QmlDebugClientPlugin : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlDebugClientPlugin) + Q_DISABLE_COPY(QmlDebugClientPlugin) + +public: + QmlDebugClientPlugin(const QString &, QmlDebugClient *parent); + + QString name() const; + + bool isEnabled() const; + void setEnabled(bool); + + void sendMessage(const QByteArray &); + +protected: + virtual void messageReceived(const QByteArray &); + +private: + friend class QmlDebugClient; + friend class QmlDebugClientPrivate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLDEBUGCLIENT_H diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index 0bbcb2c..c925148 100644 --- a/src/declarative/debugger/qmldebugger.cpp +++ b/src/declarative/debugger/qmldebugger.cpp @@ -61,11 +61,10 @@ #include <QtDeclarative/qmlexpression.h> #include <private/qmlpropertyview_p.h> #include <private/qmlwatches_p.h> -#include <private/qmlcanvasdebugger_p.h> QmlDebugger::QmlDebugger(QWidget *parent) : QWidget(parent), m_tree(0), m_warnings(0), m_watchTable(0), m_watches(0), - m_canvas(0), m_properties(0), m_text(0), m_highlightedItem(0) + m_properties(0), m_text(0), m_highlightedItem(0) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); @@ -111,11 +110,6 @@ QmlDebugger::QmlDebugger(QWidget *parent) tabs->addTab(m_properties, tr("Properties")); tabs->setCurrentWidget(m_properties); - m_canvas = new QmlCanvasDebugger(m_watches, this); - QObject::connect(m_canvas, SIGNAL(objectClicked(quint32)), - this, SLOT(highlightObject(quint32))); - tabs->addTab(m_canvas, tr("Canvas")); - splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); @@ -339,7 +333,6 @@ bool operator<(const QPair<quint32, QPair<int, QString> > &lhs, void QmlDebugger::setCanvas(QSimpleCanvas *c) { - m_canvas->setCanvas(c); } void QmlDebugger::setDebugObject(QObject *obj) diff --git a/src/declarative/debugger/qmldebugger.h b/src/declarative/debugger/qmldebugger.h index 4641bce..10b2f9a 100644 --- a/src/declarative/debugger/qmldebugger.h +++ b/src/declarative/debugger/qmldebugger.h @@ -61,7 +61,6 @@ class QmlPropertyView; class QmlWatches; class QmlObjectTree; class QmlContext; -class QmlCanvasDebugger; class QSimpleCanvas; class QmlDebugger : public QWidget { @@ -88,7 +87,6 @@ private: QTreeWidget *m_warnings; QTableView *m_watchTable; QmlWatches *m_watches; - QmlCanvasDebugger *m_canvas; QmlPropertyView *m_properties; QPlainTextEdit *m_text; QPointer<QObject> m_object; diff --git a/src/declarative/debugger/qmldebugserver.cpp b/src/declarative/debugger/qmldebugserver.cpp new file mode 100644 index 0000000..a253e8c --- /dev/null +++ b/src/declarative/debugger/qmldebugserver.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmldebugserver.h" +#include <QtCore/qdebug.h> +#include <QtNetwork/qtcpserver.h> +#include <QtNetwork/qtcpsocket.h> +#include <private/qobject_p.h> +#include <QtDeclarative/qpacketprotocol.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +class QmlDebugServerPrivate; +class QmlDebugServer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlDebugServer) + Q_DISABLE_COPY(QmlDebugServer) +public: + static QmlDebugServer *instance(); + +private slots: + void readyRead(); + +private: + friend class QmlDebugServerPlugin; + friend class QmlDebugServerPluginPrivate; + QmlDebugServer(int); +}; + +class QmlDebugServerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlDebugServer); +public: + QmlDebugServerPrivate(); + void init(int port); + + QTcpSocket *connection; + QPacketProtocol *protocol; + QHash<QString, QmlDebugServerPlugin *> plugins; + QStringList enabledPlugins; +}; + +class QmlDebugServerPluginPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlDebugServerPlugin); +public: + QmlDebugServerPluginPrivate(); + + QString name; + QmlDebugServer *server; +}; + +QmlDebugServerPrivate::QmlDebugServerPrivate() +: connection(0), protocol(0) +{ +} + +void QmlDebugServerPrivate::init(int port) +{ + 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); + } + + if (server && server->d_func()->connection) + return server; + else + return 0; +} + +QmlDebugServer::QmlDebugServer(int port) +: QObject(*(new QmlDebugServerPrivate)) +{ + Q_D(QmlDebugServer); + d->init(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, QmlDebugServerPlugin *>::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, QmlDebugServerPlugin *>::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, QmlDebugServerPlugin *>::Iterator iter = + d->plugins.find(name); + if (iter == d->plugins.end()) { + qWarning() << "QmlDebugServer: Message received for missing plugin" << name; + } else { + (*iter)->messageReceived(message); + } + } + } +} + +QmlDebugServerPluginPrivate::QmlDebugServerPluginPrivate() +: server(0) +{ +} + +QmlDebugServerPlugin::QmlDebugServerPlugin(const QString &name, QObject *parent) +: QObject(*(new QmlDebugServerPluginPrivate), parent) +{ + Q_D(QmlDebugServerPlugin); + d->name = name; + d->server = QmlDebugServer::instance(); + + if (!d->server) + return; + + if (d->server->d_func()->plugins.contains(name)) { + qWarning() << "QmlDebugServerPlugin: Conflicting plugin name" << name; + d->server = 0; + } else { + d->server->d_func()->plugins.insert(name, this); + } +} + +QString QmlDebugServerPlugin::name() const +{ + Q_D(const QmlDebugServerPlugin); + return d->name; +} + +bool QmlDebugServerPlugin::isEnabled() const +{ + Q_D(const QmlDebugServerPlugin); + return (d->server && d->server->d_func()->enabledPlugins.contains(d->name)); +} + +bool QmlDebugServerPlugin::isDebuggingEnabled() +{ + return QmlDebugServer::instance() != 0; +} + +QString QmlDebugServerPlugin::objectToString(QObject *obj) +{ + if(!obj) + return QLatin1String("NULL"); + + QString objectName = obj->objectName(); + if(objectName.isEmpty()) + objectName = QLatin1String("<unnamed>"); + + QString rv = QLatin1String(obj->metaObject()->className()) + + QLatin1String(": ") + objectName; + + return rv; +} + +void QmlDebugServerPlugin::sendMessage(const QByteArray &message) +{ + Q_D(QmlDebugServerPlugin); + + if (!d->server || !d->server->d_func()->connection) + return; + + QPacket pack; + pack << d->name << message; + d->server->d_func()->protocol->send(pack); +} + +void QmlDebugServerPlugin::enabledChanged(bool) +{ +} + +void QmlDebugServerPlugin::messageReceived(const QByteArray &) +{ +} + +#include "qmldebugserver.moc" + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qmlcanvasdebugger_p.h b/src/declarative/debugger/qmldebugserver.h index 80a2322..02fe7d1 100644 --- a/src/declarative/debugger/qmlcanvasdebugger_p.h +++ b/src/declarative/debugger/qmldebugserver.h @@ -39,51 +39,44 @@ ** ****************************************************************************/ -#ifndef QMLCANVASDEBUGGER_P_H -#define QMLCANVASDEBUGGER_P_H +#ifndef QMLDEBUGSERVER_H +#define QMLDEBUGSERVER_H -#include <QtGui/qwidget.h> -#include <QtCore/qpointer.h> +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QSimpleCanvas; -class QSimpleCanvasItem; -class QTreeWidget; -class QTreeWidgetItem; -class QmlWatches; -class QmlCanvasDebugger : public QWidget +class QmlDebugServerPluginPrivate; +class QmlDebugServerPlugin : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(QmlDebugServerPlugin) + Q_DISABLE_COPY(QmlDebugServerPlugin) public: - QmlCanvasDebugger(QmlWatches *, QWidget *parent = 0); + QmlDebugServerPlugin(const QString &, QObject *parent = 0); - void setCanvas(QSimpleCanvas *); + QString name() const; -signals: - void objectClicked(quint32); + bool isEnabled() const; -private slots: - void refresh(); - void itemClicked(QTreeWidgetItem *); - void itemExpanded(QTreeWidgetItem *); - void itemCollapsed(QTreeWidgetItem *); - void setX(int); - void setY(int); + void sendMessage(const QByteArray &); -private: - void setOpacityRecur(QTreeWidgetItem *, qreal); - void clone(QTreeWidgetItem *, QSimpleCanvasItem *me, QSimpleCanvasItem *them); + static bool isDebuggingEnabled(); + static QString objectToString(QObject *obj); + +protected: + virtual void enabledChanged(bool); + virtual void messageReceived(const QByteArray &); - QmlWatches *m_watches; - QTreeWidget *m_tree; - QSimpleCanvas *m_canvas; - QSimpleCanvasItem *m_canvasRoot; - QPointer<QSimpleCanvas> m_debugCanvas; - QTreeWidgetItem *m_selected; +private: + friend class QmlDebugServer; }; QT_END_NAMESPACE -#endif // QMLCANVASDEBUGGER_P_H +QT_END_HEADER + +#endif // QMLDEBUGSERVER_H diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp new file mode 100644 index 0000000..6911b89 --- /dev/null +++ b/src/declarative/debugger/qpacketprotocol.cpp @@ -0,0 +1,462 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qpacketprotocol.h" +#include <QBuffer> + +#define MAX_PACKET_SIZE 0x7FFFFFFF + +/*! + \class QPacketProtocol + + \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))); + } + +signals: + void readyRead(); + void packetWritten(); + void invalidPacket(); + +public 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 + \inpublicgroup QtBaseModule + + \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 behaviour. + + \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 + \inpublicgroup QtBaseModule + + \internal + */ +QPacketAutoSend::QPacketAutoSend(QPacketProtocol * _p) +: QPacket(), p(_p) +{ +} + +QPacketAutoSend::~QPacketAutoSend() +{ + if(!b.isEmpty()) + p->send(*this); +} + +#include "qpacketprotocol.moc" + diff --git a/src/declarative/debugger/qpacketprotocol.h b/src/declarative/debugger/qpacketprotocol.h new file mode 100644 index 0000000..6dd8bda --- /dev/null +++ b/src/declarative/debugger/qpacketprotocol.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QPACKETPROTOCOL_H +#define QPACKETPROTOCOL_H + +#include <QtCore/qobject.h> +#include <QtCore/qdatastream.h> + +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(); + +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; +}; + +#endif diff --git a/src/declarative/canvas/monitor/main.cpp b/tools/qmldebugger/canvasframerate.cpp index f5f40bd..022aed5 100644 --- a/src/declarative/canvas/monitor/main.cpp +++ b/tools/qmldebugger/canvasframerate.cpp @@ -1,8 +1,18 @@ -#include <QApplication> -#include <QWidget> -#include <QPainter> -#include <QTcpSocket> -#include <QScrollBar> +#include "canvasframerate.h" +#include <QtGui/qwidget.h> +#include <QtGui/qpainter.h> +#include <QtGui/qscrollbar.h> +#include <QtDeclarative/qmldebugclient.h> +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatastream.h> +#include <QtGui/qboxlayout.h> +#include <QResizeEvent> +#include <QShowEvent> +#include <QTabWidget> +#include <QPushButton> +#include <QLineEdit> +#include <QCheckBox> class QLineGraph : public QWidget { @@ -17,15 +27,12 @@ public slots: protected: virtual void paintEvent(QPaintEvent *); - virtual void mousePressEvent(QMouseEvent *); - virtual void resizeEvent(QResizeEvent *); - virtual void showEvent(QShowEvent *); + virtual QSize sizeHint() const; private slots: void scrollbarChanged(int); private: - void positionScrollbar(); void updateScrollbar(); void drawSample(QPainter *, int, const QRect &); void drawTime(QPainter *, const QRect &); @@ -49,43 +56,27 @@ QLineGraph::QLineGraph(QWidget *parent) sb.setMinimum(0); sb.setSingleStep(1); + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + layout->addStretch(2); + layout->addWidget(&sb); QObject::connect(&sb, SIGNAL(valueChanged(int)), this, SLOT(scrollbarChanged(int))); } -void QLineGraph::scrollbarChanged(int v) -{ - if(ignoreScroll) - return; - - position = v; - update(); -} - -void QLineGraph::positionScrollbar() -{ - sb.setFixedWidth(width()); - sb.move(0, height() - sb.height()); -} - -void QLineGraph::resizeEvent(QResizeEvent *e) +QSize QLineGraph::sizeHint() const { - QWidget::resizeEvent(e); - positionScrollbar(); + return QSize(800, 600); } -void QLineGraph::showEvent(QShowEvent *e) +void QLineGraph::scrollbarChanged(int v) { - QWidget::showEvent(e); - positionScrollbar(); -} + if(ignoreScroll) + return; -void QLineGraph::mousePressEvent(QMouseEvent *) -{ - if(position == -1) { - position = qMax(0, _samples.count() - samplesPerWidth - 1); - } else { + if (v == sb.maximum()) position = -1; - } + else + position = v; update(); } @@ -115,6 +106,11 @@ void QLineGraph::addSample(int a, int b, int c, int d, bool isBreak) update(); } +void QLineGraph::setPosition(int p) +{ + scrollbarChanged(p); +} + void QLineGraph::drawTime(QPainter *p, const QRect &rect) { if(_samples.isEmpty()) @@ -211,77 +207,98 @@ void QLineGraph::paintEvent(QPaintEvent *) drawTime(&p, r); } -class MyReader : public QObject +class CanvasFrameRatePlugin : public QmlDebugClientPlugin { Q_OBJECT public: - MyReader(const QString &host, int port); + CanvasFrameRatePlugin(QmlDebugClient *client); signals: void sample(int, int, int, int, bool); -private slots: - void readyRead(); +protected: + virtual void messageReceived(const QByteArray &); private: - QTcpSocket *socket; - int la; int lb; int ld; }; -MyReader::MyReader(const QString &host, int port) -: socket(0), la(-1) +CanvasFrameRatePlugin::CanvasFrameRatePlugin(QmlDebugClient *client) +: QmlDebugClientPlugin(QLatin1String("CanvasFrameRate"), client), la(-1) { - socket = new QTcpSocket(this); - QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); - socket->connectToHost(host, port); - socket->waitForConnected(); } -void MyReader::readyRead() +void CanvasFrameRatePlugin::messageReceived(const QByteArray &data) { - static int la = -1; - static int lb; - static int ld; - - if(socket->canReadLine()) { - QString line = socket->readLine(); - - int a; - int b; - int c; - int d; - int isBreak; - sscanf(line.toLatin1().constData(), "%d %d %d %d %d", &a, &b, &c, &d, &isBreak); - - if (la != -1) - emit sample(c, lb, la, ld, isBreak); - - la = a; - lb = b; - ld = d; - } + QByteArray rwData = data; + QDataStream stream(&rwData, QIODevice::ReadOnly); + + int a; int b; int c; int d; bool isBreak; + stream >> a >> b >> c >> d >> isBreak; + + if (la != -1) + emit sample(c, lb, la, ld, isBreak); + + la = a; + lb = b; + ld = d; +} + +CanvasFrameRate::CanvasFrameRate(QmlDebugClient *client, QWidget *parent) +: QWidget(parent) +{ + m_plugin = new CanvasFrameRatePlugin(client); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0,0,0,0); + layout->setSpacing(0); + setLayout(layout); + + m_tabs = new QTabWidget(this); + layout->addWidget(m_tabs); + + QHBoxLayout *bottom = new QHBoxLayout; + layout->addLayout(bottom); + bottom->addStretch(2); + + QCheckBox *check = new QCheckBox("Enable", this); + bottom->addWidget(check); + QObject::connect(check, SIGNAL(stateChanged(int)), + this, SLOT(stateChanged(int))); + + QPushButton *pb = new QPushButton(tr("New Tab"), this); + QObject::connect(pb, SIGNAL(clicked()), this, SLOT(newTab())); + bottom->addWidget(pb); + + newTab(); } -int main(int argc, char ** argv) +void CanvasFrameRate::newTab() { - if(argc != 3) { - qWarning() << "Usage:" << argv[0] << "host port"; - return -1; + if (m_tabs->count()) { + QWidget *w = m_tabs->widget(m_tabs->count() - 1); + QObject::disconnect(m_plugin, SIGNAL(sample(int,int,int,int,bool)), + w, SLOT(addSample(int,int,int,int,bool))); } - QApplication app(argc, argv); + int id = m_tabs->count(); - MyReader reader(argv[1], atoi(argv[2])); + QLineGraph *graph = new QLineGraph(this); + QObject::connect(m_plugin, SIGNAL(sample(int,int,int,int,bool)), + graph, SLOT(addSample(int,int,int,int,bool))); - QLineGraph graph; - QObject::connect(&reader, SIGNAL(sample(int,int,int,int,bool)), &graph, SLOT(addSample(int,int,int,int,bool))); - graph.setFixedSize(800, 600); - graph.show(); + QString name = QLatin1String("Graph ") + QString::number(id); + m_tabs->addTab(graph, name); + m_tabs->setCurrentIndex(id); +} + +void CanvasFrameRate::stateChanged(int s) +{ + bool checked = s != 0; - return app.exec(); + static_cast<QmlDebugClientPlugin *>(m_plugin)->setEnabled(checked); } -#include "main.moc" +#include "canvasframerate.moc" diff --git a/tools/qmldebugger/canvasframerate.h b/tools/qmldebugger/canvasframerate.h new file mode 100644 index 0000000..543f233 --- /dev/null +++ b/tools/qmldebugger/canvasframerate.h @@ -0,0 +1,24 @@ +#ifndef CANVASFRAMERATE_H +#define CANVASFRAMERATE_H + +#include <QWidget> + +class QmlDebugClient; +class QTabWidget; +class CanvasFrameRate : public QWidget +{ + Q_OBJECT +public: + CanvasFrameRate(QmlDebugClient *, QWidget *parent = 0); + +private slots: + void newTab(); + void stateChanged(int); + +private: + QTabWidget *m_tabs; + QObject *m_plugin; +}; + +#endif // CANVASFRAMERATE_H + diff --git a/tools/qmldebugger/canvasscene.cpp b/tools/qmldebugger/canvasscene.cpp new file mode 100644 index 0000000..2d5b764 --- /dev/null +++ b/tools/qmldebugger/canvasscene.cpp @@ -0,0 +1,245 @@ +#include "canvasscene.h" +#include <QtDeclarative/qmldebugclient.h> +#include <QDataStream> +#include <QVBoxLayout> +#include <QPushButton> +#include <QSpinBox> +#include <QSplitter> +#include <QtDeclarative/qfxrect.h> +#include <QtDeclarative/qfximage.h> + +class CanvasSceneClientPlugin : public QmlDebugClientPlugin +{ +public: + CanvasSceneClientPlugin(QmlDebugClient *, CanvasScene *s); + +protected: + void messageReceived(const QByteArray &); + +private: + void dump(QDataStream &, int indent); + CanvasScene *scene; +}; + +class QmlCanvasDebuggerItem : public QTreeWidgetItem +{ +public: + QmlCanvasDebuggerItem(QTreeWidget *tree) + : QTreeWidgetItem(tree), me(0), img(0) + { + } + + QmlCanvasDebuggerItem(QTreeWidgetItem *item) + : QTreeWidgetItem(item), me(0), img(0) + { + } + + QFxRect *me; + QFxImage *img; +}; + +CanvasSceneClientPlugin::CanvasSceneClientPlugin(QmlDebugClient *c, + CanvasScene *s) +: QmlDebugClientPlugin(QLatin1String("CanvasScene"), c), scene(s) +{ +} + +void CanvasSceneClientPlugin::messageReceived(const QByteArray &data) +{ + QByteArray d = data; + QDataStream ds(&d, QIODevice::ReadOnly); + + scene->message(ds); +} + +void CanvasScene::message(QDataStream &ds) +{ + QList<QSimpleCanvasItem *> children = m_canvasRoot->children(); + qDeleteAll(children); + m_tree->clear(); + m_selected = 0; + + QTreeWidgetItem *root = new QmlCanvasDebuggerItem(m_tree); + root->setText(0, tr("Root")); + root->setExpanded(true); + clone(root, m_canvasRoot, ds); +} + +void CanvasScene::clone(QTreeWidgetItem *item, QSimpleCanvasItem *me, + QDataStream &ds) +{ + int children; + ds >> children; + + for (int ii = 0; ii < children; ++ii) { + QString name; + qreal x, y, z, width, height, scale; + QTransform transform; + bool activeFocus; + int transformOrigin, flip, options; + QPixmap pix; + + ds >> name >> x >> y >> z >> width >> height >> transformOrigin >> scale + >> flip >> transform >> activeFocus >> options >> pix; + + QmlCanvasDebuggerItem *childItem = new QmlCanvasDebuggerItem(item); + childItem->setText(0, name); + childItem->setExpanded(true); + + QFxRect *rect = new QFxRect; + rect->setParent(me); + rect->setX(x); + rect->setY(y); + rect->setZ(z); + rect->setWidth(width); + rect->setHeight(height); + rect->setTransformOrigin((QSimpleCanvasItem::TransformOrigin)transformOrigin); + rect->setScale(scale); + rect->setFlip((QSimpleCanvasItem::Flip)flip); + rect->setTransform(transform); + + if (activeFocus) + rect->setColor(QColor(0, 0, 0, 10)); + else if(options & QSimpleCanvasItem::IsFocusPanel) + rect->setColor(QColor(0, 255, 0, 10)); + else if(options & QSimpleCanvasItem::IsFocusRealm) + rect->setColor(QColor(0, 0, 255, 10)); + else + rect->setColor(QColor(255, 0, 0, 10)); + + if (pix.width() > 0 || pix.height() > 0) { + QFxImage *img = new QFxImage; + img->setParent(rect); + img->setWidth(width); + img->setHeight(height); + img->setPixmap(pix); + img->setOpacity(0); + childItem->img = img; + } + + childItem->me = rect; + + clone(childItem, rect, ds); + } +} + +void CanvasSceneClientPlugin::dump(QDataStream &ds, int indent) +{ + QString name; + qreal x, y, z, width, height, scale; + QTransform transform; + bool activeFocus; + int transformOrigin, flip, options, count; + QPixmap pix; + + ds >> name >> x >> y >> z >> width >> height >> transformOrigin >> scale + >> flip >> transform >> activeFocus >> options >> pix >> count; + + QByteArray ba(indent * 4, ' '); + qWarning() << ba.constData() << name << x << y; + + for(int ii = 0; ii < count; ++ii) + dump(ds, indent + 1); +} + +CanvasScene::CanvasScene(QmlDebugClient *c, QWidget *parent) +: QWidget(parent) +{ + client = new CanvasSceneClientPlugin(c, this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0,0,0,0); + layout->setSpacing(0); + setLayout(layout); + QSplitter *splitter = new QSplitter(this); + + m_tree = new QTreeWidget(this); + m_tree->setHeaderHidden(true); + QObject::connect(m_tree, SIGNAL(itemExpanded(QTreeWidgetItem*)), + this, SLOT(itemExpanded(QTreeWidgetItem*))); + QObject::connect(m_tree, SIGNAL(itemCollapsed(QTreeWidgetItem*)), + this, SLOT(itemCollapsed(QTreeWidgetItem*))); + QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + this, SLOT(itemClicked(QTreeWidgetItem*))); + m_canvas = new QSimpleCanvas(QSimpleCanvas::SimpleCanvas, this); + m_canvasRoot = new QSimpleCanvasItem; + m_canvasRoot->setParent(m_canvas->root()); + splitter->addWidget(m_tree); + splitter->addWidget(m_canvas); + splitter->setStretchFactor(1, 2); + layout->addWidget(splitter); + + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->setContentsMargins(0,0,0,0); + hlayout->addStretch(2); + hlayout->setSpacing(0); + layout->addLayout(hlayout); + QSpinBox *x = new QSpinBox(this); + x->setSingleStep(50); + x->setMaximum(10000); + x->setMinimum(-10000); + QObject::connect(x, SIGNAL(valueChanged(int)), this, SLOT(setX(int))); + QSpinBox *y = new QSpinBox(this); + y->setSingleStep(50); + y->setMaximum(10000); + y->setMinimum(-10000); + QObject::connect(y, SIGNAL(valueChanged(int)), this, SLOT(setY(int))); + hlayout->addWidget(x); + hlayout->addWidget(y); + QPushButton *pb = new QPushButton(tr("Refresh"), this); + QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh())); + hlayout->addWidget(pb); +} + +void CanvasScene::refresh() +{ + client->sendMessage(QByteArray()); +} + +void CanvasScene::itemExpanded(QTreeWidgetItem *i) +{ + QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); + if(item->me) + item->me->setOpacity(1); +} + +void CanvasScene::setOpacityRecur(QTreeWidgetItem *i, qreal op) +{ + QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); + if(item->img) + item->img->setOpacity(op); + + for(int ii = 0; ii < item->childCount(); ++ii) + setOpacityRecur(item->child(ii), op); +} + +void CanvasScene::itemClicked(QTreeWidgetItem *i) +{ + QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); + + if(m_selected) { + setOpacityRecur(m_selected, 0); + m_selected = 0; + } + + m_selected = item; + setOpacityRecur(m_selected, 1); +} + +void CanvasScene::itemCollapsed(QTreeWidgetItem *i) +{ + QmlCanvasDebuggerItem *item = static_cast<QmlCanvasDebuggerItem *>(i); + if(item->me) + item->me->setOpacity(0); +} + +void CanvasScene::setX(int x) +{ + m_canvasRoot->setX(x); +} + +void CanvasScene::setY(int y) +{ + m_canvasRoot->setY(y); +} + diff --git a/tools/qmldebugger/canvasscene.h b/tools/qmldebugger/canvasscene.h new file mode 100644 index 0000000..d980241 --- /dev/null +++ b/tools/qmldebugger/canvasscene.h @@ -0,0 +1,39 @@ +#ifndef CANVASSCENE_H +#define CANVASSCENE_H + +#include <QWidget> +#include <QTreeWidget> +#include <QtDeclarative/qsimplecanvas.h> +#include <QtDeclarative/qsimplecanvasitem.h> + +class QmlDebugClient; +class CanvasSceneClient; +class QmlDebugClientPlugin; +class CanvasScene : public QWidget +{ +Q_OBJECT +public: + CanvasScene(QmlDebugClient *, QWidget *parent = 0); + + void message(QDataStream &); +private slots: + void refresh(); + void itemClicked(QTreeWidgetItem *); + void itemExpanded(QTreeWidgetItem *); + void itemCollapsed(QTreeWidgetItem *); + void setX(int); + void setY(int); + +private: + void setOpacityRecur(QTreeWidgetItem *, qreal); + void clone(QTreeWidgetItem *item, QSimpleCanvasItem *me, QDataStream &); + QmlDebugClientPlugin *client; + + QTreeWidget *m_tree; + QSimpleCanvas *m_canvas; + QSimpleCanvasItem *m_canvasRoot; + QTreeWidgetItem *m_selected; +}; + +#endif // CANVASSCENE_H + diff --git a/tools/qmldebugger/main.cpp b/tools/qmldebugger/main.cpp new file mode 100644 index 0000000..5b94cbb --- /dev/null +++ b/tools/qmldebugger/main.cpp @@ -0,0 +1,137 @@ +#include <QtNetwork/qtcpsocket.h> +#include <QtGui/qapplication.h> +#include <QtGui/qwidget.h> +#include <QtGui/qpainter.h> +#include <QtGui/qscrollbar.h> +#include <QtDeclarative/qmldebugclient.h> +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatastream.h> +#include "canvasframerate.h" +#include "canvasscene.h" +#include <QVBoxLayout> +#include <QPushButton> +#include <QLineEdit> +#include <QTabWidget> +#include <QSpinBox> +#include <QLabel> + +class Shell : public QWidget +{ +Q_OBJECT +public: + Shell(QWidget * = 0); + +private slots: + void connectToHost(); + void disconnectFromHost(); + void connectionStateChanged(); + +private: + QmlDebugClient client; + + QLabel *m_connectionState; + QLineEdit *m_host; + QSpinBox *m_port; + QPushButton *m_connectButton; + QPushButton *m_disconnectButton; +}; + +Shell::Shell(QWidget *parent) +: QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + + QHBoxLayout *connectLayout = new QHBoxLayout; + layout->addLayout(connectLayout); + connectLayout->addStretch(2); + + m_connectionState = new QLabel(this); + connectLayout->addWidget(m_connectionState); + m_host = new QLineEdit(this); + m_host->setText("127.0.0.1"); + connectLayout->addWidget(m_host); + m_port = new QSpinBox(this); + m_port->setMinimum(1024); + m_port->setMaximum(20000); + m_port->setValue(3768); + connectLayout->addWidget(m_port); + m_connectButton = new QPushButton(tr("Connect"), this); + QObject::connect(m_connectButton, SIGNAL(clicked()), + this, SLOT(connectToHost())); + connectLayout->addWidget(m_connectButton); + m_disconnectButton = new QPushButton(tr("Disconnect"), this); + QObject::connect(m_disconnectButton, SIGNAL(clicked()), + this, SLOT(disconnectFromHost())); + m_disconnectButton->setEnabled(false); + connectLayout->addWidget(m_disconnectButton); + + QTabWidget *tabs = new QTabWidget(this); + layout->addWidget(tabs); + + CanvasFrameRate *cfr = new CanvasFrameRate(&client, this); + tabs->addTab(cfr, tr("Frame Rate")); + + CanvasScene *cs = new CanvasScene(&client, this); + tabs->addTab(cs, tr("Scene")); + + QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(connectionStateChanged())); + connectionStateChanged(); +} + +void Shell::connectionStateChanged() +{ + switch (client.state()) { + default: + case QAbstractSocket::UnconnectedState: + m_connectionState->setText(tr("Disconnected")); + m_connectButton->setEnabled(true); + m_disconnectButton->setEnabled(false); + break; + case QAbstractSocket::HostLookupState: + m_connectionState->setText(tr("Resolving")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + break; + case QAbstractSocket::ConnectingState: + m_connectionState->setText(tr("Connecting")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + break; + case QAbstractSocket::ConnectedState: + m_connectionState->setText(tr("Connected")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + break; + case QAbstractSocket::ClosingState: + m_connectionState->setText(tr("Closing")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(false); + break; + } +} + +void Shell::connectToHost() +{ + client.connectToHost(m_host->text(), m_port->value()); +} + +void Shell::disconnectFromHost() +{ + client.disconnectFromHost(); +} + +int main(int argc, char ** argv) +{ + QApplication app(argc, argv); + + Shell shell; + shell.show(); + + + return app.exec(); +} + +#include "main.moc" diff --git a/tools/qmldebugger/qmldebugger.pro b/tools/qmldebugger/qmldebugger.pro new file mode 100644 index 0000000..757ba12 --- /dev/null +++ b/tools/qmldebugger/qmldebugger.pro @@ -0,0 +1,10 @@ +DESTDIR = ../../bin +QT += network declarative +# Input +HEADERS += canvasframerate.h canvasscene.h +SOURCES += main.cpp canvasframerate.cpp canvasscene.cpp + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +CONFIG += console |