From 1bf3418314ae4412a0938a728a7a3e30a47f9f85 Mon Sep 17 00:00:00 2001 From: Bea Lam <bea.lam@nokia.com> Date: Fri, 11 Dec 2009 14:56:04 +1000 Subject: [PATCH] Add qmlinspector plugin. --- src/plugins/plugins.pro | 9 + .../qmlinspector/QmlInspector.pluginspec | 28 + .../components/canvasframerate.cpp | 569 ++++++++++++++++++ .../qmlinspector/components/canvasframerate.h | 80 +++ .../qmlinspector/components/engine.cpp | 209 +++++++ src/plugins/qmlinspector/components/engine.h | 91 +++ .../qmlinspector/components/engine.png | Bin 0 -> 6394 bytes .../qmlinspector/components/engines.qml | 46 ++ .../components/expressionquerywidget.cpp | 264 ++++++++ .../components/expressionquerywidget.h | 94 +++ .../components/objectpropertiesview.cpp | 263 ++++++++ .../components/objectpropertiesview.h | 81 +++ .../qmlinspector/components/objecttree.cpp | 219 +++++++ .../qmlinspector/components/objecttree.h | 84 +++ .../qmlinspector/components/qmldebugger.pri | 16 + .../qmlinspector/components/qmldebugger.qrc | 7 + .../qmlinspector/components/refresh.png | Bin 0 -> 6169 bytes .../qmlinspector/components/standalone.pro | 19 + .../qmlinspector/components/watchtable.cpp | 354 +++++++++++ .../qmlinspector/components/watchtable.h | 142 +++++ src/plugins/qmlinspector/images/logo.png | Bin 0 -> 2662 bytes .../qmlinspector/inspectoroutputpane.cpp | 138 +++++ .../qmlinspector/inspectoroutputpane.h | 82 +++ src/plugins/qmlinspector/qmlinspector.h | 53 ++ src/plugins/qmlinspector/qmlinspector.pro | 27 + src/plugins/qmlinspector/qmlinspector.qrc | 6 + src/plugins/qmlinspector/qmlinspectormode.cpp | 555 +++++++++++++++++ src/plugins/qmlinspector/qmlinspectormode.h | 121 ++++ .../qmlinspector/qmlinspectorplugin.cpp | 163 +++++ src/plugins/qmlinspector/qmlinspectorplugin.h | 78 +++ src/plugins/qmlinspector/runcontrol.cpp | 162 +++++ src/plugins/qmlinspector/runcontrol.h | 94 +++ 32 files changed, 4054 insertions(+) create mode 100644 src/plugins/qmlinspector/QmlInspector.pluginspec create mode 100644 src/plugins/qmlinspector/components/canvasframerate.cpp create mode 100644 src/plugins/qmlinspector/components/canvasframerate.h create mode 100644 src/plugins/qmlinspector/components/engine.cpp create mode 100644 src/plugins/qmlinspector/components/engine.h create mode 100644 src/plugins/qmlinspector/components/engine.png create mode 100644 src/plugins/qmlinspector/components/engines.qml create mode 100644 src/plugins/qmlinspector/components/expressionquerywidget.cpp create mode 100644 src/plugins/qmlinspector/components/expressionquerywidget.h create mode 100644 src/plugins/qmlinspector/components/objectpropertiesview.cpp create mode 100644 src/plugins/qmlinspector/components/objectpropertiesview.h create mode 100644 src/plugins/qmlinspector/components/objecttree.cpp create mode 100644 src/plugins/qmlinspector/components/objecttree.h create mode 100644 src/plugins/qmlinspector/components/qmldebugger.pri create mode 100644 src/plugins/qmlinspector/components/qmldebugger.qrc create mode 100644 src/plugins/qmlinspector/components/refresh.png create mode 100644 src/plugins/qmlinspector/components/standalone.pro create mode 100644 src/plugins/qmlinspector/components/watchtable.cpp create mode 100644 src/plugins/qmlinspector/components/watchtable.h create mode 100644 src/plugins/qmlinspector/images/logo.png create mode 100644 src/plugins/qmlinspector/inspectoroutputpane.cpp create mode 100644 src/plugins/qmlinspector/inspectoroutputpane.h create mode 100644 src/plugins/qmlinspector/qmlinspector.h create mode 100644 src/plugins/qmlinspector/qmlinspector.pro create mode 100644 src/plugins/qmlinspector/qmlinspector.qrc create mode 100644 src/plugins/qmlinspector/qmlinspectormode.cpp create mode 100644 src/plugins/qmlinspector/qmlinspectormode.h create mode 100644 src/plugins/qmlinspector/qmlinspectorplugin.cpp create mode 100644 src/plugins/qmlinspector/qmlinspectorplugin.h create mode 100644 src/plugins/qmlinspector/runcontrol.cpp create mode 100644 src/plugins/qmlinspector/runcontrol.h diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 77cf85e11db..11060df7620 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -37,6 +37,10 @@ SUBDIRS = plugin_coreplugin \ plugin_mercurial \ debugger/dumper.pro +contains(QT_CONFIG, declarative) { + SUBDIRS += plugin_qmlinspector +} + plugin_coreplugin.subdir = coreplugin plugin_welcome.subdir = welcome @@ -180,6 +184,11 @@ plugin_qmlprojectmanager.depends += plugin_projectexplorer plugin_qmlprojectmanager.depends += plugin_help 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.depends = plugin_texteditor plugin_mercurial.depends = plugin_vcsbase diff --git a/src/plugins/qmlinspector/QmlInspector.pluginspec b/src/plugins/qmlinspector/QmlInspector.pluginspec new file mode 100644 index 00000000000..9ad51d42309 --- /dev/null +++ b/src/plugins/qmlinspector/QmlInspector.pluginspec @@ -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> diff --git a/src/plugins/qmlinspector/components/canvasframerate.cpp b/src/plugins/qmlinspector/components/canvasframerate.cpp new file mode 100644 index 00000000000..91c762fad5e --- /dev/null +++ b/src/plugins/qmlinspector/components/canvasframerate.cpp @@ -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" diff --git a/src/plugins/qmlinspector/components/canvasframerate.h b/src/plugins/qmlinspector/components/canvasframerate.h new file mode 100644 index 00000000000..88335a6df02 --- /dev/null +++ b/src/plugins/qmlinspector/components/canvasframerate.h @@ -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 + diff --git a/src/plugins/qmlinspector/components/engine.cpp b/src/plugins/qmlinspector/components/engine.cpp new file mode 100644 index 00000000000..1a768d4e3b4 --- /dev/null +++ b/src/plugins/qmlinspector/components/engine.cpp @@ -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 + diff --git a/src/plugins/qmlinspector/components/engine.h b/src/plugins/qmlinspector/components/engine.h new file mode 100644 index 00000000000..9f232e68e1d --- /dev/null +++ b/src/plugins/qmlinspector/components/engine.h @@ -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 + diff --git a/src/plugins/qmlinspector/components/engine.png b/src/plugins/qmlinspector/components/engine.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a8a04a63bc865dd84d179783a39f19fda30571 GIT binary patch literal 6394 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%0DU(0@19XC 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 IM6N<$f@bPMkpKVy literal 0 HcmV?d00001 diff --git a/src/plugins/qmlinspector/components/engines.qml b/src/plugins/qmlinspector/components/engines.qml new file mode 100644 index 00000000000..1e9335b5883 --- /dev/null +++ b/src/plugins/qmlinspector/components/engines.qml @@ -0,0 +1,46 @@ +import Qt 4.6 + +Item { + height: 100 + id: Root + signal engineClicked(int id) + signal refreshEngines() + + Row { + anchors.fill: parent + Repeater { + model: engines + Item { + width: 100; height: 100; + Image { + id: EngineIcon; + source: "qrc:/engine.png" + anchors.horizontalCenter: parent.horizontalCenter + } + Text { + anchors.top: EngineIcon.bottom; + text: modelData.name + "(" + modelData.engineId + ")" + anchors.horizontalCenter: parent.horizontalCenter + } + MouseRegion { + anchors.fill: parent + onClicked: Root.engineClicked(modelData.engineId); + } + } + } + } + + + Image { + y: 15 + source: "qrc:/refresh.png"; + width: 75; + height: 63; + smooth: true + anchors.right: parent.right + MouseRegion { + anchors.fill: parent + onClicked: Root.refreshEngines() + } + } +} diff --git a/src/plugins/qmlinspector/components/expressionquerywidget.cpp b/src/plugins/qmlinspector/components/expressionquerywidget.cpp new file mode 100644 index 00000000000..94299c0b029 --- /dev/null +++ b/src/plugins/qmlinspector/components/expressionquerywidget.cpp @@ -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); +} diff --git a/src/plugins/qmlinspector/components/expressionquerywidget.h b/src/plugins/qmlinspector/components/expressionquerywidget.h new file mode 100644 index 00000000000..f2315b54596 --- /dev/null +++ b/src/plugins/qmlinspector/components/expressionquerywidget.h @@ -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 + diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.cpp b/src/plugins/qmlinspector/components/objectpropertiesview.cpp new file mode 100644 index 00000000000..b82a9b30706 --- /dev/null +++ b/src/plugins/qmlinspector/components/objectpropertiesview.cpp @@ -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" diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.h b/src/plugins/qmlinspector/components/objectpropertiesview.h new file mode 100644 index 00000000000..2def0b57ccc --- /dev/null +++ b/src/plugins/qmlinspector/components/objectpropertiesview.h @@ -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 diff --git a/src/plugins/qmlinspector/components/objecttree.cpp b/src/plugins/qmlinspector/components/objecttree.cpp new file mode 100644 index 00000000000..cb27f818926 --- /dev/null +++ b/src/plugins/qmlinspector/components/objecttree.cpp @@ -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); + } + } +} diff --git a/src/plugins/qmlinspector/components/objecttree.h b/src/plugins/qmlinspector/components/objecttree.h new file mode 100644 index 00000000000..d7ac02c0259 --- /dev/null +++ b/src/plugins/qmlinspector/components/objecttree.h @@ -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 diff --git a/src/plugins/qmlinspector/components/qmldebugger.pri b/src/plugins/qmlinspector/components/qmldebugger.pri new file mode 100644 index 00000000000..aad5eb14fa8 --- /dev/null +++ b/src/plugins/qmlinspector/components/qmldebugger.pri @@ -0,0 +1,16 @@ +QT += network declarative +contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl + +# Input +HEADERS += $$PWD/canvasframerate.h \ + $$PWD/watchtable.h \ + $$PWD/objecttree.h \ + $$PWD/objectpropertiesview.h \ + $$PWD/expressionquerywidget.h + +SOURCES += $$PWD/canvasframerate.cpp \ + $$PWD/watchtable.cpp \ + $$PWD/objecttree.cpp \ + $$PWD/objectpropertiesview.cpp \ + $$PWD/expressionquerywidget.cpp + diff --git a/src/plugins/qmlinspector/components/qmldebugger.qrc b/src/plugins/qmlinspector/components/qmldebugger.qrc new file mode 100644 index 00000000000..cb53ad5ea6f --- /dev/null +++ b/src/plugins/qmlinspector/components/qmldebugger.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/"> + <file>engines.qml</file> + <file>engine.png</file> + <file>refresh.png</file> + </qresource> +</RCC> diff --git a/src/plugins/qmlinspector/components/refresh.png b/src/plugins/qmlinspector/components/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..8befc804f22b4a2b1adf57eb012c31b4f95ce7d3 GIT binary patch literal 6169 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 literal 0 HcmV?d00001 diff --git a/src/plugins/qmlinspector/components/standalone.pro b/src/plugins/qmlinspector/components/standalone.pro new file mode 100644 index 00000000000..72d051f3154 --- /dev/null +++ b/src/plugins/qmlinspector/components/standalone.pro @@ -0,0 +1,19 @@ +DESTDIR = ../../../bin +TARGET = qmldebugger + +include(qmldebugger.pri) + +HEADERS += $$PWD/qmldebugger.h \ + $$PWD/engine.h + +SOURCES += $$PWD/qmldebugger.cpp \ + $$PWD/engine.cpp \ + $$PWD/main.cpp + +RESOURCES += $$PWD/qmldebugger.qrc +OTHER_FILES += $$PWD/engines.qml + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +CONFIG += console diff --git a/src/plugins/qmlinspector/components/watchtable.cpp b/src/plugins/qmlinspector/components/watchtable.cpp new file mode 100644 index 00000000000..991c44b63d3 --- /dev/null +++ b/src/plugins/qmlinspector/components/watchtable.cpp @@ -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 diff --git a/src/plugins/qmlinspector/components/watchtable.h b/src/plugins/qmlinspector/components/watchtable.h new file mode 100644 index 00000000000..e2602671095 --- /dev/null +++ b/src/plugins/qmlinspector/components/watchtable.h @@ -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 diff --git a/src/plugins/qmlinspector/images/logo.png b/src/plugins/qmlinspector/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5ac14a5a81cea8a3482acf218b71df807bc11a26 GIT binary patch literal 2662 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 U`D=bPHvj+t07*qoM6N<$g2Z_e$p8QV literal 0 HcmV?d00001 diff --git a/src/plugins/qmlinspector/inspectoroutputpane.cpp b/src/plugins/qmlinspector/inspectoroutputpane.cpp new file mode 100644 index 00000000000..84b0a1cd57c --- /dev/null +++ b/src/plugins/qmlinspector/inspectoroutputpane.cpp @@ -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); +} + diff --git a/src/plugins/qmlinspector/inspectoroutputpane.h b/src/plugins/qmlinspector/inspectoroutputpane.h new file mode 100644 index 00000000000..3b5b299d508 --- /dev/null +++ b/src/plugins/qmlinspector/inspectoroutputpane.h @@ -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 + diff --git a/src/plugins/qmlinspector/qmlinspector.h b/src/plugins/qmlinspector/qmlinspector.h new file mode 100644 index 00000000000..9c01ab771cb --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspector.h @@ -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 diff --git a/src/plugins/qmlinspector/qmlinspector.pro b/src/plugins/qmlinspector/qmlinspector.pro new file mode 100644 index 00000000000..7e9a4f1214f --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspector.pro @@ -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) + diff --git a/src/plugins/qmlinspector/qmlinspector.qrc b/src/plugins/qmlinspector/qmlinspector.qrc new file mode 100644 index 00000000000..45e8ddaad5d --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspector.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/qmlinspector" > + <file>images/logo.png</file> + </qresource> +</RCC> + diff --git a/src/plugins/qmlinspector/qmlinspectormode.cpp b/src/plugins/qmlinspector/qmlinspectormode.cpp new file mode 100644 index 00000000000..636c488defb --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspectormode.cpp @@ -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" + diff --git a/src/plugins/qmlinspector/qmlinspectormode.h b/src/plugins/qmlinspector/qmlinspectormode.h new file mode 100644 index 00000000000..00f136dba2e --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspectormode.h @@ -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 diff --git a/src/plugins/qmlinspector/qmlinspectorplugin.cpp b/src/plugins/qmlinspector/qmlinspectorplugin.cpp new file mode 100644 index 00000000000..a81184b379f --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspectorplugin.cpp @@ -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 + diff --git a/src/plugins/qmlinspector/qmlinspectorplugin.h b/src/plugins/qmlinspector/qmlinspectorplugin.h new file mode 100644 index 00000000000..a1735d4c3bf --- /dev/null +++ b/src/plugins/qmlinspector/qmlinspectorplugin.h @@ -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 diff --git a/src/plugins/qmlinspector/runcontrol.cpp b/src/plugins/qmlinspector/runcontrol.cpp new file mode 100644 index 00000000000..72254310594 --- /dev/null +++ b/src/plugins/qmlinspector/runcontrol.cpp @@ -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); +} diff --git a/src/plugins/qmlinspector/runcontrol.h b/src/plugins/qmlinspector/runcontrol.h new file mode 100644 index 00000000000..b2523b5347a --- /dev/null +++ b/src/plugins/qmlinspector/runcontrol.h @@ -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 -- GitLab