summaryrefslogtreecommitdiffstats
path: root/tools/qmldebugger
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-02-11 08:45:31 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-02-11 08:45:31 (GMT)
commit1cd0e310f35125d4a4211c504647e918ef6220c4 (patch)
treeeb9d5ab8f2b4be40f38bb7b51f32db4c758e1473 /tools/qmldebugger
parent892d4b5e6e9495e29c4df40383e883fc19aa0baa (diff)
parent8ca8c0e7b8eef2a7e8f8babc7f54507541c81533 (diff)
downloadQt-1cd0e310f35125d4a4211c504647e918ef6220c4.zip
Qt-1cd0e310f35125d4a4211c504647e918ef6220c4.tar.gz
Qt-1cd0e310f35125d4a4211c504647e918ef6220c4.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-qml into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-qml: (3397 commits) Update QmlChanges.txt Adds qml prefix to all declarative autotests Removed "running: true" for animations used as propertyvaluesource Animations are running by default when used as property source value Fix QmlEngine offlineStoragePath test. Fix Image test on Windows. Fix FontLoader test on Windows. Test should use ceil() not floor() since ceil() is used for calculating Fix BorderImage tests on Windows. Test should use ceil() not floor() since ceil() is used for calculating Clean up Must pass app arguments onto qExec() or else test system cannot QML Object toString should use 64-bit address on 64-bit platforms Improve stability of tst_qmlecmascript::dynamicDestruction Fix tst_qmlecmascript::callQtInvokables Fixed qmldebug* tests crashing. Fix declarative/qmldom::loadDynamicProperty autotest Fix declarative/animatedimage autotest Removed the tests/auto/declarative/visual(&examples) from .pro Add EXPECT_FAIL to js parser tests in declarative ui ...
Diffstat (limited to 'tools/qmldebugger')
-rw-r--r--tools/qmldebugger/qmldebugger.pro5
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.cpp581
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.h91
-rw-r--r--tools/qmldebugger/standalone/engine.cpp219
-rw-r--r--tools/qmldebugger/standalone/engine.h101
-rw-r--r--tools/qmldebugger/standalone/engine.pngbin0 -> 6394 bytes
-rw-r--r--tools/qmldebugger/standalone/engines.qml46
-rw-r--r--tools/qmldebugger/standalone/expressionquerywidget.cpp276
-rw-r--r--tools/qmldebugger/standalone/expressionquerywidget.h105
-rw-r--r--tools/qmldebugger/standalone/main.cpp77
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.cpp274
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.h93
-rw-r--r--tools/qmldebugger/standalone/objecttree.cpp231
-rw-r--r--tools/qmldebugger/standalone/objecttree.h96
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.cpp181
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.h90
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.pri18
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.qrc7
-rw-r--r--tools/qmldebugger/standalone/refresh.pngbin0 -> 6169 bytes
-rw-r--r--tools/qmldebugger/standalone/standalone.pro19
-rw-r--r--tools/qmldebugger/standalone/watchtable.cpp366
-rw-r--r--tools/qmldebugger/standalone/watchtable.h154
22 files changed, 3030 insertions, 0 deletions
diff --git a/tools/qmldebugger/qmldebugger.pro b/tools/qmldebugger/qmldebugger.pro
new file mode 100644
index 0000000..679cae6
--- /dev/null
+++ b/tools/qmldebugger/qmldebugger.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = standalone
+
diff --git a/tools/qmldebugger/standalone/canvasframerate.cpp b/tools/qmldebugger/standalone/canvasframerate.cpp
new file mode 100644
index 0000000..d956029
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.cpp
@@ -0,0 +1,581 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmargins.h>
+
+#include <QtGui/qapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qtooltip.h>
+#include <QtGui/qslider.h>
+#include <QtGui/qscrollbar.h>
+#include <QtGui/qspinbox.h>
+#include <QtGui/qgroupbox.h>
+#include <QtGui/qboxlayout.h>
+#include <QtGui/qlabel.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qtabwidget.h>
+
+#include <QResizeEvent>
+#include <QShowEvent>
+
+#include <private/qmldebugclient_p.h>
+#include "canvasframerate.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLineGraph : public QWidget
+{
+Q_OBJECT
+public:
+ QLineGraph(QAbstractSlider *slider, QWidget * = 0);
+
+ void setPosition(int);
+
+public slots:
+ void addSample(int, int, int, bool);
+ void setResolutionForHeight(int);
+ void clear();
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+ virtual void mouseMoveEvent(QMouseEvent *);
+ virtual void leaveEvent(QEvent *);
+ virtual void wheelEvent(QWheelEvent *event);
+
+private slots:
+ void sliderChanged(int);
+
+private:
+ void updateSlider();
+ void drawSample(QPainter *, int, const QRect &, QList<QRect> *);
+ void drawTime(QPainter *, const QRect &);
+ QRect findContainingRect(const QList<QRect> &rects, const QPoint &pos) const;
+ struct Sample {
+ int sample[3];
+ bool isBreak;
+ };
+ QList<Sample> _samples;
+
+ QAbstractSlider *slider;
+ int position;
+ int samplesPerWidth;
+ int resolutionForHeight;
+ bool ignoreScroll;
+ QMargins graphMargins;
+
+ QList<QRect> rectsPaintTime; // time to do a paintEvent()
+ QList<QRect> rectsTimeBetween; // time between frames
+ QRect highlightedBar;
+};
+
+QLineGraph::QLineGraph(QAbstractSlider *slider, QWidget *parent)
+: QWidget(parent), slider(slider), position(-1), samplesPerWidth(99), resolutionForHeight(50),
+ ignoreScroll(false), graphMargins(65, 10, 71, 35)
+{
+ setMouseTracking(true);
+
+ slider->setMaximum(0);
+ slider->setMinimum(0);
+ slider->setSingleStep(1);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int)));
+}
+
+void QLineGraph::sliderChanged(int v)
+{
+ if(ignoreScroll)
+ return;
+
+ if (v == slider->maximum())
+ position = -1;
+ else
+ position = v;
+
+ update();
+
+ // update highlightedRect
+ QPoint pos = mapFromGlobal(QCursor::pos());
+ if (geometry().contains(pos)) {
+ QMouseEvent *me = new QMouseEvent(QEvent::MouseMove, pos,
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier);
+ QApplication::postEvent(this, me);
+ }
+}
+
+void QLineGraph::clear()
+{
+ _samples.clear();
+ rectsPaintTime.clear();
+ rectsTimeBetween.clear();
+ highlightedBar = QRect();
+ position = -1;
+
+ updateSlider();
+ update();
+}
+
+void QLineGraph::updateSlider()
+{
+ ignoreScroll = true;
+ slider->setMaximum(qMax(0, _samples.count() - samplesPerWidth - 1));
+
+ if(position == -1) {
+ slider->setValue(slider->maximum());
+ } else {
+ slider->setValue(position);
+ }
+ ignoreScroll = false;
+}
+
+void QLineGraph::addSample(int a, int b, int d, bool isBreak)
+{
+ Sample s;
+ s.isBreak = isBreak;
+ s.sample[0] = a;
+ s.sample[1] = b;
+ s.sample[2] = d;
+ _samples << s;
+ updateSlider();
+ update();
+}
+
+void QLineGraph::setPosition(int p)
+{
+ sliderChanged(p);
+}
+
+void QLineGraph::drawTime(QPainter *p, const QRect &rect)
+{
+ if(_samples.isEmpty())
+ return;
+
+ int first = position;
+ if(first == -1)
+ first = qMax(0, _samples.count() - samplesPerWidth - 1);
+ int last = qMin(_samples.count() - 1, first + samplesPerWidth);
+
+ qreal scaleX = qreal(rect.width()) / qreal(samplesPerWidth);
+
+ int t = 0;
+
+ for(int ii = first; ii <= last; ++ii) {
+ int sampleTime = _samples.at(ii).sample[2] / 1000;
+ if(sampleTime != t) {
+
+ int xEnd = rect.left() + scaleX * (ii - first);
+ p->drawLine(xEnd, rect.bottom(), xEnd, rect.bottom() + 7);
+
+ QRect text(xEnd - 30, rect.bottom() + 10, 60, 30);
+
+ p->drawText(text, Qt::AlignHCenter | Qt::AlignTop, QString::number(_samples.at(ii).sample[2]));
+
+ t = sampleTime;
+ }
+ }
+
+}
+
+void QLineGraph::drawSample(QPainter *p, int s, const QRect &rect, QList<QRect> *record)
+{
+ if(_samples.isEmpty())
+ return;
+
+ int first = position;
+ if(first == -1)
+ first = qMax(0, _samples.count() - samplesPerWidth - 1);
+ int last = qMin(_samples.count() - 1, first + samplesPerWidth);
+
+ qreal scaleY = qreal(rect.height()) / resolutionForHeight;
+ qreal scaleX = qreal(rect.width()) / qreal(samplesPerWidth);
+
+ int xEnd;
+ int lastXEnd = rect.left();
+
+ p->save();
+ p->setPen(Qt::NoPen);
+ for(int ii = first + 1; ii <= last; ++ii) {
+
+ xEnd = rect.left() + scaleX * (ii - first);
+ int yEnd = rect.bottom() - _samples.at(ii).sample[s] * scaleY;
+
+ if (!(s == 0 && _samples.at(ii).isBreak)) {
+ QRect bar(lastXEnd, yEnd, scaleX, _samples.at(ii).sample[s] * scaleY);
+ record->append(bar);
+ p->drawRect(bar);
+ }
+
+ lastXEnd = xEnd;
+ }
+ p->restore();
+}
+
+void QLineGraph::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+
+ QRect r(graphMargins.left(), graphMargins.top(),
+ width() - graphMargins.right(), height() - graphMargins.bottom());
+
+ p.save();
+ p.rotate(-90);
+ p.translate(-r.height()/2 - r.width()/2 - graphMargins.right(), -r.height()/2);
+ p.drawText(r, Qt::AlignCenter, tr("Frame rate"));
+ p.restore();
+
+ p.setBrush(QColor("lightsteelblue"));
+ rectsTimeBetween.clear();
+ drawSample(&p, 0, r, &rectsTimeBetween);
+
+ p.setBrush(QColor("pink"));
+ rectsPaintTime.clear();
+ drawSample(&p, 1, r, &rectsPaintTime);
+
+ if (!highlightedBar.isNull()) {
+ p.setBrush(Qt::darkGreen);
+ p.drawRect(highlightedBar);
+ }
+
+ p.setBrush(Qt::NoBrush);
+ p.drawRect(r);
+
+ slider->setGeometry(x() + r.x(), slider->y(), r.width(), slider->height());
+
+ for(int ii = 0; ii <= resolutionForHeight; ++ii) {
+ int y = 1 + r.bottom() - ii * r.height() / resolutionForHeight;
+
+ if((ii % 10) == 0) {
+ p.drawLine(r.left() - 20, y, r.left(), y);
+ QRect text(r.left() - 20 - 53, y - 10, 50, 20);
+ p.drawText(text, Qt::AlignRight | Qt::AlignVCenter, QString::number(ii));
+ } else {
+ p.drawLine(r.left() - 7, y, r.left(), y);
+ }
+ }
+
+ drawTime(&p, r);
+}
+
+void QLineGraph::mouseMoveEvent(QMouseEvent *event)
+{
+ QPoint pos = event->pos();
+
+ QRect rect = findContainingRect(rectsPaintTime, pos);
+ if (rect.isNull())
+ rect = findContainingRect(rectsTimeBetween, pos);
+
+ if (!highlightedBar.isNull())
+ update(highlightedBar.adjusted(-1, -1, 1, 1));
+ highlightedBar = rect;
+
+ if (!rect.isNull()) {
+ QRect graph(graphMargins.left(), graphMargins.top(),
+ width() - graphMargins.right(), height() - graphMargins.bottom());
+ qreal scaleY = qreal(graph.height()) / resolutionForHeight;
+ QToolTip::showText(event->globalPos(), QString::number(qRound(rect.height() / scaleY)), this, rect);
+ update(rect.adjusted(-1, -1, 1, 1));
+ }
+}
+
+void QLineGraph::leaveEvent(QEvent *)
+{
+ if (!highlightedBar.isNull()) {
+ QRect bar = highlightedBar.adjusted(-1, -1, 1, 1);
+ highlightedBar = QRect();
+ update(bar);
+ }
+}
+
+void QLineGraph::wheelEvent(QWheelEvent *event)
+{
+ QWheelEvent we(QPoint(0,0), event->delta(), event->buttons(), event->modifiers(), event->orientation());
+ QApplication::sendEvent(slider, &we);
+}
+
+void QLineGraph::setResolutionForHeight(int resolution)
+{
+ resolutionForHeight = resolution;
+ update();
+}
+
+QRect QLineGraph::findContainingRect(const QList<QRect> &rects, const QPoint &pos) const
+{
+ for (int i=0; i<rects.count(); i++) {
+ if (rects[i].contains(pos))
+ return rects[i];
+ }
+ return QRect();
+}
+
+
+class GraphWindow : public QWidget
+{
+ Q_OBJECT
+public:
+ GraphWindow(QWidget *parent = 0);
+
+ virtual QSize sizeHint() const;
+
+public slots:
+ void addSample(int, int, int, bool);
+ void setResolutionForHeight(int);
+ void clear();
+
+private:
+ QLineGraph *m_graph;
+};
+
+GraphWindow::GraphWindow(QWidget *parent)
+ : QWidget(parent)
+{
+ QSlider *scroll = new QSlider(Qt::Horizontal);
+ scroll->setFocusPolicy(Qt::WheelFocus);
+ m_graph = new QLineGraph(scroll);
+
+ setFocusPolicy(Qt::WheelFocus);
+ setFocusProxy(scroll);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 5, 0);
+ layout->setSpacing(0);
+ layout->addWidget(m_graph, 2);
+ layout->addWidget(new QLabel(tr("Total time elapsed (ms)")), 0, Qt::AlignHCenter);
+ layout->addWidget(scroll);
+}
+
+void GraphWindow::addSample(int a, int b, int d, bool isBreak)
+{
+ m_graph->addSample(a, b, d, isBreak);
+}
+
+void GraphWindow::setResolutionForHeight(int res)
+{
+ m_graph->setResolutionForHeight(res);
+}
+
+void GraphWindow::clear()
+{
+ m_graph->clear();
+}
+
+QSize GraphWindow::sizeHint() const
+{
+ return QSize(400, 220);
+}
+
+
+class CanvasFrameRatePlugin : public QmlDebugClient
+{
+ Q_OBJECT
+public:
+ CanvasFrameRatePlugin(QmlDebugConnection *client);
+
+signals:
+ void sample(int, int, int, bool);
+
+protected:
+ virtual void messageReceived(const QByteArray &);
+
+private:
+ int lb;
+ int ld;
+};
+
+CanvasFrameRatePlugin::CanvasFrameRatePlugin(QmlDebugConnection *client)
+: QmlDebugClient(QLatin1String("CanvasFrameRate"), client), lb(-1)
+{
+}
+
+void CanvasFrameRatePlugin::messageReceived(const QByteArray &data)
+{
+ QByteArray rwData = data;
+ QDataStream stream(&rwData, QIODevice::ReadOnly);
+
+ int b; int c; int d; bool isBreak;
+ stream >> b >> c >> d >> isBreak;
+
+ if (lb != -1)
+ emit sample(c, lb, ld, isBreak);
+
+ lb = b;
+ ld = d;
+}
+
+CanvasFrameRate::CanvasFrameRate(QWidget *parent)
+: QWidget(parent),
+ m_plugin(0)
+{
+ m_tabs = new QTabWidget(this);
+
+ QHBoxLayout *bottom = new QHBoxLayout;
+ bottom->setMargin(0);
+ bottom->setSpacing(10);
+
+ m_res = new QSpinBox;
+ m_res->setRange(30, 200);
+ m_res->setValue(m_res->minimum());
+ m_res->setSingleStep(10);
+ m_res->setSuffix(QLatin1String("ms"));
+ bottom->addWidget(new QLabel(tr("Resolution:")));
+ bottom->addWidget(m_res);
+
+ bottom->addStretch();
+
+ m_clearButton = new QPushButton(tr("Clear"));
+ connect(m_clearButton, SIGNAL(clicked()), SLOT(clearGraph()));
+ bottom->addWidget(m_clearButton);
+
+ QPushButton *pb = new QPushButton(tr("New Graph"), this);
+ connect(pb, SIGNAL(clicked()), this, SLOT(newTab()));
+ bottom->addWidget(pb);
+
+ m_group = new QGroupBox(tr("Enabled"));
+ m_group->setCheckable(true);
+ m_group->setChecked(false);
+ connect(m_group, SIGNAL(toggled(bool)), SLOT(enabledToggled(bool)));
+
+ QVBoxLayout *groupLayout = new QVBoxLayout(m_group);
+ groupLayout->setContentsMargins(5, 0, 5, 0);
+ groupLayout->setSpacing(2);
+ groupLayout->addWidget(m_tabs);
+ groupLayout->addLayout(bottom);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 10, 0, 0);
+ layout->setSpacing(0);
+ layout->addWidget(m_group);
+ setLayout(layout);
+}
+
+void CanvasFrameRate::reset(QmlDebugConnection *conn)
+{
+ delete m_plugin;
+ m_plugin = 0;
+
+ QWidget *w;
+ for (int i=0; i<m_tabs->count(); i++) {
+ w = m_tabs->widget(i);
+ m_tabs->removeTab(i);
+ delete w;
+ }
+
+ if (conn) {
+ connect(conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ SLOT(connectionStateChanged(QAbstractSocket::SocketState)));
+ if (conn->state() == QAbstractSocket::ConnectedState)
+ handleConnected(conn);
+ }
+}
+
+void CanvasFrameRate::connectionStateChanged(QAbstractSocket::SocketState state)
+{
+ if (state == QAbstractSocket::UnconnectedState) {
+ delete m_plugin;
+ m_plugin = 0;
+ } else if (state == QAbstractSocket::ConnectedState) {
+ handleConnected(qobject_cast<QmlDebugConnection*>(sender()));
+ }
+}
+
+void CanvasFrameRate::handleConnected(QmlDebugConnection *conn)
+{
+ delete m_plugin;
+ m_plugin = new CanvasFrameRatePlugin(conn);
+ enabledToggled(m_group->isChecked());
+ newTab();
+}
+
+void CanvasFrameRate::setSizeHint(const QSize &size)
+{
+ m_sizeHint = size;
+}
+
+QSize CanvasFrameRate::sizeHint() const
+{
+ return m_sizeHint;
+}
+
+void CanvasFrameRate::clearGraph()
+{
+ if (m_tabs->count()) {
+ GraphWindow *w = qobject_cast<GraphWindow*>(m_tabs->currentWidget());
+ if (w)
+ w->clear();
+ }
+}
+
+void CanvasFrameRate::newTab()
+{
+ if (!m_plugin)
+ return;
+
+ if (m_tabs->count()) {
+ QWidget *w = m_tabs->widget(m_tabs->count() - 1);
+ QObject::disconnect(m_plugin, SIGNAL(sample(int,int,int,bool)),
+ w, SLOT(addSample(int,int,int,bool)));
+ }
+
+ int count = m_tabs->count();
+
+ GraphWindow *graph = new GraphWindow;
+ graph->setResolutionForHeight(m_res->value());
+ connect(m_plugin, SIGNAL(sample(int,int,int,bool)),
+ graph, SLOT(addSample(int,int,int,bool)));
+ connect(m_res, SIGNAL(valueChanged(int)),
+ graph, SLOT(setResolutionForHeight(int)));
+
+ QString name = QLatin1String("Graph ") + QString::number(count + 1);
+ m_tabs->addTab(graph, name);
+ m_tabs->setCurrentIndex(count);
+}
+
+void CanvasFrameRate::enabledToggled(bool checked)
+{
+ if (m_plugin)
+ static_cast<QmlDebugClient *>(m_plugin)->setEnabled(checked);
+}
+
+QT_END_NAMESPACE
+
+#include "canvasframerate.moc"
diff --git a/tools/qmldebugger/standalone/canvasframerate.h b/tools/qmldebugger/standalone/canvasframerate.h
new file mode 100644
index 0000000..f8eec59
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 CANVASFRAMERATE_H
+#define CANVASFRAMERATE_H
+
+#include <QtCore/qpointer.h>
+#include <QtGui/qwidget.h>
+
+#include <private/qmldebugclient_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTabWidget;
+class QSlider;
+class QGroupBox;
+class QLabel;
+class QSpinBox;
+class QPushButton;
+
+class CanvasFrameRatePlugin;
+
+class CanvasFrameRate : public QWidget
+{
+ Q_OBJECT
+public:
+ CanvasFrameRate(QWidget *parent = 0);
+
+ void reset(QmlDebugConnection *conn);
+
+ void setSizeHint(const QSize &);
+ virtual QSize sizeHint() const;
+
+private slots:
+ void clearGraph();
+ void newTab();
+ void enabledToggled(bool);
+ void connectionStateChanged(QAbstractSocket::SocketState state);
+
+private:
+ void handleConnected(QmlDebugConnection *conn);
+
+ QGroupBox *m_group;
+ QTabWidget *m_tabs;
+ QSpinBox *m_res;
+ QPushButton *m_clearButton;
+ CanvasFrameRatePlugin *m_plugin;
+ QSize m_sizeHint;
+};
+
+QT_END_NAMESPACE
+
+#endif // CANVASFRAMERATE_H
+
diff --git a/tools/qmldebugger/standalone/engine.cpp b/tools/qmldebugger/standalone/engine.cpp
new file mode 100644
index 0000000..6cfd82b
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSplitter>
+#include <QTabWidget>
+#include <QFile>
+
+#include <private/qmlenginedebug_p.h>
+#include <private/qmldebugclient_p.h>
+#include <QtDeclarative/qmlcomponent.h>
+#include <QtDeclarative/qmlgraphicsitem.h>
+#include <private/qmldebugservice_p.h>
+
+#include "engine.h"
+#include "objectpropertiesview.h"
+#include "expressionquerywidget.h"
+#include "objecttree.h"
+#include "watchtable.h"
+
+QT_BEGIN_NAMESPACE
+
+
+class DebuggerEngineItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name CONSTANT);
+ Q_PROPERTY(int engineId READ engineId CONSTANT);
+
+public:
+ DebuggerEngineItem(const QString &name, int id)
+ : m_name(name), m_engineId(id) {}
+
+ QString name() const { return m_name; }
+ int engineId() const { return m_engineId; }
+
+private:
+ QString m_name;
+ int m_engineId;
+};
+
+EnginePane::EnginePane(QmlDebugConnection *conn, QWidget *parent)
+: QWidget(parent), m_client(new QmlEngineDebug(conn, this)), m_engines(0), m_context(0), m_watchTableModel(0), m_exprQueryWidget(0)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ QFile enginesFile(":/engines.qml");
+ enginesFile.open(QFile::ReadOnly);
+ Q_ASSERT(enginesFile.isOpen());
+
+ m_engineView = new QmlView(this);
+ m_engineView->rootContext()->setContextProperty("engines", qVariantFromValue(&m_engineItems));
+ m_engineView->setContentResizable(true);
+ m_engineView->setQml(enginesFile.readAll());
+ m_engineView->execute();
+ m_engineView->setFixedHeight(100);
+ QObject::connect(m_engineView->root(), SIGNAL(engineClicked(int)),
+ this, SLOT(engineSelected(int)));
+ QObject::connect(m_engineView->root(), SIGNAL(refreshEngines()),
+ this, SLOT(refreshEngines()));
+
+ m_engineView->setVisible(false);
+ layout->addWidget(m_engineView);
+
+ QSplitter *splitter = new QSplitter;
+
+ m_objTree = new ObjectTree(m_client, this);
+ m_propertiesView = new ObjectPropertiesView(m_client);
+ m_watchTableModel = new WatchTableModel(m_client, this);
+
+ m_watchTableView = new WatchTableView(m_watchTableModel);
+ m_watchTableView->setModel(m_watchTableModel);
+ WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTableModel);
+ m_watchTableView->setHorizontalHeader(header);
+
+ connect(m_objTree, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_propertiesView, SLOT(reload(QmlDebugObjectReference)));
+ connect(m_objTree, SIGNAL(expressionWatchRequested(QmlDebugObjectReference,QString)),
+ m_watchTableModel, SLOT(expressionWatchRequested(QmlDebugObjectReference,QString)));
+
+ connect(m_propertiesView, SIGNAL(activated(QmlDebugObjectReference,QmlDebugPropertyReference)),
+ m_watchTableModel, SLOT(togglePropertyWatch(QmlDebugObjectReference,QmlDebugPropertyReference)));
+
+ connect(m_watchTableModel, SIGNAL(watchCreated(QmlDebugWatch*)),
+ m_propertiesView, SLOT(watchCreated(QmlDebugWatch*)));
+
+ connect(m_watchTableView, SIGNAL(objectActivated(int)),
+ m_objTree, SLOT(setCurrentObject(int)));
+
+ m_exprQueryWidget = new ExpressionQueryWidget(ExpressionQueryWidget::SeparateEntryMode, m_client);
+ connect(m_objTree, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
+ m_exprQueryWidget, SLOT(setCurrentObject(QmlDebugObjectReference)));
+
+ QSplitter *propertiesTab = new QSplitter(Qt::Vertical);
+ propertiesTab->addWidget(m_propertiesView);
+ propertiesTab->addWidget(m_exprQueryWidget);
+ propertiesTab->setStretchFactor(0, 2);
+ propertiesTab->setStretchFactor(1, 1);
+
+ m_tabs = new QTabWidget(this);
+ m_tabs->addTab(propertiesTab, tr("Properties"));
+ m_tabs->addTab(m_watchTableView, tr("Watched"));
+
+ splitter->addWidget(m_objTree);
+ splitter->addWidget(m_tabs);
+ splitter->setStretchFactor(1, 2);
+ layout->addWidget(splitter);
+}
+
+void EnginePane::engineSelected(int id)
+{
+ qWarning() << "Engine selected" << id;
+ queryContext(id);
+}
+
+void EnginePane::queryContext(int id)
+{
+ if (m_context) {
+ delete m_context;
+ m_context = 0;
+ }
+
+ m_context = m_client->queryRootContexts(QmlDebugEngineReference(id), this);
+ if (!m_context->isWaiting())
+ contextChanged();
+ else
+ QObject::connect(m_context, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(contextChanged()));
+}
+
+void EnginePane::contextChanged()
+{
+ //dump(m_context->rootContext(), 0);
+
+ foreach (const QmlDebugObjectReference &object, m_context->rootContext().objects())
+ m_objTree->reload(object.debugId());
+
+ delete m_context; m_context = 0;
+}
+
+void EnginePane::refreshEngines()
+{
+ if (m_engines)
+ return;
+
+ m_engines = m_client->queryAvailableEngines(this);
+ if (!m_engines->isWaiting())
+ enginesChanged();
+ else
+ QObject::connect(m_engines, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(enginesChanged()));
+}
+
+void EnginePane::enginesChanged()
+{
+ qDeleteAll(m_engineItems);
+ m_engineItems.clear();
+
+ QList<QmlDebugEngineReference> engines = m_engines->engines();
+ delete m_engines; m_engines = 0;
+
+ if (engines.isEmpty())
+ qWarning("qmldebugger: no engines found!");
+
+ for (int ii = 0; ii < engines.count(); ++ii)
+ m_engineItems << new DebuggerEngineItem(engines.at(ii).name(),
+ engines.at(ii).debugId());
+
+ m_engineView->rootContext()->setContextProperty("engines", qVariantFromValue(&m_engineItems));
+
+ m_engineView->setVisible(m_engineItems.count() > 1);
+ if (m_engineItems.count() == 1)
+ engineSelected(qobject_cast<DebuggerEngineItem*>(m_engineItems.at(0))->engineId());
+}
+
+
+#include "engine.moc"
+
+QT_END_NAMESPACE
+
diff --git a/tools/qmldebugger/standalone/engine.h b/tools/qmldebugger/standalone/engine.h
new file mode 100644
index 0000000..f4c4275
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 ENGINE_H
+#define ENGINE_H
+
+#include <QWidget>
+#include <QtCore/qpointer.h>
+#include <QtDeclarative/qmlengine.h>
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qmlview.h>
+#include <private/qmldebug_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class ObjectPropertiesView;
+class QmlDebugConnection;
+class QmlDebugPropertyReference;
+class QmlDebugWatch;
+class ObjectTree;
+class WatchTableModel;
+class WatchTableView;
+class ExpressionQueryWidget;
+
+class QTabWidget;
+
+class EnginePane : public QWidget
+{
+Q_OBJECT
+public:
+ EnginePane(QmlDebugConnection *, QWidget *parent = 0);
+
+public slots:
+ void refreshEngines();
+
+private slots:
+ void enginesChanged();
+
+ void queryContext(int);
+ void contextChanged();
+
+ void engineSelected(int);
+
+private:
+ QmlEngineDebug *m_client;
+ QmlDebugEnginesQuery *m_engines;
+ QmlDebugRootContextQuery *m_context;
+
+ ObjectTree *m_objTree;
+ QTabWidget *m_tabs;
+ WatchTableView *m_watchTableView;
+ WatchTableModel *m_watchTableModel;
+ ExpressionQueryWidget *m_exprQueryWidget;
+
+ QmlView *m_engineView;
+ QList<QObject *> m_engineItems;
+
+ ObjectPropertiesView *m_propertiesView;
+};
+
+QT_END_NAMESPACE
+
+#endif // ENGINE_H
+
diff --git a/tools/qmldebugger/standalone/engine.png b/tools/qmldebugger/standalone/engine.png
new file mode 100644
index 0000000..a0a8a04
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.png
Binary files differ
diff --git a/tools/qmldebugger/standalone/engines.qml b/tools/qmldebugger/standalone/engines.qml
new file mode 100644
index 0000000..0b2b7ac
--- /dev/null
+++ b/tools/qmldebugger/standalone/engines.qml
@@ -0,0 +1,46 @@
+import Qt 4.6
+
+Item {
+ height: 100
+ id: root
+ signal engineClicked(int id)
+ signal refreshEngines()
+
+ Row {
+ anchors.fill: parent
+ Repeater {
+ model: engines
+ Item {
+ width: 100; height: 100;
+ Image {
+ id: engineIcon;
+ source: "qrc:/engine.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Text {
+ anchors.top: engineIcon.bottom;
+ text: modelData.name + "(" + modelData.engineId + ")"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: root.engineClicked(modelData.engineId);
+ }
+ }
+ }
+ }
+
+
+ Image {
+ y: 15
+ source: "qrc:/refresh.png";
+ width: 75;
+ height: 63;
+ smooth: true
+ anchors.right: parent.right
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: root.refreshEngines()
+ }
+ }
+}
diff --git a/tools/qmldebugger/standalone/expressionquerywidget.cpp b/tools/qmldebugger/standalone/expressionquerywidget.cpp
new file mode 100644
index 0000000..cd59871
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtCore/qdebug.h>
+
+#include <QtGui/qlabel.h>
+#include <QtGui/qtextedit.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qgroupbox.h>
+#include <QtGui/qtextobject.h>
+#include <QtGui/qlayout.h>
+
+#include "expressionquerywidget.h"
+
+ExpressionQueryWidget::ExpressionQueryWidget(Mode mode, QmlEngineDebug *client, QWidget *parent)
+ : QWidget(parent),
+ m_mode(mode),
+ m_client(client),
+ m_query(0),
+ m_textEdit(new QTextEdit),
+ m_lineEdit(0)
+{
+ m_prompt = QLatin1String(">> ");
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(m_textEdit);
+
+ updateTitle();
+
+ if (m_mode == SeparateEntryMode) {
+ m_lineEdit = new QLineEdit;
+ connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression()));
+ QHBoxLayout *hbox = new QHBoxLayout;
+ hbox->setMargin(5);
+ hbox->setSpacing(5);
+ hbox->addWidget(new QLabel(tr("Expression:")));
+ hbox->addWidget(m_lineEdit);
+ layout->addLayout(hbox);
+
+ m_textEdit->setReadOnly(true);
+ m_lineEdit->installEventFilter(this);
+ } else {
+ m_textEdit->installEventFilter(this);
+ appendPrompt();
+ }
+}
+
+void ExpressionQueryWidget::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ExpressionQueryWidget::clear()
+{
+ m_textEdit->clear();
+ if (m_lineEdit)
+ m_lineEdit->clear();
+ if (m_mode == ShellMode)
+ appendPrompt();
+}
+
+void ExpressionQueryWidget::updateTitle()
+{
+ if (m_currObject.debugId() < 0) {
+ m_title = tr("Expression queries");
+ } else {
+ QString desc = QLatin1String("<")
+ + m_currObject.className() + QLatin1String(": ")
+ + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed>") : m_currObject.name())
+ + QLatin1String(">");
+ m_title = tr("Expression queries (using context for %1)" , "Selected object").arg(desc);
+ }
+}
+
+void ExpressionQueryWidget::appendPrompt()
+{
+ m_textEdit->moveCursor(QTextCursor::End);
+
+ if (m_mode == SeparateEntryMode) {
+ m_textEdit->insertPlainText("\n");
+ } else {
+ m_textEdit->setTextColor(Qt::gray);
+ m_textEdit->append(m_prompt);
+ }
+}
+
+void ExpressionQueryWidget::setCurrentObject(const QmlDebugObjectReference &obj)
+{
+ m_currObject = obj;
+ updateTitle();
+}
+
+void ExpressionQueryWidget::checkCurrentContext()
+{
+ m_textEdit->moveCursor(QTextCursor::End);
+
+ if (m_currObject.debugId() != -1 && m_currObject.debugId() != m_objectAtLastFocus.debugId())
+ showCurrentContext();
+ m_objectAtLastFocus = m_currObject;
+}
+
+void ExpressionQueryWidget::showCurrentContext()
+{
+ if (m_mode == ShellMode) {
+ // clear the initial prompt
+ if (m_textEdit->document()->lineCount() == 1)
+ m_textEdit->clear();
+ }
+
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->append(m_currObject.className()
+ + QLatin1String(": ")
+ + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed object>") : m_currObject.name()));
+ appendPrompt();
+}
+
+void ExpressionQueryWidget::executeExpression()
+{
+ if (!m_client)
+ return;
+
+ if (m_mode == SeparateEntryMode)
+ m_expr = m_lineEdit->text().trimmed();
+ else
+ m_expr = m_expr.trimmed();
+
+ if (!m_expr.isEmpty() && m_currObject.debugId() != -1) {
+ if (m_query)
+ delete m_query;
+ m_query = m_client->queryExpressionResult(m_currObject.debugId(), m_expr, this);
+ if (!m_query->isWaiting())
+ showResult();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(showResult()));
+
+ m_lastExpr = m_expr;
+ if (m_lineEdit)
+ m_lineEdit->clear();
+ }
+}
+
+void ExpressionQueryWidget::showResult()
+{
+ if (m_query) {
+ m_textEdit->moveCursor(QTextCursor::End);
+ QVariant value = m_query->result();
+ QString result;
+
+ if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
+ result = tr("<%1 items>", "%1 = number of items").arg(value.toList().count());
+ } else if (value.isNull()) {
+ result = QLatin1String("<no value>");
+ } else {
+ result = value.toString();
+ }
+
+ if (m_mode == SeparateEntryMode) {
+ m_textEdit->setTextColor(Qt::black);
+ m_textEdit->setFontWeight(QFont::Bold);
+ m_textEdit->insertPlainText(m_expr + " : ");
+ m_textEdit->setFontWeight(QFont::Normal);
+ m_textEdit->insertPlainText(result);
+ } else {
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->insertPlainText(" => ");
+ m_textEdit->setTextColor(Qt::black);
+ m_textEdit->insertPlainText(result);
+ }
+ appendPrompt();
+ m_expr.clear();
+ }
+}
+
+bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_textEdit) {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ int key = keyEvent->key();
+ if (key == Qt::Key_Return || key == Qt::Key_Enter) {
+ executeExpression();
+ return true;
+ } else if (key == Qt::Key_Backspace) {
+ // ensure m_expr doesn't contain backspace characters
+ QTextCursor cursor = m_textEdit->textCursor();
+ bool atLastLine = !(cursor.block().next().isValid());
+ if (!atLastLine)
+ return true;
+ if (cursor.columnNumber() <= m_prompt.count())
+ return true;
+ cursor.deletePreviousChar();
+ m_expr = cursor.block().text().mid(m_prompt.count());
+ return true;
+ } else {
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::black);
+ m_expr += keyEvent->text();
+ }
+ break;
+ }
+ case QEvent::FocusIn:
+ checkCurrentContext();
+ m_textEdit->moveCursor(QTextCursor::End);
+ break;
+ default:
+ break;
+ }
+ } else if (obj == m_lineEdit) {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ int key = keyEvent->key();
+ if (key == Qt::Key_Up && m_lineEdit->text() != m_lastExpr) {
+ m_expr = m_lineEdit->text();
+ if (!m_lastExpr.isEmpty())
+ m_lineEdit->setText(m_lastExpr);
+ } else if (key == Qt::Key_Down) {
+ m_lineEdit->setText(m_expr);
+ }
+ break;
+ }
+ case QEvent::FocusIn:
+ checkCurrentContext();
+ break;
+ default:
+ break;
+ }
+ }
+ return QWidget::eventFilter(obj, event);
+}
diff --git a/tools/qmldebugger/standalone/expressionquerywidget.h b/tools/qmldebugger/standalone/expressionquerywidget.h
new file mode 100644
index 0000000..8c224f8
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 EXPRESSIONQUERYWIDGET_H
+#define EXPRESSIONQUERYWIDGET_H
+
+#include <QWidget>
+
+#include <private/qmldebug_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGroupBox;
+class QTextEdit;
+class QLineEdit;
+class QPushButton;
+
+class ExpressionQueryWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Mode {
+ SeparateEntryMode,
+ ShellMode
+ };
+
+ ExpressionQueryWidget(Mode mode = SeparateEntryMode, QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+ void clear();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event);
+
+public slots:
+ void setCurrentObject(const QmlDebugObjectReference &obj);
+
+private slots:
+ void executeExpression();
+ void showResult();
+
+private:
+ void appendPrompt();
+ void checkCurrentContext();
+ void showCurrentContext();
+ void updateTitle();
+
+ Mode m_mode;
+
+ QmlEngineDebug *m_client;
+ QmlDebugExpressionQuery *m_query;
+ QTextEdit *m_textEdit;
+ QLineEdit *m_lineEdit;
+ QPushButton *m_button;
+ QString m_prompt;
+ QString m_expr;
+ QString m_lastExpr;
+
+ QString m_title;
+
+ QmlDebugObjectReference m_currObject;
+ QmlDebugObjectReference m_objectAtLastFocus;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/tools/qmldebugger/standalone/main.cpp b/tools/qmldebugger/standalone/main.cpp
new file mode 100644
index 0000000..715837e
--- /dev/null
+++ b/tools/qmldebugger/standalone/main.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtGui/qapplication.h>
+
+#include "qmldebugger.h"
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+ app.setApplicationName("QtQmlDebugger");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("nokia.com");
+
+ QStringList args = app.arguments();
+
+ QmlDebugger win;
+ if (args.contains("--engine"))
+ win.showEngineTab();
+
+ for (int i=0; i<args.count(); i++) {
+ if (!args[i].contains(':'))
+ continue;
+ QStringList hostAndPort = args[i].split(':');
+ bool ok = false;
+ quint16 port = hostAndPort.value(1).toInt(&ok);
+ if (ok) {
+ qWarning() << "qmldebugger connecting to"
+ << hostAndPort[0] << port << "...";
+ win.setHost(hostAndPort[0]);
+ win.setPort(port);
+ win.connectToHost();
+ break;
+ }
+ }
+
+ win.show();
+
+ return app.exec();
+}
diff --git a/tools/qmldebugger/standalone/objectpropertiesview.cpp b/tools/qmldebugger/standalone/objectpropertiesview.cpp
new file mode 100644
index 0000000..3a8d8c8
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtCore/qdebug.h>
+
+#include <QtGui/qtreewidget.h>
+#include <QtGui/qlayout.h>
+#include <QtGui/qheaderview.h>
+
+#include <private/qmldebugservice_p.h>
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "objectpropertiesview.h"
+
+QT_BEGIN_NAMESPACE
+
+class PropertiesViewItem : public QObject, public QTreeWidgetItem
+{
+ Q_OBJECT
+public:
+ enum Type {
+ BindingType,
+ OtherType
+ };
+
+ PropertiesViewItem(QTreeWidget *widget, Type type = OtherType);
+ PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType);
+
+ QmlDebugPropertyReference property;
+ Type type;
+};
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type)
+ : QTreeWidgetItem(widget), type(type)
+{
+}
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type)
+ : QTreeWidgetItem(parent), type(type)
+{
+}
+
+ObjectPropertiesView::ObjectPropertiesView(QmlEngineDebug *client, QWidget *parent)
+ : QWidget(parent),
+ m_client(client),
+ m_query(0),
+ m_watch(0)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+
+ m_tree = new QTreeWidget(this);
+ m_tree->setAlternatingRowColors(true);
+ m_tree->setExpandsOnDoubleClick(false);
+ m_tree->setHeaderLabels(QStringList()
+ << tr("Name") << tr("Value") << tr("Type"));
+ QObject::connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ this, SLOT(itemActivated(QTreeWidgetItem *)));
+
+ m_tree->setColumnCount(3);
+ m_tree->header()->setDefaultSectionSize(150);
+
+ layout->addWidget(m_tree);
+}
+
+void ObjectPropertiesView::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ObjectPropertiesView::clear()
+{
+ setObject(QmlDebugObjectReference());
+}
+
+void ObjectPropertiesView::reload(const QmlDebugObjectReference &obj)
+{
+ if (!m_client)
+ return;
+ if (m_query)
+ delete m_query;
+
+ m_query = m_client->queryObjectRecursive(obj, this);
+ if (!m_query->isWaiting())
+ queryFinished();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(queryFinished()));
+}
+
+void ObjectPropertiesView::queryFinished()
+{
+ if (!m_client || !m_query)
+ return;
+
+ QmlDebugObjectReference obj = m_query->object();
+
+ QmlDebugWatch *watch = m_client->addWatch(obj, this);
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ if (m_watch) {
+ m_client->removeWatch(m_watch);
+ delete m_watch;
+ }
+ m_watch = watch;
+ QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)),
+ this, SLOT(valueChanged(QByteArray,QVariant)));
+ }
+
+ delete m_query;
+ m_query = 0;
+
+ setObject(obj);
+}
+
+void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray)
+{
+ if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
+ PropertiesViewItem *bindingItem = static_cast<PropertiesViewItem*>(item->takeChild(item->childCount() - 1));
+ if (bindingItem && bindingItem->type != PropertiesViewItem::BindingType) {
+ delete bindingItem;
+ bindingItem = 0;
+ }
+
+ qDeleteAll(item->takeChildren());
+
+ QVariantList variants = value.toList();
+ item->setText(1, tr("<%1 items>", "%1 = number of items").arg(variants.count()));
+ item->setText(2, QString::fromUtf8(value.typeName()));
+
+ PropertiesViewItem *child;
+ for (int i=0; i<variants.count(); i++) {
+ child = new PropertiesViewItem(item);
+ setPropertyValue(child, variants[i], makeGray);
+ }
+
+ if (bindingItem)
+ item->addChild(bindingItem);
+
+ item->setExpanded(false);
+ } else {
+ item->setText(1, (value.isNull() ? QLatin1String("<no value>") : value.toString()));
+ item->setExpanded(true);
+ }
+
+ if (makeGray) {
+ for (int i=0; i<m_tree->columnCount(); i++)
+ item->setForeground(i, Qt::gray);
+ }
+}
+
+void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object)
+{
+ m_object = object;
+ m_tree->clear();
+
+ QList<QmlDebugPropertyReference> properties = object.properties();
+ for (int i=0; i<properties.count(); i++) {
+ const QmlDebugPropertyReference &p = properties[i];
+
+ PropertiesViewItem *item = new PropertiesViewItem(m_tree);
+ item->property = p;
+
+ item->setText(0, p.name());
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ setPropertyValue(item, p.value(), !p.hasNotifySignal());
+ item->setText(2, p.valueTypeName());
+
+ // binding is set after property value to ensure it is added to the end of the
+ // list, if the value is a list
+ if (!p.binding().isEmpty()) {
+ PropertiesViewItem *binding = new PropertiesViewItem(item, PropertiesViewItem::BindingType);
+ binding->setText(1, p.binding());
+ binding->setForeground(1, Qt::darkGreen);
+ }
+ }
+}
+
+void ObjectPropertiesView::watchCreated(QmlDebugWatch *watch)
+{
+ if (watch->objectDebugId() == m_object.debugId()
+ && qobject_cast<QmlDebugPropertyWatch*>(watch)) {
+ connect(watch, SIGNAL(stateChanged(QmlDebugWatch::State)), SLOT(watchStateChanged()));
+ setWatched(qobject_cast<QmlDebugPropertyWatch*>(watch)->name(), true);
+ }
+}
+
+void ObjectPropertiesView::watchStateChanged()
+{
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+
+ if (watch->objectDebugId() == m_object.debugId()
+ && qobject_cast<QmlDebugPropertyWatch*>(watch)
+ && watch->state() == QmlDebugWatch::Inactive) {
+ setWatched(qobject_cast<QmlDebugPropertyWatch*>(watch)->name(), false);
+ }
+}
+
+void ObjectPropertiesView::setWatched(const QString &property, bool watched)
+{
+ for (int i=0; i<m_tree->topLevelItemCount(); i++) {
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i));
+ if (item->property.name() == property && item->property.hasNotifySignal()) {
+ QFont font = m_tree->font();
+ font.setBold(watched);
+ item->setFont(0, font);
+ }
+ }
+}
+
+void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant &value)
+{
+ for (int i=0; i<m_tree->topLevelItemCount(); i++) {
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i));
+ if (item->property.name() == name) {
+ setPropertyValue(item, value, !item->property.hasNotifySignal());
+ return;
+ }
+ }
+}
+
+void ObjectPropertiesView::itemActivated(QTreeWidgetItem *i)
+{
+ PropertiesViewItem *item = static_cast<PropertiesViewItem *>(i);
+ if (!item->property.name().isEmpty())
+ emit activated(m_object, item->property);
+}
+
+QT_END_NAMESPACE
+
+#include "objectpropertiesview.moc"
diff --git a/tools/qmldebugger/standalone/objectpropertiesview.h b/tools/qmldebugger/standalone/objectpropertiesview.h
new file mode 100644
index 0000000..43413dc
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 PROPERTIESTABLEMODEL_H
+#define PROPERTIESTABLEMODEL_H
+
+#include <private/qmldebug_p.h>
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QmlDebugConnection;
+class PropertiesViewItem;
+
+class ObjectPropertiesView : public QWidget
+{
+ Q_OBJECT
+public:
+ ObjectPropertiesView(QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+ void clear();
+
+signals:
+ void activated(const QmlDebugObjectReference &, const QmlDebugPropertyReference &);
+
+public slots:
+ void reload(const QmlDebugObjectReference &);
+ void watchCreated(QmlDebugWatch *);
+
+private slots:
+ void queryFinished();
+ void watchStateChanged();
+ void valueChanged(const QByteArray &name, const QVariant &value);
+ void itemActivated(QTreeWidgetItem *i);
+
+private:
+ void setObject(const QmlDebugObjectReference &object);
+ void setWatched(const QString &property, bool watched);
+ void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray);
+
+ QmlEngineDebug *m_client;
+ QmlDebugObjectQuery *m_query;
+ QmlDebugWatch *m_watch;
+
+ QTreeWidget *m_tree;
+ QmlDebugObjectReference m_object;
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/qmldebugger/standalone/objecttree.cpp b/tools/qmldebugger/standalone/objecttree.cpp
new file mode 100644
index 0000000..cf467f2
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtGui/qevent.h>
+#include <QtGui/qmenu.h>
+#include <QtGui/qaction.h>
+
+#include <QInputDialog>
+
+#include <private/qmldebugservice_p.h>
+#include <private/qmldebug_p.h>
+#include <private/qmldebugclient_p.h>
+
+#include "objecttree.h"
+
+Q_DECLARE_METATYPE(QmlDebugObjectReference)
+
+ObjectTree::ObjectTree(QmlEngineDebug *client, QWidget *parent)
+ : QTreeWidget(parent),
+ m_client(client),
+ m_query(0)
+{
+ setHeaderHidden(true);
+ setMinimumWidth(250);
+ setExpandsOnDoubleClick(false);
+
+ connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ SLOT(currentItemChanged(QTreeWidgetItem *)));
+ connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ SLOT(activated(QTreeWidgetItem *)));
+}
+
+void ObjectTree::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ObjectTree::reload(int objectDebugId)
+{
+ if (!m_client)
+ return;
+
+ if (m_query) {
+ delete m_query;
+ m_query = 0;
+ }
+
+ m_query = m_client->queryObjectRecursive(QmlDebugObjectReference(objectDebugId), this);
+ if (!m_query->isWaiting())
+ objectFetched();
+ else
+ QObject::connect(m_query, SIGNAL(stateChanged(QmlDebugQuery::State)),
+ this, SLOT(objectFetched()));
+}
+
+void ObjectTree::setCurrentObject(int debugId)
+{
+ QTreeWidgetItem *item = findItemByObjectId(debugId);
+ if (item) {
+ setCurrentItem(item);
+ scrollToItem(item);
+ item->setExpanded(true);
+ }
+}
+
+void ObjectTree::objectFetched()
+{
+ dump(m_query->object(), 0);
+ buildTree(m_query->object(), 0);
+ setCurrentItem(topLevelItem(0));
+
+ delete m_query;
+ m_query = 0;
+}
+
+void ObjectTree::currentItemChanged(QTreeWidgetItem *item)
+{
+ if (!item)
+ return;
+
+ QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (obj.debugId() >= 0)
+ emit currentObjectChanged(obj);
+}
+
+void ObjectTree::activated(QTreeWidgetItem *item)
+{
+ if (!item)
+ return;
+
+ QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (obj.debugId() >= 0)
+ emit activated(obj);
+}
+
+void ObjectTree::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent)
+{
+ if (!parent)
+ clear();
+
+ QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this);
+ item->setText(0, obj.className());
+ item->setData(0, Qt::UserRole, qVariantFromValue(obj));
+
+ if (parent && obj.contextDebugId() >= 0
+ && obj.contextDebugId() != parent->data(0, Qt::UserRole
+ ).value<QmlDebugObjectReference>().contextDebugId()) {
+ QmlDebugFileReference source = obj.source();
+ if (!source.url().isEmpty()) {
+ QString toolTipString = QLatin1String("URL: ") + source.url().toString();
+ item->setToolTip(0, toolTipString);
+ }
+ item->setForeground(0, QColor("orange"));
+ } else {
+ item->setExpanded(true);
+ }
+
+ if (obj.contextDebugId() < 0)
+ item->setForeground(0, Qt::lightGray);
+
+ for (int ii = 0; ii < obj.children().count(); ++ii)
+ buildTree(obj.children().at(ii), item);
+}
+
+void ObjectTree::dump(const QmlDebugContextReference &ctxt, int ind)
+{
+ QByteArray indent(ind * 4, ' ');
+ qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
+ << qPrintable(ctxt.name());
+
+ for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
+ dump(ctxt.contexts().at(ii), ind + 1);
+
+ for (int ii = 0; ii < ctxt.objects().count(); ++ii)
+ dump(ctxt.objects().at(ii), ind);
+}
+
+void ObjectTree::dump(const QmlDebugObjectReference &obj, int ind)
+{
+ QByteArray indent(ind * 4, ' ');
+ qWarning().nospace() << indent.constData() << qPrintable(obj.className())
+ << " " << qPrintable(obj.name()) << " "
+ << obj.debugId();
+
+ for (int ii = 0; ii < obj.children().count(); ++ii)
+ dump(obj.children().at(ii), ind + 1);
+}
+
+QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
+{
+ for (int i=0; i<topLevelItemCount(); i++) {
+ QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
+ if (item)
+ return item;
+ }
+
+ return 0;
+}
+
+QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
+{
+ if (item->data(0, Qt::UserRole).value<QmlDebugObjectReference>().debugId() == debugId)
+ return item;
+
+ QTreeWidgetItem *child;
+ for (int i=0; i<item->childCount(); i++) {
+ child = findItem(item->child(i), debugId);
+ if (child)
+ return child;
+ }
+
+ return 0;
+}
+
+void ObjectTree::mousePressEvent(QMouseEvent *me)
+{
+ QTreeWidget::mousePressEvent(me);
+ if (!currentItem())
+ return;
+ if(me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
+ QAction action(tr("Add watch..."), 0);
+ QList<QAction *> actions;
+ actions << &action;
+ QmlDebugObjectReference obj =
+ currentItem()->data(0, Qt::UserRole).value<QmlDebugObjectReference>();
+ if (QMenu::exec(actions, me->globalPos())) {
+ bool ok = false;
+ QString watch = QInputDialog::getText(this, tr("Watch expression"),
+ tr("Expression:"), QLineEdit::Normal, QString(), &ok);
+ if (ok && !watch.isEmpty())
+ emit expressionWatchRequested(obj, watch);
+ }
+ }
+}
diff --git a/tools/qmldebugger/standalone/objecttree.h b/tools/qmldebugger/standalone/objecttree.h
new file mode 100644
index 0000000..c8d625c
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 OBJECTTREE_H
+#define OBJECTTREE_H
+
+#include <QtGui/qtreewidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeWidgetItem;
+
+class QmlEngineDebug;
+class QmlDebugObjectReference;
+class QmlDebugObjectQuery;
+class QmlDebugContextReference;
+class QmlDebugConnection;
+
+
+class ObjectTree : public QTreeWidget
+{
+ Q_OBJECT
+public:
+ ObjectTree(QmlEngineDebug *client = 0, QWidget *parent = 0);
+
+ void setEngineDebug(QmlEngineDebug *client);
+
+signals:
+ void currentObjectChanged(const QmlDebugObjectReference &);
+ void activated(const QmlDebugObjectReference &);
+ void expressionWatchRequested(const QmlDebugObjectReference &, const QString &);
+
+public slots:
+ void reload(int objectDebugId); // set the root object
+ void setCurrentObject(int debugId); // select an object in the tree
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *);
+
+private slots:
+ void objectFetched();
+ void currentItemChanged(QTreeWidgetItem *);
+ void activated(QTreeWidgetItem *);
+
+private:
+ QTreeWidgetItem *findItemByObjectId(int debugId) const;
+ QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const;
+ void dump(const QmlDebugContextReference &, int);
+ void dump(const QmlDebugObjectReference &, int);
+ void buildTree(const QmlDebugObjectReference &, QTreeWidgetItem *parent);
+
+ QmlEngineDebug *m_client;
+ QmlDebugObjectQuery *m_query;
+};
+
+QT_END_NAMESPACE
+
+
+#endif
diff --git a/tools/qmldebugger/standalone/qmldebugger.cpp b/tools/qmldebugger/standalone/qmldebugger.cpp
new file mode 100644
index 0000000..4d86377
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+
+#include <QtGui/qlayout.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qtabwidget.h>
+#include <QtGui/qspinbox.h>
+#include <QtGui/qlabel.h>
+
+#include "canvasframerate.h"
+#include "engine.h"
+#include "qmldebugger.h"
+
+QmlDebugger::QmlDebugger(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);
+ connectLayout->addWidget(m_host);
+ m_port = new QSpinBox(this);
+ m_port->setMinimum(1024);
+ m_port->setMaximum(20000);
+ 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);
+
+ m_tabs = new QTabWidget(this);
+ layout->addWidget(m_tabs);
+
+ CanvasFrameRate *cfr = new CanvasFrameRate(this);
+ cfr->reset(&client);
+ cfr->setSizeHint(QSize(800, 600));
+ m_tabs->addTab(cfr, tr("Frame Rate"));
+
+ m_enginePane = new EnginePane(&client, this);
+ m_tabs->addTab(m_enginePane, tr("QML Engine"));
+
+ QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(connectionStateChanged()));
+ connectionStateChanged();
+
+ QObject::connect(&client, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(connectionError(QAbstractSocket::SocketError)));
+
+ QSettings settings;
+ m_host->setText(settings.value("Host", "127.0.0.1").toString());
+ m_port->setValue(settings.value("Port", 3768).toInt());
+
+ connectToHost();
+}
+
+void QmlDebugger::setHost(const QString &host)
+{
+ m_host->setText(host);
+}
+
+void QmlDebugger::setPort(quint16 port)
+{
+ m_port->setValue(port);
+}
+
+void QmlDebugger::showEngineTab()
+{
+ m_tabs->setCurrentWidget(m_enginePane);
+}
+
+void QmlDebugger::closeEvent(QCloseEvent *event)
+{
+ QSettings settings;
+ settings.setValue("Host", m_host->text());
+ settings.setValue("Port", m_port->value());
+
+ QWidget::closeEvent(event);
+}
+
+void QmlDebugger::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);
+
+ QTimer::singleShot(0, m_enginePane, SLOT(refreshEngines()));
+ break;
+ case QAbstractSocket::ClosingState:
+ m_connectionState->setText(tr("Closing"));
+ m_connectButton->setEnabled(false);
+ m_disconnectButton->setEnabled(false);
+ break;
+ }
+}
+
+void QmlDebugger::connectionError(QAbstractSocket::SocketError socketError)
+{
+ qWarning() << "qmldebugger cannot connect:" << socketError
+ << client.errorString();
+}
+
+void QmlDebugger::connectToHost()
+{
+ client.connectToHost(m_host->text(), m_port->value());
+}
+
+void QmlDebugger::disconnectFromHost()
+{
+ client.disconnectFromHost();
+}
diff --git a/tools/qmldebugger/standalone/qmldebugger.h b/tools/qmldebugger/standalone/qmldebugger.h
new file mode 100644
index 0000000..da95ef9
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.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 Qt QML Debugger 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 QMLDEBUGGER_H
+#define QMLDEBUGGER_H
+
+#include <private/qmldebugclient_p.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <QtGui/qwidget.h>
+
+class QLabel;
+class QLineEdit;
+class QSpinBox;
+class QPushButton;
+class QTabWidget;
+
+class EnginePane;
+
+class QmlDebugger : public QWidget
+{
+ Q_OBJECT
+public:
+ QmlDebugger(QWidget * = 0);
+
+ void setHost(const QString &host);
+ void setPort(quint16 port);
+ void showEngineTab();
+
+public slots:
+ void connectToHost();
+ void disconnectFromHost();
+
+protected:
+ void closeEvent(QCloseEvent *);
+
+private slots:
+ void connectionStateChanged();
+ void connectionError(QAbstractSocket::SocketError socketError);
+
+private:
+ QmlDebugConnection client;
+
+ QLabel *m_connectionState;
+ QLineEdit *m_host;
+ QSpinBox *m_port;
+ QPushButton *m_connectButton;
+ QPushButton *m_disconnectButton;
+
+ EnginePane *m_enginePane;
+ QTabWidget *m_tabs;
+};
+
+#endif
diff --git a/tools/qmldebugger/standalone/qmldebugger.pri b/tools/qmldebugger/standalone/qmldebugger.pri
new file mode 100644
index 0000000..ede7d31
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.pri
@@ -0,0 +1,18 @@
+QT += network declarative
+contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl
+
+INCLUDEPATH += ../../../src/declarative/debugger
+
+# Input
+HEADERS += $$PWD/canvasframerate.h \
+ $$PWD/watchtable.h \
+ $$PWD/objecttree.h \
+ $$PWD/objectpropertiesview.h \
+ $$PWD/expressionquerywidget.h
+
+SOURCES += $$PWD/canvasframerate.cpp \
+ $$PWD/watchtable.cpp \
+ $$PWD/objecttree.cpp \
+ $$PWD/objectpropertiesview.cpp \
+ $$PWD/expressionquerywidget.cpp
+
diff --git a/tools/qmldebugger/standalone/qmldebugger.qrc b/tools/qmldebugger/standalone/qmldebugger.qrc
new file mode 100644
index 0000000..cb53ad5
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file>engines.qml</file>
+ <file>engine.png</file>
+ <file>refresh.png</file>
+ </qresource>
+</RCC>
diff --git a/tools/qmldebugger/standalone/refresh.png b/tools/qmldebugger/standalone/refresh.png
new file mode 100644
index 0000000..8befc80
--- /dev/null
+++ b/tools/qmldebugger/standalone/refresh.png
Binary files differ
diff --git a/tools/qmldebugger/standalone/standalone.pro b/tools/qmldebugger/standalone/standalone.pro
new file mode 100644
index 0000000..72d051f
--- /dev/null
+++ b/tools/qmldebugger/standalone/standalone.pro
@@ -0,0 +1,19 @@
+DESTDIR = ../../../bin
+TARGET = qmldebugger
+
+include(qmldebugger.pri)
+
+HEADERS += $$PWD/qmldebugger.h \
+ $$PWD/engine.h
+
+SOURCES += $$PWD/qmldebugger.cpp \
+ $$PWD/engine.cpp \
+ $$PWD/main.cpp
+
+RESOURCES += $$PWD/qmldebugger.qrc
+OTHER_FILES += $$PWD/engines.qml
+
+target.path=$$[QT_INSTALL_BINS]
+INSTALLS += target
+
+CONFIG += console
diff --git a/tools/qmldebugger/standalone/watchtable.cpp b/tools/qmldebugger/standalone/watchtable.cpp
new file mode 100644
index 0000000..0e73de5
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.cpp
@@ -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 Qt QML Debugger 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 "watchtable.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qaction.h>
+#include <QtGui/qmenu.h>
+
+#include <private/qmldebug_p.h>
+#include <QtDeclarative/qmlmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+
+WatchTableModel::WatchTableModel(QmlEngineDebug *client, QObject *parent)
+ : QAbstractTableModel(parent),
+ m_client(client)
+{
+}
+
+WatchTableModel::~WatchTableModel()
+{
+ for (int i=0; i<m_columns.count(); i++)
+ delete m_columns[i].watch;
+}
+
+void WatchTableModel::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void WatchTableModel::addWatch(QmlDebugWatch *watch, const QString &title)
+{
+ QString property;
+ if (qobject_cast<QmlDebugPropertyWatch *>(watch))
+ property = qobject_cast<QmlDebugPropertyWatch *>(watch)->name();
+
+ connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)),
+ SLOT(watchedValueChanged(QByteArray,QVariant)));
+
+ connect(watch, SIGNAL(stateChanged(QmlDebugWatch::State)), SLOT(watchStateChanged()));
+
+ int col = columnCount(QModelIndex());
+ beginInsertColumns(QModelIndex(), col, col);
+
+ WatchedEntity e;
+ e.title = title;
+ e.hasFirstValue = false;
+ e.property = property;
+ e.watch = watch;
+ m_columns.append(e);
+
+ endInsertColumns();
+}
+
+void WatchTableModel::removeWatch(QmlDebugWatch *watch)
+{
+ int column = columnForWatch(watch);
+ if (column == -1)
+ return;
+
+ WatchedEntity entity = m_columns.takeAt(column);
+
+ for (QList<Value>::Iterator iter = m_values.begin(); iter != m_values.end();) {
+ if (iter->column == column) {
+ iter = m_values.erase(iter);
+ } else {
+ if(iter->column > column)
+ --iter->column;
+ ++iter;
+ }
+ }
+
+ reset();
+}
+
+void WatchTableModel::updateWatch(QmlDebugWatch *watch, const QVariant &value)
+{
+ int column = columnForWatch(watch);
+ if (column == -1)
+ return;
+
+ addValue(column, value);
+
+ if (!m_columns[column].hasFirstValue) {
+ m_columns[column].hasFirstValue = true;
+ m_values[m_values.count() - 1].first = true;
+ }
+}
+
+QmlDebugWatch *WatchTableModel::findWatch(int column) const
+{
+ if (column < m_columns.count())
+ return m_columns.at(column).watch;
+ return 0;
+}
+
+QmlDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QString &property) const
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_columns[i].watch->objectDebugId() == objectDebugId
+ && m_columns[i].property == property) {
+ return m_columns[i].watch;
+ }
+ }
+ return 0;
+}
+
+int WatchTableModel::rowCount(const QModelIndex &) const
+{
+ return m_values.count();
+}
+
+int WatchTableModel::columnCount(const QModelIndex &) const
+{
+ return m_columns.count();
+}
+
+QVariant WatchTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ if (section < m_columns.count() && role == Qt::DisplayRole)
+ return m_columns.at(section).title;
+ } else {
+ if (role == Qt::DisplayRole)
+ return section + 1;
+ }
+ return QVariant();
+}
+
+QVariant WatchTableModel::data(const QModelIndex &idx, int role) const
+{
+ if (m_values.at(idx.row()).column == idx.column()) {
+ if (role == Qt::DisplayRole) {
+ const QVariant &value = m_values.at(idx.row()).variant;
+ QString str = value.toString();
+
+ if (str.isEmpty() && QmlMetaType::isObject(value.userType())) {
+ QObject *o = QmlMetaType::toQObject(value);
+ if(o) {
+ QString objectName = o->objectName();
+ if(objectName.isEmpty())
+ objectName = QLatin1String("<unnamed>");
+ str = QLatin1String(o->metaObject()->className()) +
+ QLatin1String(": ") + objectName;
+ }
+ }
+
+ if(str.isEmpty()) {
+ QDebug d(&str);
+ d << value;
+ }
+ return QVariant(str);
+ } else if(role == Qt::BackgroundRole) {
+ if(m_values.at(idx.row()).first)
+ return QColor(Qt::green);
+ else
+ return QVariant();
+ } else {
+ return QVariant();
+ }
+ } else {
+ return QVariant();
+ }
+}
+
+void WatchTableModel::watchStateChanged()
+{
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+
+ if (watch && watch->state() == QmlDebugWatch::Inactive) {
+ removeWatch(watch);
+ watch->deleteLater();
+ }
+}
+
+int WatchTableModel::columnForWatch(QmlDebugWatch *watch) const
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_columns.at(i).watch == watch)
+ return i;
+ }
+ return -1;
+}
+
+void WatchTableModel::addValue(int column, const QVariant &value)
+{
+ int row = columnCount(QModelIndex());
+ beginInsertRows(QModelIndex(), row, row);
+
+ Value v;
+ v.column = column;
+ v.variant = value;
+ v.first = false;
+ m_values.append(v);
+
+ endInsertRows();
+}
+
+void WatchTableModel::togglePropertyWatch(const QmlDebugObjectReference &object, const QmlDebugPropertyReference &property)
+{
+ if (!m_client || !property.hasNotifySignal())
+ return;
+
+ QmlDebugWatch *watch = findWatch(object.debugId(), property.name());
+ if (watch) {
+ // watch will be deleted in watchStateChanged()
+ m_client->removeWatch(watch);
+ return;
+ }
+
+ watch = m_client->addWatch(property, this);
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ QString desc = property.name()
+ + QLatin1String(" on\n")
+ + object.className()
+ + QLatin1String(":\n")
+ + (object.name().isEmpty() ? QLatin1String("<unnamed object>") : object.name());
+ addWatch(watch, desc);
+ emit watchCreated(watch);
+ }
+}
+
+void WatchTableModel::watchedValueChanged(const QByteArray &propertyName, const QVariant &value)
+{
+ Q_UNUSED(propertyName);
+ QmlDebugWatch *watch = qobject_cast<QmlDebugWatch*>(sender());
+ if (watch)
+ updateWatch(watch, value);
+}
+
+void WatchTableModel::expressionWatchRequested(const QmlDebugObjectReference &obj, const QString &expr)
+{
+ if (!m_client)
+ return;
+
+ QmlDebugWatch *watch = m_client->addWatch(obj, expr, this);
+
+ if (watch->state() == QmlDebugWatch::Dead) {
+ delete watch;
+ watch = 0;
+ } else {
+ addWatch(watch, expr);
+ emit watchCreated(watch);
+ }
+}
+
+void WatchTableModel::removeWatchAt(int column)
+{
+ if (!m_client)
+ return;
+
+ QmlDebugWatch *watch = findWatch(column);
+ if (watch) {
+ m_client->removeWatch(watch);
+ delete watch;
+ watch = 0;
+ }
+}
+
+void WatchTableModel::removeAllWatches()
+{
+ for (int i=0; i<m_columns.count(); i++) {
+ if (m_client)
+ m_client->removeWatch(m_columns[i].watch);
+ else
+ delete m_columns[i].watch;
+ }
+ m_columns.clear();
+ m_values.clear();
+ reset();
+}
+
+//----------------------------------------------
+
+WatchTableHeaderView::WatchTableHeaderView(WatchTableModel *model, QWidget *parent)
+ : QHeaderView(Qt::Horizontal, parent),
+ m_model(model)
+{
+ setClickable(true);
+}
+
+void WatchTableHeaderView::mousePressEvent(QMouseEvent *me)
+{
+ QHeaderView::mousePressEvent(me);
+
+ if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
+ int col = logicalIndexAt(me->pos());
+ if (col >= 0) {
+ QAction action(tr("Stop watching"), 0);
+ QList<QAction *> actions;
+ actions << &action;
+ if (QMenu::exec(actions, me->globalPos()))
+ m_model->removeWatchAt(col);
+ }
+ }
+}
+
+
+//----------------------------------------------
+
+WatchTableView::WatchTableView(WatchTableModel *model, QWidget *parent)
+ : QTableView(parent),
+ m_model(model)
+{
+ setAlternatingRowColors(true);
+ connect(model, SIGNAL(watchCreated(QmlDebugWatch*)), SLOT(watchCreated(QmlDebugWatch*)));
+ connect(this, SIGNAL(activated(QModelIndex)), SLOT(indexActivated(QModelIndex)));
+}
+
+void WatchTableView::indexActivated(const QModelIndex &index)
+{
+ QmlDebugWatch *watch = m_model->findWatch(index.column());
+ if (watch)
+ emit objectActivated(watch->objectDebugId());
+}
+
+void WatchTableView::watchCreated(QmlDebugWatch *watch)
+{
+ int column = m_model->columnForWatch(watch);
+ resizeColumnToContents(column);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qmldebugger/standalone/watchtable.h b/tools/qmldebugger/standalone/watchtable.h
new file mode 100644
index 0000000..fd12d3d
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 Qt QML Debugger 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 WATCHTABLEMODEL_H
+#define WATCHTABLEMODEL_H
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qlist.h>
+
+#include <QWidget>
+#include <QHeaderView>
+#include <QAbstractTableModel>
+#include <QTableView>
+
+QT_BEGIN_NAMESPACE
+
+class QmlDebugWatch;
+class QmlEngineDebug;
+class QmlDebugConnection;
+class QmlDebugPropertyReference;
+class QmlDebugObjectReference;
+
+class WatchTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ WatchTableModel(QmlEngineDebug *client = 0, QObject *parent = 0);
+ ~WatchTableModel();
+
+ void setEngineDebug(QmlEngineDebug *client);
+
+ QmlDebugWatch *findWatch(int column) const;
+ int columnForWatch(QmlDebugWatch *watch) const;
+
+ void removeWatchAt(int column);
+ void removeAllWatches();
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+signals:
+ void watchCreated(QmlDebugWatch *watch);
+
+public slots:
+ void togglePropertyWatch(const QmlDebugObjectReference &obj, const QmlDebugPropertyReference &prop);
+ void expressionWatchRequested(const QmlDebugObjectReference &, const QString &);
+
+private slots:
+ void watchStateChanged();
+ void watchedValueChanged(const QByteArray &propertyName, const QVariant &value);
+
+private:
+ void addWatch(QmlDebugWatch *watch, const QString &title);
+ void removeWatch(QmlDebugWatch *watch);
+ void updateWatch(QmlDebugWatch *watch, const QVariant &value);
+
+ QmlDebugWatch *findWatch(int objectDebugId, const QString &property) const;
+
+ void addValue(int column, const QVariant &value);
+
+ struct WatchedEntity
+ {
+ QString title;
+ bool hasFirstValue;
+ QString property;
+ QPointer<QmlDebugWatch> watch;
+ };
+
+ struct Value {
+ int column;
+ QVariant variant;
+ bool first;
+ };
+
+ QmlEngineDebug *m_client;
+ QList<WatchedEntity> m_columns;
+ QList<Value> m_values;
+};
+
+
+class WatchTableHeaderView : public QHeaderView
+{
+ Q_OBJECT
+public:
+ WatchTableHeaderView(WatchTableModel *model, QWidget *parent = 0);
+
+protected:
+ void mousePressEvent(QMouseEvent *me);
+
+private:
+ WatchTableModel *m_model;
+};
+
+
+class WatchTableView : public QTableView
+{
+ Q_OBJECT
+public:
+ WatchTableView(WatchTableModel *model, QWidget *parent = 0);
+
+signals:
+ void objectActivated(int objectDebugId);
+
+private slots:
+ void indexActivated(const QModelIndex &index);
+ void watchCreated(QmlDebugWatch *watch);
+
+private:
+ WatchTableModel *m_model;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // WATCHTABLEMODEL_H