Add qmlinspector plugin.

This commit is contained in:
Bea Lam
2009-12-11 14:56:04 +10:00
parent 046dd5d902
commit 1bf3418314
32 changed files with 4054 additions and 0 deletions

View File

@@ -37,6 +37,10 @@ SUBDIRS = plugin_coreplugin \
plugin_mercurial \ plugin_mercurial \
debugger/dumper.pro debugger/dumper.pro
contains(QT_CONFIG, declarative) {
SUBDIRS += plugin_qmlinspector
}
plugin_coreplugin.subdir = coreplugin plugin_coreplugin.subdir = coreplugin
plugin_welcome.subdir = welcome plugin_welcome.subdir = welcome
@@ -180,6 +184,11 @@ plugin_qmlprojectmanager.depends += plugin_projectexplorer
plugin_qmlprojectmanager.depends += plugin_help plugin_qmlprojectmanager.depends += plugin_help
plugin_qmlprojectmanager.depends += plugin_qmleditor plugin_qmlprojectmanager.depends += plugin_qmleditor
plugin_qmlinspector.subdir = qmlinspector
plugin_qmlinspector.depends += plugin_projectexplorer
plugin_qmlinspector.depends += plugin_coreplugin
plugin_qmlinspector.depends += plugin_texteditor
plugin_mercurial.subdir = mercurial plugin_mercurial.subdir = mercurial
plugin_mercurial.depends = plugin_texteditor plugin_mercurial.depends = plugin_texteditor
plugin_mercurial.depends = plugin_vcsbase plugin_mercurial.depends = plugin_vcsbase

View File

@@ -0,0 +1,28 @@
<plugin name="QmlInspector" version="1.3.80" compatVersion="1.3.80">
<vendor>Nokia Corporation</vendor>
<copyright>(C) 2008-2009 Nokia Corporation</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin in
accordance with the Qt Commercial License Agreement provided with the
Software or, alternatively, in accordance with the terms contained in
a written agreement between you and Nokia.
GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser
General Public License version 2.1 as published by the Free Software
Foundation. 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.</license>
<description>Qml support</description>
<url>http://qt.nokia.com</url>
<dependencyList>
<dependency name="QmlProjectManager" version="1.3.80"/>
<dependency name="ProjectExplorer" version="1.3.80"/>
<dependency name="CppTools" version="1.3.80"/>
<dependency name="CppEditor" version="1.3.80"/>
<dependency name="Help" version="1.3.80"/>
</dependencyList>
</plugin>

View File

@@ -0,0 +1,569 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "canvasframerate.h"
#include <private/qmldebugclient_p.h>
#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 <QtGui/qevent.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"

View File

@@ -0,0 +1,80 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef CANVASFRAMERATE_H
#define CANVASFRAMERATE_H
#include <private/qmldebugclient_p.h>
#include <QtCore/qpointer.h>
#include <QtGui/qwidget.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

View File

@@ -0,0 +1,209 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "engine.h"
#include "objectpropertiesview.h"
#include "expressionquerywidget.h"
#include "objecttree.h"
#include "watchtable.h"
#include <private/qmlenginedebug_p.h>
#include <private/qmldebugclient_p.h>
#include <private/qmldebugservice_p.h>
#include <QtDeclarative/qmlcomponent.h>
#include <QtDeclarative/qmlgraphicsitem.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
#include <QTabWidget>
#include <QFile>
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

View File

@@ -0,0 +1,91 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef ENGINE_H
#define ENGINE_H
#include <private/qmldebug_p.h>
#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmlview.h>
#include <QtCore/qpointer.h>
#include <QtGui/qwidget.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -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()
}
}
}

View File

@@ -0,0 +1,264 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "expressionquerywidget.h"
#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>
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);
}

View File

@@ -0,0 +1,94 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef EXPRESSIONQUERYWIDGET_H
#define EXPRESSIONQUERYWIDGET_H
#include <private/qmldebug_p.h>
#include <QtGui/qwidget.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

View File

@@ -0,0 +1,263 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "objectpropertiesview.h"
#include <private/qmldebugservice_p.h>
#include <private/qmldebug_p.h>
#include <private/qmldebugclient_p.h>
#include <QtCore/qdebug.h>
#include <QtGui/qtreewidget.h>
#include <QtGui/qlayout.h>
#include <QtGui/qheaderview.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"

View File

@@ -0,0 +1,81 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#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

View File

@@ -0,0 +1,219 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#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);
}
}
}

View File

@@ -0,0 +1,84 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#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

View File

@@ -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

View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file>engines.qml</file>
<file>engine.png</file>
<file>refresh.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -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

View File

@@ -0,0 +1,354 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#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

View File

@@ -0,0 +1,142 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef WATCHTABLEMODEL_H
#define WATCHTABLEMODEL_H
#include <QtCore/qpointer.h>
#include <QtCore/qlist.h>
#include <QtCore/qabstractitemmodel.h>
#include <QtGui/qwidget.h>
#include <QtGui/qheaderview.h>
#include <QtGui/qtableview.h>
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,138 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "inspectoroutputpane.h"
#include <QtGui/qtextedit.h>
InspectorOutputPane::InspectorOutputPane(QObject *parent)
: Core::IOutputPane(parent),
m_textEdit(new QTextEdit)
{
}
InspectorOutputPane::~InspectorOutputPane()
{
delete m_textEdit;
}
QWidget *InspectorOutputPane::outputWidget(QWidget *parent)
{
Q_UNUSED(parent);
return m_textEdit;
}
QList<QWidget*> InspectorOutputPane::toolBarWidgets() const
{
return QList<QWidget *>();
}
QString InspectorOutputPane::name() const
{
return tr("Inspector Output");
}
int InspectorOutputPane::priorityInStatusBar() const
{
return 1;
}
void InspectorOutputPane::clearContents()
{
m_textEdit->clear();
}
void InspectorOutputPane::visibilityChanged(bool visible)
{
Q_UNUSED(visible);
}
void InspectorOutputPane::setFocus()
{
m_textEdit->setFocus();
}
bool InspectorOutputPane::hasFocus()
{
return m_textEdit->hasFocus();
}
bool InspectorOutputPane::canFocus()
{
return true;
}
bool InspectorOutputPane::canNavigate()
{
return false;
}
bool InspectorOutputPane::canNext()
{
return false;
}
bool InspectorOutputPane::canPrevious()
{
return false;
}
void InspectorOutputPane::goToNext()
{
}
void InspectorOutputPane::goToPrev()
{
}
void InspectorOutputPane::addOutput(RunControl *, const QString &text)
{
m_textEdit->insertPlainText(text);
m_textEdit->moveCursor(QTextCursor::End);
}
void InspectorOutputPane::addOutputInline(RunControl *, const QString &text)
{
m_textEdit->insertPlainText(text);
m_textEdit->moveCursor(QTextCursor::End);
}
void InspectorOutputPane::addErrorOutput(RunControl *, const QString &text)
{
m_textEdit->append(text);
m_textEdit->moveCursor(QTextCursor::End);
}
void InspectorOutputPane::addInspectorStatus(const QString &text)
{
m_textEdit->setTextColor(Qt::darkGreen);
m_textEdit->append(text);
m_textEdit->moveCursor(QTextCursor::End);
m_textEdit->setTextColor(Qt::black);
}

View File

@@ -0,0 +1,82 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef INSPECTOROUTPUTPANE_H
#define INSPECTOROUTPUTPANE_H
#include <coreplugin/ioutputpane.h>
#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
class QTextEdit;
class RunControl;
class InspectorOutputPane : public Core::IOutputPane
{
Q_OBJECT
public:
InspectorOutputPane(QObject *parent = 0);
virtual ~InspectorOutputPane();
virtual QWidget *outputWidget(QWidget *parent);
virtual QList<QWidget*> toolBarWidgets() const;
virtual QString name() const;
virtual int priorityInStatusBar() const;
virtual void clearContents();
virtual void visibilityChanged(bool visible);
virtual void setFocus();
virtual bool hasFocus();
virtual bool canFocus();
virtual bool canNavigate();
virtual bool canNext();
virtual bool canPrevious();
virtual void goToNext();
virtual void goToPrev();
public slots:
void addOutput(RunControl *, const QString &text);
void addOutputInline(RunControl *, const QString &text);
void addErrorOutput(RunControl *, const QString &text);
void addInspectorStatus(const QString &text);
private:
QTextEdit *m_textEdit;
};
QT_END_NAMESPACE
#endif

View File

@@ -0,0 +1,53 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLINSPECTOR_H
#define QMLINSPECTOR_H
#include <QString>
namespace QmlInspector {
namespace Constants {
const char * const RUN = "QmlInspector.Run";
const char * const STOP = "QmlInspector.Stop";
const char * const C_INSPECTOR = "QmlInspector";
};
class StartParameters
{
public:
StartParameters() : port(0) {}
~StartParameters() {}
QString address;
quint16 port;
};
};
#endif

View File

@@ -0,0 +1,27 @@
TEMPLATE = lib
TARGET = QmlInspector
INCLUDEPATH += .
DEPENDPATH += .
include(components/qmldebugger.pri)
HEADERS += qmlinspectorplugin.h \
qmlinspector.h \
qmlinspectormode.h \
inspectoroutputpane.h \
runcontrol.h
SOURCES += qmlinspectorplugin.cpp \
qmlinspectormode.cpp \
inspectoroutputpane.cpp \
runcontrol.cpp
OTHER_FILES += QmlInspector.pluginspec
RESOURCES += qmlinspector.qrc
include(../../qtcreatorplugin.pri)
include(../../plugins/projectexplorer/projectexplorer.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/texteditor/texteditor.pri)

View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/qmlinspector" >
<file>images/logo.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,555 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "qmlinspector.h"
#include "qmlinspectormode.h"
#include "components/objectpropertiesview.h"
#include "components/objecttree.h"
#include "components/watchtable.h"
#include "components/canvasframerate.h"
#include "components/expressionquerywidget.h"
#include <private/qmldebug_p.h>
#include <private/qmldebugclient_p.h>
#include <utils/styledbar.h>
#include <utils/fancymainwindow.h>
#include <coreplugin/basemode.h>
#include <coreplugin/findplaceholder.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/rightpane.h>
#include <coreplugin/navigationwidget.h>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <texteditor/itexteditor.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <QtCore/QStringList>
#include <QtCore/QtPlugin>
#include <QtCore/QDebug>
#include <QtGui/qtoolbutton.h>
#include <QtGui/qtoolbar.h>
#include <QtGui/qboxlayout.h>
#include <QtGui/qlabel.h>
#include <QtGui/qdockwidget.h>
#include <QtGui/qaction.h>
#include <QtGui/qlineedit.h>
#include <QtGui/qlabel.h>
#include <QtGui/qspinbox.h>
QT_BEGIN_NAMESPACE
class EngineSpinBox : public QSpinBox
{
Q_OBJECT
public:
struct EngineInfo
{
QString name;
int id;
};
EngineSpinBox(QWidget *parent = 0);
void addEngine(int engine, const QString &name);
void clearEngines();
protected:
virtual QString textFromValue(int value) const;
virtual int valueFromText(const QString &text) const;
private:
QList<EngineInfo> m_engines;
};
EngineSpinBox::EngineSpinBox(QWidget *parent)
: QSpinBox(parent)
{
setEnabled(false);
setReadOnly(true);
setRange(0, 0);
}
void EngineSpinBox::addEngine(int engine, const QString &name)
{
EngineInfo info;
info.id = engine;
if (name.isEmpty())
info.name = tr("Engine %1", "engine number").arg(engine);
else
info.name = name;
m_engines << info;
setRange(0, m_engines.count()-1);
}
void EngineSpinBox::clearEngines()
{
m_engines.clear();
}
QString EngineSpinBox::textFromValue(int value) const
{
for (int i=0; i<m_engines.count(); ++i) {
if (m_engines[i].id == value)
return m_engines[i].name;
}
return QLatin1String("<None>");
}
int EngineSpinBox::valueFromText(const QString &text) const
{
for (int i=0; i<m_engines.count(); ++i) {
if (m_engines[i].name == text)
return m_engines[i].id;
}
return -1;
}
QmlInspectorMode::QmlInspectorMode(QObject *parent)
: Core::BaseMode(parent),
m_conn(0),
m_client(0),
m_engineQuery(0),
m_contextQuery(0)
{
m_watchTableModel = new WatchTableModel(0, this);
initActions();
setWidget(createModeWindow());
setName(tr("QML Inspect"));
setIcon(QIcon(":/qmlinspector/images/logo.png"));
setUniqueModeName("QML_INSPECT_MODE");
}
quint16 QmlInspectorMode::viewerPort() const
{
return m_portSpinBox->value();
}
void QmlInspectorMode::connectToViewer()
{
if (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState)
return;
delete m_client; m_client = 0;
if (m_conn) {
m_conn->disconnectFromHost();
delete m_conn;
}
m_conn = new QmlDebugConnection(this);
connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(connectionStateChanged()));
connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(connectionError()));
m_conn->connectToHost(m_addressEdit->text(), m_portSpinBox->value());
}
void QmlInspectorMode::disconnectFromViewer()
{
m_conn->disconnectFromHost();
}
void QmlInspectorMode::connectionStateChanged()
{
switch (m_conn->state()) {
default:
case QAbstractSocket::UnconnectedState:
{
emit statusMessage(tr("[Inspector] disconnected.\n\n"));
m_addressEdit->setEnabled(true);
m_portSpinBox->setEnabled(true);
delete m_engineQuery;
m_engineQuery = 0;
delete m_contextQuery;
m_contextQuery = 0;
break;
}
case QAbstractSocket::HostLookupState:
emit statusMessage(tr("[Inspector] resolving host..."));
break;
case QAbstractSocket::ConnectingState:
emit statusMessage(tr("[Inspector] connecting to debug server..."));
break;
case QAbstractSocket::ConnectedState:
{
emit statusMessage(tr("[Inspector] connected.\n"));
m_addressEdit->setEnabled(false);
m_portSpinBox->setEnabled(false);
if (!m_client) {
m_client = new QmlEngineDebug(m_conn, this);
m_objectTreeWidget->setEngineDebug(m_client);
m_propertiesWidget->setEngineDebug(m_client);
m_watchTableModel->setEngineDebug(m_client);
m_expressionWidget->setEngineDebug(m_client);
}
m_objectTreeWidget->clear();
m_propertiesWidget->clear();
m_expressionWidget->clear();
m_watchTableModel->removeAllWatches();
m_frameRateWidget->reset(m_conn);
reloadEngines();
break;
}
case QAbstractSocket::ClosingState:
emit statusMessage(tr("[Inspector] closing..."));
break;
}
}
void QmlInspectorMode::connectionError()
{
emit statusMessage(tr("[Inspector] error: (%1) %2", "%1=error code, %2=error message")
.arg(m_conn->error()).arg(m_conn->errorString()));
}
void QmlInspectorMode::initActions()
{
m_actions.startAction = new QAction(tr("Start Inspector"), this);
m_actions.startAction->setIcon(QIcon(ProjectExplorer::Constants::ICON_RUN));
m_actions.stopAction = new QAction(tr("Stop Inspector"), this);
m_actions.stopAction->setIcon(QIcon(ProjectExplorer::Constants::ICON_STOP));
Core::ICore *core = Core::ICore::instance();
Core::ActionManager *am = core->actionManager();
Core::UniqueIDManager *uidm = core->uniqueIDManager();
QList<int> context;
context << uidm->uniqueIdentifier(QmlInspector::Constants::C_INSPECTOR);
am->registerAction(m_actions.startAction, QmlInspector::Constants::RUN, context);
connect(m_actions.startAction, SIGNAL(triggered()), SIGNAL(startViewer()));
am->registerAction(m_actions.stopAction, QmlInspector::Constants::STOP, context);
connect(m_actions.stopAction, SIGNAL(triggered()), SIGNAL(stopViewer()));
}
QToolButton *QmlInspectorMode::createToolButton(QAction *action)
{
QToolButton *button = new QToolButton;
button->setDefaultAction(action);
return button;
}
QWidget *QmlInspectorMode::createMainView()
{
initWidgets();
Utils::FancyMainWindow *mainWindow = new Utils::FancyMainWindow;
mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
mainWindow->setDocumentMode(true);
QBoxLayout *editorHolderLayout = new QVBoxLayout;
editorHolderLayout->setMargin(0);
editorHolderLayout->setSpacing(0);
QWidget *editorAndFindWidget = new QWidget;
editorAndFindWidget->setLayout(editorHolderLayout);
editorHolderLayout->addWidget(new Core::EditorManagerPlaceHolder(this));
editorHolderLayout->addWidget(new Core::FindToolBarPlaceHolder(editorAndFindWidget));
Utils::StyledBar *treeOptionBar = new Utils::StyledBar;
QHBoxLayout *treeOptionBarLayout = new QHBoxLayout(treeOptionBar);
treeOptionBarLayout->setContentsMargins(5, 0, 5, 0);
treeOptionBarLayout->setSpacing(5);
treeOptionBarLayout->addWidget(new QLabel(tr("QML engine:")));
treeOptionBarLayout->addWidget(m_engineSpinBox);
QWidget *treeWindow = new QWidget;
QVBoxLayout *treeWindowLayout = new QVBoxLayout(treeWindow);
treeWindowLayout->setMargin(0);
treeWindowLayout->setSpacing(0);
treeWindowLayout->addWidget(treeOptionBar);
treeWindowLayout->addWidget(m_objectTreeWidget);
Core::MiniSplitter *documentAndTree = new Core::MiniSplitter;
documentAndTree->addWidget(editorAndFindWidget);
documentAndTree->addWidget(new Core::RightPanePlaceHolder(this));
documentAndTree->addWidget(treeWindow);
documentAndTree->setStretchFactor(0, 2);
documentAndTree->setStretchFactor(1, 0);
documentAndTree->setStretchFactor(2, 0);
Utils::StyledBar *configBar = new Utils::StyledBar;
configBar->setProperty("topBorder", true);
QHBoxLayout *configBarLayout = new QHBoxLayout(configBar);
configBarLayout->setMargin(0);
configBarLayout->setSpacing(5);
Core::ICore *core = Core::ICore::instance();
Core::ActionManager *am = core->actionManager();
configBarLayout->addWidget(createToolButton(am->command(QmlInspector::Constants::RUN)->action()));
configBarLayout->addWidget(createToolButton(am->command(QmlInspector::Constants::STOP)->action()));
configBarLayout->addWidget(m_addressEdit);
configBarLayout->addWidget(m_portSpinBox);
configBarLayout->addStretch();
QWidget *widgetAboveTabs = new QWidget;
QVBoxLayout *widgetAboveTabsLayout = new QVBoxLayout(widgetAboveTabs);
widgetAboveTabsLayout->setMargin(0);
widgetAboveTabsLayout->setSpacing(0);
widgetAboveTabsLayout->addWidget(documentAndTree);
widgetAboveTabsLayout->addWidget(configBar);
Core::MiniSplitter *mainSplitter = new Core::MiniSplitter(Qt::Vertical);
mainSplitter->addWidget(widgetAboveTabs);
mainSplitter->addWidget(createBottomWindow());
mainSplitter->setStretchFactor(0, 3);
mainSplitter->setStretchFactor(1, 1);
QWidget *centralWidget = new QWidget;
QVBoxLayout *centralLayout = new QVBoxLayout(centralWidget);
centralLayout->setMargin(0);
centralLayout->setSpacing(0);
centralLayout->addWidget(mainSplitter);
mainWindow->setCentralWidget(centralWidget);
return mainWindow;
}
QWidget *QmlInspectorMode::createBottomWindow()
{
Utils::FancyMainWindow *win = new Utils::FancyMainWindow;
win->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
win->setDocumentMode(true);
win->setTrackingEnabled(true);
Core::MiniSplitter *leftSplitter = new Core::MiniSplitter(Qt::Vertical);
leftSplitter->addWidget(m_propertiesWidget);
leftSplitter->addWidget(m_expressionWidget);
leftSplitter->setStretchFactor(0, 2);
leftSplitter->setStretchFactor(1, 1);
Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Horizontal);
propSplitter->addWidget(leftSplitter);
propSplitter->addWidget(m_watchTableView);
propSplitter->setStretchFactor(0, 2);
propSplitter->setStretchFactor(1, 1);
propSplitter->setWindowTitle(tr("Properties and Watchers"));
QDockWidget *propertiesDock = win->addDockForWidget(propSplitter);
win->addDockWidget(Qt::TopDockWidgetArea, propertiesDock);
QDockWidget *frameRateDock = win->addDockForWidget(m_frameRateWidget);
win->addDockWidget(Qt::TopDockWidgetArea, frameRateDock);
// stack the dock widgets as tabs
win->tabifyDockWidget(frameRateDock, propertiesDock);
return win;
}
QWidget *QmlInspectorMode::createModeWindow()
{
// right-side window with editor, output etc.
Core::MiniSplitter *mainWindowSplitter = new Core::MiniSplitter;
mainWindowSplitter->addWidget(createMainView());
mainWindowSplitter->addWidget(new Core::OutputPanePlaceHolder(this));
mainWindowSplitter->setStretchFactor(0, 10);
mainWindowSplitter->setStretchFactor(1, 0);
mainWindowSplitter->setOrientation(Qt::Vertical);
// navigation + right-side window
Core::MiniSplitter *splitter = new Core::MiniSplitter;
splitter->addWidget(new Core::NavigationWidgetPlaceHolder(this));
splitter->addWidget(mainWindowSplitter);
splitter->setStretchFactor(0, 0);
splitter->setStretchFactor(1, 1);
return splitter;
}
void QmlInspectorMode::initWidgets()
{
m_objectTreeWidget = new ObjectTree;
m_propertiesWidget = new ObjectPropertiesView;
m_watchTableView = new WatchTableView(m_watchTableModel);
m_frameRateWidget = new CanvasFrameRate;
m_expressionWidget = new ExpressionQueryWidget(ExpressionQueryWidget::ShellMode);
// FancyMainWindow uses widgets' window titles for tab labels
m_objectTreeWidget->setWindowTitle(tr("Object Tree"));
m_frameRateWidget->setWindowTitle(tr("Frame rate"));
m_watchTableView->setModel(m_watchTableModel);
WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTableModel);
m_watchTableView->setHorizontalHeader(header);
connect(m_objectTreeWidget, SIGNAL(activated(QmlDebugObjectReference)),
this, SLOT(treeObjectActivated(QmlDebugObjectReference)));
connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
m_propertiesWidget, SLOT(reload(QmlDebugObjectReference)));
connect(m_objectTreeWidget, SIGNAL(expressionWatchRequested(QmlDebugObjectReference,QString)),
m_watchTableModel, SLOT(expressionWatchRequested(QmlDebugObjectReference,QString)));
connect(m_propertiesWidget, SIGNAL(activated(QmlDebugObjectReference,QmlDebugPropertyReference)),
m_watchTableModel, SLOT(togglePropertyWatch(QmlDebugObjectReference,QmlDebugPropertyReference)));
connect(m_watchTableModel, SIGNAL(watchCreated(QmlDebugWatch*)),
m_propertiesWidget, SLOT(watchCreated(QmlDebugWatch*)));
connect(m_watchTableModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
m_watchTableView, SLOT(scrollToBottom()));
connect(m_watchTableView, SIGNAL(objectActivated(int)),
m_objectTreeWidget, SLOT(setCurrentObject(int)));
connect(m_objectTreeWidget, SIGNAL(currentObjectChanged(QmlDebugObjectReference)),
m_expressionWidget, SLOT(setCurrentObject(QmlDebugObjectReference)));
m_addressEdit = new QLineEdit;
m_addressEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
m_addressEdit->setText("127.0.0.1");
m_portSpinBox = new QSpinBox;
m_portSpinBox->setMinimum(1024);
m_portSpinBox->setMaximum(20000);
m_portSpinBox->setValue(3768);
m_engineSpinBox = new EngineSpinBox;
m_engineSpinBox->setEnabled(false);
connect(m_engineSpinBox, SIGNAL(valueChanged(int)),
SLOT(queryEngineContext(int)));
}
void QmlInspectorMode::reloadEngines()
{
if (m_engineQuery) {
emit statusMessage("[Inspector] Waiting for response to previous engine query");
return;
}
m_engineSpinBox->setEnabled(false);
m_engineQuery = m_client->queryAvailableEngines(this);
if (!m_engineQuery->isWaiting())
enginesChanged();
else
QObject::connect(m_engineQuery, SIGNAL(stateChanged(QmlDebugQuery::State)),
this, SLOT(enginesChanged()));
}
void QmlInspectorMode::enginesChanged()
{
m_engineSpinBox->clearEngines();
QList<QmlDebugEngineReference> engines = m_engineQuery->engines();
delete m_engineQuery; m_engineQuery = 0;
if (engines.isEmpty())
qWarning("qmldebugger: no engines found!");
m_engineSpinBox->setEnabled(true);
for (int i=0; i<engines.count(); ++i)
m_engineSpinBox->addEngine(engines.at(i).debugId(), engines.at(i).name());
if (engines.count() > 0) {
m_engineSpinBox->setValue(engines.at(0).debugId());
queryEngineContext(engines.at(0).debugId());
}
}
void QmlInspectorMode::queryEngineContext(int id)
{
if (id < 0)
return;
if (m_contextQuery) {
delete m_contextQuery;
m_contextQuery = 0;
}
m_contextQuery = m_client->queryRootContexts(QmlDebugEngineReference(id), this);
if (!m_contextQuery->isWaiting())
contextChanged();
else
QObject::connect(m_contextQuery, SIGNAL(stateChanged(QmlDebugQuery::State)),
this, SLOT(contextChanged()));
}
void QmlInspectorMode::contextChanged()
{
//dump(m_contextQuery->rootContext(), 0);
foreach (const QmlDebugObjectReference &object, m_contextQuery->rootContext().objects())
m_objectTreeWidget->reload(object.debugId());
delete m_contextQuery; m_contextQuery = 0;
}
void QmlInspectorMode::treeObjectActivated(const QmlDebugObjectReference &obj)
{
QmlDebugFileReference source = obj.source();
QString fileName = source.url().toLocalFile();
if (source.lineNumber() < 0 || !QFile::exists(fileName))
return;
Core::EditorManager *editorManager = Core::EditorManager::instance();
TextEditor::ITextEditor *editor = qobject_cast<TextEditor::ITextEditor*>(editorManager->openEditor(fileName));
if (editor) {
editorManager->ensureEditorManagerVisible();
editorManager->addCurrentPositionToNavigationHistory();
editor->gotoLine(source.lineNumber());
editor->widget()->setFocus();
}
}
QT_END_NAMESPACE
#include "qmlinspectormode.moc"

View File

@@ -0,0 +1,121 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLINSPECTORMODE_H
#define QMLINSPECTORMODE_H
#include <coreplugin/basemode.h>
#include <QtGui/QAction>
#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
class QToolButton;
class QLineEdit;
class QSpinBox;
class QLabel;
class QmlEngineDebug;
class QmlDebugConnection;
class QmlDebugEnginesQuery;
class QmlDebugRootContextQuery;
class QmlDebugObjectReference;
class ObjectTree;
class WatchTableModel;
class WatchTableView;
class ObjectPropertiesView;
class CanvasFrameRate;
class ExpressionQueryWidget;
class EngineSpinBox;
class QmlInspectorMode : public Core::BaseMode
{
Q_OBJECT
public:
QmlInspectorMode(QObject *parent = 0);
quint16 viewerPort() const;
signals:
void startViewer();
void stopViewer();
void statusMessage(const QString &text);
public slots:
void connectToViewer(); // using host, port from widgets
void disconnectFromViewer();
private slots:
void connectionStateChanged();
void connectionError();
void reloadEngines();
void enginesChanged();
void queryEngineContext(int);
void contextChanged();
void treeObjectActivated(const QmlDebugObjectReference &obj);
private:
struct Actions {
QAction *startAction;
QAction *stopAction;
};
void initActions();
QWidget *createModeWindow();
QWidget *createMainView();
void initWidgets();
QWidget *createBottomWindow();
QToolButton *createToolButton(QAction *action);
Actions m_actions;
QmlDebugConnection *m_conn;
QmlEngineDebug *m_client;
QmlDebugEnginesQuery *m_engineQuery;
QmlDebugRootContextQuery *m_contextQuery;
ObjectTree *m_objectTreeWidget;
ObjectPropertiesView *m_propertiesWidget;
WatchTableModel *m_watchTableModel;
WatchTableView *m_watchTableView;
CanvasFrameRate *m_frameRateWidget;
ExpressionQueryWidget *m_expressionWidget;
QLineEdit *m_addressEdit;
QSpinBox *m_portSpinBox;
EngineSpinBox *m_engineSpinBox;
};
QT_END_NAMESPACE
#endif

View File

@@ -0,0 +1,163 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "runcontrol.h"
#include "qmlinspector.h"
#include "qmlinspectormode.h"
#include "inspectoroutputpane.h"
#include "qmlinspectorplugin.h"
#include <private/qmldebug_p.h>
#include <private/qmldebugclient_p.h>
#include <coreplugin/icore.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QStringList>
#include <QtCore/QtPlugin>
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
QmlInspectorPlugin::QmlInspectorPlugin()
: m_inspectMode(0),
m_runControl(0)
{
}
QmlInspectorPlugin::~QmlInspectorPlugin()
{
}
void QmlInspectorPlugin::shutdown()
{
removeObject(m_inspectMode);
delete m_inspectMode;
m_inspectMode = 0;
removeObject(m_outputPane);
delete m_outputPane;
m_outputPane = 0;
}
bool QmlInspectorPlugin::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
Core::ICore *core = Core::ICore::instance();
Core::UniqueIDManager *uidm = core->uniqueIDManager();
QList<int> context;
context.append(uidm->uniqueIdentifier(QmlInspector::Constants::C_INSPECTOR));
context.append(uidm->uniqueIdentifier(Core::Constants::C_EDITORMANAGER));
context.append(uidm->uniqueIdentifier(Core::Constants::C_NAVIGATION_PANE));
m_inspectMode = new QmlInspectorMode(this);
connect(m_inspectMode, SIGNAL(startViewer()), SLOT(startViewer()));
connect(m_inspectMode, SIGNAL(stopViewer()), SLOT(stopViewer()));
m_inspectMode->setContext(context);
addObject(m_inspectMode);
m_outputPane = new InspectorOutputPane;
addObject(m_outputPane);
connect(m_inspectMode, SIGNAL(statusMessage(QString)),
m_outputPane, SLOT(addInspectorStatus(QString)));
m_runControlFactory = new QmlInspectorRunControlFactory(this);
addAutoReleasedObject(m_runControlFactory);
return true;
}
void QmlInspectorPlugin::extensionsInitialized()
{
}
void QmlInspectorPlugin::startViewer()
{
stopViewer();
ProjectExplorer::Project *project = 0;
ProjectExplorer::ProjectExplorerPlugin *plugin = ProjectExplorer::ProjectExplorerPlugin::instance();
if (plugin)
project = plugin->currentProject();
if (!project) {
qDebug() << "No project loaded"; // TODO should this just run the debugger without a viewer?
return;
}
ProjectExplorer::RunConfiguration *rc = project->activeRunConfiguration();
QmlInspector::StartParameters sp;
sp.port = m_inspectMode->viewerPort();
m_runControl = m_runControlFactory->create(rc, ProjectExplorer::Constants::RUNMODE, sp);
if (m_runControl) {
connect(m_runControl, SIGNAL(started()), m_inspectMode, SLOT(connectToViewer()));
connect(m_runControl, SIGNAL(finished()), m_inspectMode, SLOT(disconnectFromViewer()));
connect(m_runControl, SIGNAL(addToOutputWindow(RunControl*,QString)),
m_outputPane, SLOT(addOutput(RunControl*,QString)));
connect(m_runControl, SIGNAL(addToOutputWindowInline(RunControl*,QString)),
m_outputPane, SLOT(addOutputInline(RunControl*,QString)));
connect(m_runControl, SIGNAL(error(RunControl*,QString)),
m_outputPane, SLOT(addErrorOutput(RunControl*,QString)));
m_runControl->start();
m_outputPane->popup(false);
}
}
void QmlInspectorPlugin::stopViewer()
{
if (m_runControl) {
m_runControl->stop();
m_runControl->deleteLater();
m_runControl = 0;
}
}
Q_EXPORT_PLUGIN(QmlInspectorPlugin)
QT_END_NAMESPACE

View File

@@ -0,0 +1,78 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLINSPECTORPLUGIN_H
#define QMLINSPECTORPLUGIN_H
#include <extensionsystem/iplugin.h>
#include <QtCore/QObject>
#include <QtCore/QPointer>
QT_BEGIN_NAMESPACE
class QStringList;
class QmlInspectorRunControlFactory;
class QmlInspectorMode;
class InspectorOutputPane;
namespace ProjectExplorer
{
class RunControl;
}
class QmlInspectorPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
public:
QmlInspectorPlugin();
~QmlInspectorPlugin();
virtual bool initialize(const QStringList &arguments, QString *errorString);
virtual void extensionsInitialized();
virtual void shutdown();
private slots:
void startViewer();
void stopViewer();
private:
QmlInspectorMode *m_inspectMode;
InspectorOutputPane *m_outputPane;
QmlInspectorRunControlFactory *m_runControlFactory;
QPointer<ProjectExplorer::RunControl> m_runControl;
};
QT_END_NAMESPACE
#endif // QMLINSPECTORPLUGIN_H

View File

@@ -0,0 +1,162 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "runcontrol.h"
#include <projectexplorer/applicationlauncher.h>
#include <projectexplorer/applicationrunconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <QtCore/qdebug.h>
#include <QtCore/qtimer.h>
using namespace ProjectExplorer;
QmlInspectorRunControlFactory::QmlInspectorRunControlFactory(QObject *parent)
: ProjectExplorer::IRunControlFactory(parent)
{
}
bool QmlInspectorRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const
{
Q_UNUSED(runConfiguration);
if (mode != ProjectExplorer::Constants::RUNMODE)
return false;
return true;
}
ProjectExplorer::RunControl *QmlInspectorRunControlFactory::create(RunConfiguration *runConfiguration, const QString &mode)
{
Q_UNUSED(mode);
return new QmlInspectorRunControl(runConfiguration);
}
ProjectExplorer::RunControl *QmlInspectorRunControlFactory::create(ProjectExplorer::RunConfiguration *runConfiguration,
const QString &mode, const QmlInspector::StartParameters &sp)
{
Q_UNUSED(mode);
return new QmlInspectorRunControl(runConfiguration, sp);
}
QString QmlInspectorRunControlFactory::displayName() const
{
return tr("Qml Inspector");
}
QWidget *QmlInspectorRunControlFactory::configurationWidget(RunConfiguration *runConfiguration)
{
Q_UNUSED(runConfiguration);
return 0;
}
QmlInspectorRunControl::QmlInspectorRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
const QmlInspector::StartParameters &sp)
: ProjectExplorer::RunControl(runConfiguration),
m_configuration(runConfiguration),
m_running(false),
m_viewerLauncher(0),
m_startParams(sp)
{
}
QmlInspectorRunControl::~QmlInspectorRunControl()
{
}
void QmlInspectorRunControl::start()
{
if (m_running || m_viewerLauncher)
return;
m_viewerLauncher = new ProjectExplorer::ApplicationLauncher(this);
connect(m_viewerLauncher, SIGNAL(applicationError(QString)), SLOT(applicationError(QString)));
connect(m_viewerLauncher, SIGNAL(processExited(int)), SLOT(viewerExited()));
connect(m_viewerLauncher, SIGNAL(appendOutput(QString)), SLOT(appendOutput(QString)));
connect(m_viewerLauncher, SIGNAL(bringToForegroundRequested(qint64)),
this, SLOT(appStarted()));
LocalApplicationRunConfiguration *rc = qobject_cast<LocalApplicationRunConfiguration *>(m_configuration);
if (!rc)
return;
ProjectExplorer::Environment env = rc->environment();
env.set("QML_DEBUG_SERVER_PORT", QString::number(m_startParams.port));
QStringList arguments = rc->commandLineArguments();
arguments << QLatin1String("-stayontop");
m_viewerLauncher->setEnvironment(env.toStringList());
m_viewerLauncher->setWorkingDirectory(rc->workingDirectory());
m_running = true;
m_viewerLauncher->start(static_cast<ApplicationLauncher::Mode>(rc->runMode()),
rc->executable(), arguments);
}
void QmlInspectorRunControl::stop()
{
if (m_viewerLauncher->isRunning())
m_viewerLauncher->stop();
}
bool QmlInspectorRunControl::isRunning() const
{
return m_running;
}
void QmlInspectorRunControl::appStarted()
{
QTimer::singleShot(500, this, SLOT(delayedStart()));
}
void QmlInspectorRunControl::appendOutput(const QString &s)
{
emit addToOutputWindow(this, s);
}
void QmlInspectorRunControl::delayedStart()
{
emit started();
}
void QmlInspectorRunControl::viewerExited()
{
m_running = false;
emit finished();
deleteLater();
}
void QmlInspectorRunControl::applicationError(const QString &s)
{
emit error(this, s);
}

View File

@@ -0,0 +1,94 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLINSPECTORRUNCONTROL_H
#define QMLINSPECTORRUNCONTROL_H
#include "qmlinspector.h"
#include <projectexplorer/runconfiguration.h>
#include <QtCore/qobject.h>
namespace ProjectExplorer {
class ApplicationLauncher;
}
class QmlInspectorRunControlFactory : public ProjectExplorer::IRunControlFactory
{
Q_OBJECT
public:
explicit QmlInspectorRunControlFactory(QObject *parent);
virtual bool canRun(
ProjectExplorer::RunConfiguration *runConfiguration,
const QString &mode) const;
virtual ProjectExplorer::RunControl *create(
ProjectExplorer::RunConfiguration *runConfiguration,
const QString &mode);
ProjectExplorer::RunControl *create(
ProjectExplorer::RunConfiguration *runConfiguration,
const QString &mode,
const QmlInspector::StartParameters &sp);
virtual QString displayName() const;
virtual QWidget *configurationWidget(ProjectExplorer::RunConfiguration *runConfiguration);
};
class QmlInspectorRunControl : public ProjectExplorer::RunControl
{
Q_OBJECT
public:
explicit QmlInspectorRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
const QmlInspector::StartParameters &sp = QmlInspector::StartParameters());
~QmlInspectorRunControl();
virtual void start();
virtual void stop();
virtual bool isRunning() const;
private slots:
void appendOutput(const QString &s);
void appStarted();
void delayedStart();
void viewerExited();
void applicationError(const QString &error);
private:
ProjectExplorer::RunConfiguration *m_configuration;
bool m_running;
ProjectExplorer::ApplicationLauncher *m_viewerLauncher;
QmlInspector::StartParameters m_startParams;
};
#endif