summaryrefslogtreecommitdiffstats
path: root/tools/qmldebugger/standalone
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qmldebugger/standalone')
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.cpp368
-rw-r--r--tools/qmldebugger/standalone/canvasframerate.h46
-rw-r--r--tools/qmldebugger/standalone/engine.cpp179
-rw-r--r--tools/qmldebugger/standalone/engine.h61
-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.cpp218
-rw-r--r--tools/qmldebugger/standalone/expressionquerywidget.h65
-rw-r--r--tools/qmldebugger/standalone/main.cpp34
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.cpp197
-rw-r--r--tools/qmldebugger/standalone/objectpropertiesview.h51
-rw-r--r--tools/qmldebugger/standalone/objecttree.cpp180
-rw-r--r--tools/qmldebugger/standalone/objecttree.h54
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.cpp131
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.h47
-rw-r--r--tools/qmldebugger/standalone/qmldebugger.pri16
-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.pro18
-rw-r--r--tools/qmldebugger/standalone/watchtable.cpp325
-rw-r--r--tools/qmldebugger/standalone/watchtable.h114
21 files changed, 2157 insertions, 0 deletions
diff --git a/tools/qmldebugger/standalone/canvasframerate.cpp b/tools/qmldebugger/standalone/canvasframerate.cpp
new file mode 100644
index 0000000..10c3dbf
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.cpp
@@ -0,0 +1,368 @@
+#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>
+#include <QSpinBox>
+#include <QLabel>
+
+QT_BEGIN_NAMESPACE
+
+class QLineGraph : public QWidget
+{
+Q_OBJECT
+public:
+ QLineGraph(QWidget * = 0);
+
+ void setPosition(int);
+
+public slots:
+ void addSample(int, int, int, bool);
+ void setResolutionForHeight(int);
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+
+private slots:
+ void scrollbarChanged(int);
+
+private:
+ void updateScrollbar();
+ void drawSample(QPainter *, int, const QRect &);
+ void drawTime(QPainter *, const QRect &);
+ struct Sample {
+ int sample[3];
+ bool isBreak;
+ };
+ QList<Sample> _samples;
+
+ QScrollBar sb;
+ int position;
+ int samplesPerWidth;
+ int resolutionForHeight;
+ bool ignoreScroll;
+};
+
+QLineGraph::QLineGraph(QWidget *parent)
+: QWidget(parent), sb(Qt::Horizontal, this), position(-1), samplesPerWidth(99), resolutionForHeight(50), ignoreScroll(false)
+{
+ setMinimumHeight(200);
+
+ sb.setMaximum(0);
+ 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;
+
+ if (v == sb.maximum())
+ position = -1;
+ else
+ position = v;
+ update();
+}
+
+void QLineGraph::updateScrollbar()
+{
+ ignoreScroll = true;
+ sb.setMaximum(qMax(0, _samples.count() - samplesPerWidth - 1));
+
+ if(position == -1) {
+ sb.setValue(sb.maximum());
+ } else {
+ sb.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;
+ updateScrollbar();
+ update();
+}
+
+void QLineGraph::setPosition(int p)
+{
+ scrollbarChanged(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)
+{
+ 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))
+ p->drawRect(QRect(lastXEnd, yEnd, scaleX, _samples.at(ii).sample[s] * scaleY));
+
+ lastXEnd = xEnd;
+ }
+ p->restore();
+}
+
+void QLineGraph::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+
+ QRect r(50, 10, width() - 60, height() - 60);
+ p.setBrush(QColor("lightsteelblue"));
+ drawSample(&p, 0, r);
+
+ p.setBrush(QColor("pink"));
+ drawSample(&p, 1, r);
+
+ p.setBrush(Qt::NoBrush);
+ p.drawRect(r);
+
+ 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::setResolutionForHeight(int resolution)
+{
+ resolutionForHeight = resolution;
+ update();
+}
+
+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)
+{
+ 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;
+ bottom->setContentsMargins(5, 0, 5, 0);
+ bottom->setSpacing(10);
+ layout->addLayout(bottom);
+
+ QLabel *label = new QLabel("Resolution", this);
+ bottom->addWidget(label);
+
+ m_spin = new QSpinBox(this);
+ m_spin->setRange(50,200);
+ m_spin->setValue(50);
+ m_spin->setSuffix("ms");
+ bottom->addWidget(m_spin);
+
+ bottom->addStretch(2);
+
+ m_enabledCheckBox = new QCheckBox("Enable", this);
+ bottom->addWidget(m_enabledCheckBox);
+ QObject::connect(m_enabledCheckBox, SIGNAL(stateChanged(int)),
+ this, SLOT(enabledStateChanged(int)));
+
+ QPushButton *pb = new QPushButton(tr("New Tab"), this);
+ QObject::connect(pb, SIGNAL(clicked()), this, SLOT(newTab()));
+ bottom->addWidget(pb);
+}
+
+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);
+ enabledStateChanged(m_enabledCheckBox->checkState());
+ newTab();
+}
+
+void CanvasFrameRate::setSizeHint(const QSize &size)
+{
+ m_sizeHint = size;
+}
+
+QSize CanvasFrameRate::sizeHint() const
+{
+ return m_sizeHint;
+}
+
+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 id = m_tabs->count();
+
+ QLineGraph *graph = new QLineGraph(this);
+ QObject::connect(m_plugin, SIGNAL(sample(int,int,int,bool)),
+ graph, SLOT(addSample(int,int,int,bool)));
+ QObject::connect(m_spin, SIGNAL(valueChanged(int)), graph, SLOT(setResolutionForHeight(int)));
+
+ QString name = QLatin1String("Graph ") + QString::number(id);
+ m_tabs->addTab(graph, name);
+ m_tabs->setCurrentIndex(id);
+}
+
+void CanvasFrameRate::enabledStateChanged(int s)
+{
+ bool checked = s != 0;
+
+ 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..6c1ff9f
--- /dev/null
+++ b/tools/qmldebugger/standalone/canvasframerate.h
@@ -0,0 +1,46 @@
+#ifndef CANVASFRAMERATE_H
+#define CANVASFRAMERATE_H
+
+#include <QtCore/qpointer.h>
+#include <QtGui/qwidget.h>
+
+#include <QtDeclarative/qmldebugclient.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTabWidget;
+class QSpinBox;
+class QCheckBox;
+
+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 newTab();
+ void enabledStateChanged(int);
+ void connectionStateChanged(QAbstractSocket::SocketState state);
+
+private:
+ void handleConnected(QmlDebugConnection *conn);
+
+ QTabWidget *m_tabs;
+ QSpinBox *m_spin;
+ CanvasFrameRatePlugin *m_plugin;
+ QSize m_sizeHint;
+ QCheckBox *m_enabledCheckBox;
+};
+
+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..a1fd009
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.cpp
@@ -0,0 +1,179 @@
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSplitter>
+#include <QTabWidget>
+#include <QFile>
+
+#include <private/qmlenginedebug_p.h>
+#include <QtDeclarative/qmldebugclient.h>
+#include <QtDeclarative/qmlcomponent.h>
+#include <QtDeclarative/qfxitem.h>
+#include <QtDeclarative/qmldebugservice.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(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(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(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..a3ebe46
--- /dev/null
+++ b/tools/qmldebugger/standalone/engine.h
@@ -0,0 +1,61 @@
+#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 <QtDeclarative/qmldebug.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..1e9335b
--- /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..f8f5aef
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.cpp
@@ -0,0 +1,218 @@
+#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(QmlEngineDebug *client, QWidget *parent)
+ : QWidget(parent),
+ m_style(Compact),
+ 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_style == Compact) {
+ 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);
+ }
+}
+
+void ExpressionQueryWidget::setEngineDebug(QmlEngineDebug *client)
+{
+ m_client = client;
+}
+
+void ExpressionQueryWidget::clear()
+{
+ m_textEdit->clear();
+ m_lineEdit->clear();
+}
+
+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_style == Compact) {
+ 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()
+{
+ m_textEdit->moveCursor(QTextCursor::End);
+ m_textEdit->setTextColor(Qt::darkGreen);
+ m_textEdit->append(m_currObject.className()
+ + QLatin1String(": ")
+ + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed>") : m_currObject.name()));
+ appendPrompt();
+}
+
+void ExpressionQueryWidget::executeExpression()
+{
+ if (!m_client)
+ return;
+
+ if (m_style == Compact)
+ 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(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);
+ QString result;
+ if (m_query->result().isNull())
+ result = QLatin1String("<no value>");
+ else
+ result = m_query->result().toString();
+
+ if (m_style == Compact) {
+ 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->append(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..6fab059
--- /dev/null
+++ b/tools/qmldebugger/standalone/expressionquerywidget.h
@@ -0,0 +1,65 @@
+#ifndef EXPRESSIONQUERYWIDGET_H
+#define EXPRESSIONQUERYWIDGET_H
+
+#include <QWidget>
+
+#include <QtDeclarative/qmldebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGroupBox;
+class QTextEdit;
+class QLineEdit;
+class QPushButton;
+
+class ExpressionQueryWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ enum Style {
+ Compact,
+ Shell
+ };
+
+ ExpressionQueryWidget(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();
+
+ Style m_style;
+
+ 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..c9983cd
--- /dev/null
+++ b/tools/qmldebugger/standalone/main.cpp
@@ -0,0 +1,34 @@
+#include <QtGui/qapplication.h>
+
+#include "qmldebugger.h"
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ 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..ae9e8be
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.cpp
@@ -0,0 +1,197 @@
+#include <QtCore/qdebug.h>
+
+#include <QtGui/qtreewidget.h>
+#include <QtGui/qlayout.h>
+
+#include <QtDeclarative/qmldebugservice.h>
+#include <QtDeclarative/qmldebug.h>
+#include <QtDeclarative/qmldebugclient.h>
+
+#include "objectpropertiesview.h"
+
+QT_BEGIN_NAMESPACE
+
+class PropertiesViewItem : public QObject, public QTreeWidgetItem
+{
+ Q_OBJECT
+public:
+ PropertiesViewItem(QTreeWidget *widget);
+ PropertiesViewItem(QTreeWidgetItem *parent);
+
+ QmlDebugPropertyReference property;
+};
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget)
+ : QTreeWidgetItem(widget)
+{
+}
+
+PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent)
+ : QTreeWidgetItem(parent)
+{
+}
+
+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("Property") << tr("Value"));
+ QObject::connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
+ this, SLOT(itemActivated(QTreeWidgetItem *)));
+
+ m_tree->setColumnCount(2);
+
+ 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(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::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);
+ if (!p.hasNotifySignal()) {
+ item->setForeground(0, Qt::gray);
+ item->setForeground(1, Qt::gray);
+ }
+
+ if (!p.binding().isEmpty()) {
+ PropertiesViewItem *binding = new PropertiesViewItem(item);
+ binding->setText(1, p.binding());
+ binding->setForeground(1, Qt::darkGreen);
+ }
+
+ item->setExpanded(true);
+ }
+
+ m_tree->resizeColumnToContents(0);
+}
+
+void ObjectPropertiesView::watchCreated(QmlDebugWatch *watch)
+{
+ if (watch->objectDebugId() == m_object.debugId()
+ && qobject_cast<QmlDebugPropertyWatch*>(watch)) {
+ connect(watch, SIGNAL(stateChanged(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) {
+ if (value.isNull()) {
+ item->setText(1, QLatin1String("<null>")
+ + QLatin1String(" : ")
+ + item->property.valueTypeName());
+ } else {
+ item->setText(1, value.toString());
+ }
+ }
+ }
+}
+
+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..6a1fc03
--- /dev/null
+++ b/tools/qmldebugger/standalone/objectpropertiesview.h
@@ -0,0 +1,51 @@
+#ifndef PROPERTIESTABLEMODEL_H
+#define PROPERTIESTABLEMODEL_H
+
+#include <QtDeclarative/qmldebug.h>
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTreeWidget;
+class QTreeWidgetItem;
+class QmlDebugConnection;
+
+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);
+
+ 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..4059e77
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.cpp
@@ -0,0 +1,180 @@
+#include <QtGui/qevent.h>
+#include <QtGui/qmenu.h>
+#include <QtGui/qaction.h>
+
+#include <QInputDialog>
+
+#include <QtDeclarative/qmldebugservice.h>
+#include <QtDeclarative/qmldebug.h>
+#include <QtDeclarative/qmldebugclient.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);
+
+ connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+ this, SLOT(currentItemChanged(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(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);
+
+ 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) {
+ qWarning("QML Object Tree: bad object id");
+ return;
+ }
+ emit currentObjectChanged(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..95820f3
--- /dev/null
+++ b/tools/qmldebugger/standalone/objecttree.h
@@ -0,0 +1,54 @@
+#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 expressionWatchRequested(const QmlDebugObjectReference &, const QString &);
+
+public slots:
+ void reload(int objectDebugId);
+ void setCurrentObject(int debugId);
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *);
+
+private slots:
+ void objectFetched();
+ void currentItemChanged(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..5455878
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.cpp
@@ -0,0 +1,131 @@
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QTabWidget>
+#include <QSpinBox>
+#include <QLabel>
+
+#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);
+ 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);
+
+ 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)));
+
+
+ m_tabs->setCurrentIndex(1);
+ 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::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..9203e33
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.h
@@ -0,0 +1,47 @@
+#ifndef QMLDEBUGGER_H
+#define QMLDEBUGGER_H
+
+#include <QtDeclarative/qmldebugclient.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();
+
+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..aad5eb1
--- /dev/null
+++ b/tools/qmldebugger/standalone/qmldebugger.pri
@@ -0,0 +1,16 @@
+QT += network declarative
+contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl
+
+# 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..72e3ef5
--- /dev/null
+++ b/tools/qmldebugger/standalone/standalone.pro
@@ -0,0 +1,18 @@
+DESTDIR = ../../bin
+
+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..ee74cfb
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.cpp
@@ -0,0 +1,325 @@
+#include "watchtable.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qaction.h>
+#include <QtGui/qmenu.h>
+
+#include <QtDeclarative/qmldebug.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(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(": ")
+ + (object.name().isEmpty() ? QLatin1String("<unnamed>") : 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);
+ 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..67c2565
--- /dev/null
+++ b/tools/qmldebugger/standalone/watchtable.h
@@ -0,0 +1,114 @@
+#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