diff --git a/src/plugins/debugger/qml/canvasframerate.cpp b/src/plugins/debugger/qml/canvasframerate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cbf1d690ddb88244b2951186db4ac7b332f1f2c --- /dev/null +++ b/src/plugins/debugger/qml/canvasframerate.cpp @@ -0,0 +1,569 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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 <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> + + +namespace Debugger { +namespace Internal { + +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 QDeclarativeDebugClient +{ + Q_OBJECT +public: + CanvasFrameRatePlugin(QDeclarativeDebugConnection *client); + +signals: + void sample(int, int, int, bool); + +protected: + virtual void messageReceived(const QByteArray &); + +private: + int lb; + int ld; +}; + +CanvasFrameRatePlugin::CanvasFrameRatePlugin(QDeclarativeDebugConnection *client) +: QDeclarativeDebugClient(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(QDeclarativeDebugConnection *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<QDeclarativeDebugConnection*>(sender())); + } +} + +void CanvasFrameRate::handleConnected(QDeclarativeDebugConnection *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<QDeclarativeDebugClient *>(m_plugin)->setEnabled(checked); +} + +} // Internal +} // Debugger + +#include "canvasframerate.moc" diff --git a/src/plugins/debugger/qml/canvasframerate.h b/src/plugins/debugger/qml/canvasframerate.h new file mode 100644 index 0000000000000000000000000000000000000000..ad35d9a7efb9ba978968f8991f205603e6c4db80 --- /dev/null +++ b/src/plugins/debugger/qml/canvasframerate.h @@ -0,0 +1,88 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 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/qdeclarativedebugclient_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; +QT_END_NAMESPACE + + +namespace Debugger { +namespace Internal { + + +class CanvasFrameRatePlugin; + +class CanvasFrameRate : public QWidget +{ + Q_OBJECT +public: + CanvasFrameRate(QWidget *parent = 0); + + void reset(QDeclarativeDebugConnection *conn); + + void setSizeHint(const QSize &); + virtual QSize sizeHint() const; + +signals: + void contextHelpIdChanged(const QString &helpId); + +private slots: + void clearGraph(); + void newTab(); + void enabledToggled(bool); + void connectionStateChanged(QAbstractSocket::SocketState state); + +private: + void handleConnected(QDeclarativeDebugConnection *conn); + + QGroupBox *m_group; + QTabWidget *m_tabs; + QSpinBox *m_res; + QPushButton *m_clearButton; + CanvasFrameRatePlugin *m_plugin; + QSize m_sizeHint; +}; + +} // Internal +} // Debugger + +#endif // CANVASFRAMERATE_H + diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri index dc9d548c57b0ad72d46ddfbe9cbefbb21e13f9b8..5191c96b41fac3f071a3e189d3a7017b0003c626 100644 --- a/src/plugins/debugger/qml/qml.pri +++ b/src/plugins/debugger/qml/qml.pri @@ -1,8 +1,12 @@ HEADERS += \ $$PWD/qmlengine.h \ + $$PWD/canvasframerate.h \ SOURCES += \ $$PWD/qmlengine.cpp \ + $$PWD/canvasframerate.cpp \ + +QT += declarative FORMS += diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 6767fa75381c19b5b0fcc05460551d994a77e96c..8c987cd14a4dacfb2d681b8e17cbd11092950fdf 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -30,6 +30,7 @@ #include "qmlengine.h" #include "debuggerconstants.h" +#include "debuggerplugin.h" #include "debuggerdialogs.h" #include "debuggerstringutils.h" @@ -40,6 +41,10 @@ #include "watchhandler.h" #include "watchutils.h" +#include "canvasframerate.h" + +#include <projectexplorer/environment.h> + #include <utils/qtcassert.h> #include <QtCore/QDateTime> @@ -55,6 +60,10 @@ #include <QtGui/QToolTip> #include <QtNetwork/QTcpSocket> +#include <QtNetwork/QHostAddress> + +#include <private/qdeclarativedebug_p.h> +#include <private/qdeclarativedebugclient_p.h> #define DEBUG_QML 1 #if DEBUG_QML @@ -97,6 +106,36 @@ QString QmlEngine::QmlCommand::toString() const } +/////////////////////////////////////////////////////////////////////// +// +// QmlDebuggerClient +// +/////////////////////////////////////////////////////////////////////// + +class QmlDebuggerClient : public QDeclarativeDebugClient +{ + Q_OBJECT + +public: + QmlDebuggerClient(QDeclarativeDebugConnection *connection, QmlEngine *engine) + : QDeclarativeDebugClient(QLatin1String("Debugger"), connection) + , m_connection(connection), m_engine(engine) + { + setEnabled(true); + } + + void messageReceived(const QByteArray &data) + { + m_engine->messageReceived(data); + } + + + QDeclarativeDebugConnection *m_connection; + QmlEngine *m_engine; +}; + + + /////////////////////////////////////////////////////////////////////// // // QmlEngine @@ -109,6 +148,13 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters) m_congestion = 0; m_inAir = 0; + m_conn = 0; + m_client = 0; + m_engineQuery = 0; + m_contextQuery = 0; + + m_frameRate = 0; + m_sendTimer.setSingleShot(true); m_sendTimer.setInterval(100); // ms connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer())); @@ -128,6 +174,7 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters) //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *))) //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), // thism SLOT(socketStateChanged(QAbstractSocket::SocketState))); + } QmlEngine::~QmlEngine() @@ -153,8 +200,9 @@ void QmlEngine::socketReadyRead() void QmlEngine::socketConnected() { + qDebug() << "SOCKET CONNECTED."; showStatusMessage("Socket connected."); - m_socket->waitForConnected(2000); + //m_socket->waitForConnected(2000); //sendCommand("Locator", "redirect", "ID"); } @@ -168,6 +216,7 @@ void QmlEngine::socketError(QAbstractSocket::SocketError) QString msg = tr("%1.").arg(m_socket->errorString()); //QMessageBox::critical(q->mainWindow(), tr("Error"), msg); showStatusMessage(msg); + qDebug() << "SOCKET ERROR: " << msg; exitDebugger(); } @@ -199,19 +248,95 @@ void QmlEngine::exitDebugger() SDEBUG("QmlEngine::exitDebugger()"); } +const int serverPort = 3768; + void QmlEngine::startDebugger() { - qDebug() << "STARTING QML ENGINE"; - setState(InferiorRunningRequested); - showStatusMessage(tr("Running requested..."), 5000); -/* const DebuggerStartParameters &sp = startParameters(); + QTC_ASSERT(state() == DebuggerNotReady, setState(DebuggerNotReady)); + setState(EngineStarting); + const DebuggerStartParameters &sp = startParameters(); const int pos = sp.remoteChannel.indexOf(QLatin1Char(':')); const QString host = sp.remoteChannel.left(pos); const quint16 port = sp.remoteChannel.mid(pos + 1).toInt(); + qDebug() << "STARTING QML ENGINE" << host << port << sp.remoteChannel + << sp.executable << sp.processArgs << sp.workingDirectory; + + ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); // empty env by default + env.set("QML_DEBUG_SERVER_PORT", QString::number(serverPort)); + + connect(&m_proc, SIGNAL(error(QProcess::ProcessError)), + SLOT(handleProcError(QProcess::ProcessError))); + connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(handleProcFinished(int, QProcess::ExitStatus))); + connect(&m_proc, SIGNAL(readyReadStandardOutput()), + SLOT(readProcStandardOutput())); + connect(&m_proc, SIGNAL(readyReadStandardError()), + SLOT(readProcStandardError())); + + setState(AdapterStarting); + m_proc.setEnvironment(env.toStringList()); + m_proc.setWorkingDirectory(sp.workingDirectory); + m_proc.start(sp.executable, sp.processArgs); + //QTimer::singleShot(0, this, SLOT(runInferior())); - m_socket->connectToHost(host, port); */ + + if (!m_proc.waitForStarted()) { + setState(AdapterStartFailed); + startFailed(); + return; + } + qDebug() << "PROC STARTED."; + //m_socket->connectToHost(host, port); + //startSuccessful(); + //showStatusMessage(tr("Running requested..."), 5000); + //setState(InferiorRunning); // FIXME + + setState(AdapterStarted); + setState(InferiorStarting); + + //m_frameRate = new CanvasFrameRate(0); + //m_frameRate->show(); +} + +void QmlEngine::setupConnection() +{ + QTC_ASSERT(m_conn == 0, /**/); + m_conn = new QDeclarativeDebugConnection(this); + + connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + SLOT(connectionStateChanged())); + connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)), + SLOT(connectionError())); + connect(m_conn, SIGNAL(connected()), + SLOT(connectionConnected())); + + QTC_ASSERT(m_client == 0, /**/); + m_client = new QmlDebuggerClient(m_conn, this); + + //m_objectTreeWidget->setEngineDebug(m_client); + //m_propertiesWidget->setEngineDebug(m_client); + //m_watchTableModel->setEngineDebug(m_client); + //m_expressionWidget->setEngineDebug(m_client); + + // resetViews(); + // m_frameRateWidget->reset(m_conn); + // reloadEngines(); + + QHostAddress ha(QHostAddress::LocalHost); + + qDebug() << "CONNECTING TO " << ha.toString() << serverPort; + m_conn->connectToHost(ha, serverPort); + + if (!m_conn->waitForConnected()) { + qDebug() << "CONNECTION FAILED"; + setState(InferiorStartFailed); + startFailed(); + return; + } + + qDebug() << "CONNECTION SUCCESSFUL"; + setState(InferiorRunning); startSuccessful(); - setState(InferiorRunning); // FIXME } void QmlEngine::continueInferior() @@ -231,6 +356,7 @@ void QmlEngine::runInferior() void QmlEngine::interruptInferior() { + qDebug() << "INTERRUPT"; QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("INTERRUPT"); @@ -503,6 +629,12 @@ void QmlEngine::handleSendTimer() */ } +void QmlEngine::sendMessage(const QByteArray &msg) +{ + QTC_ASSERT(m_client, return); + m_client->sendMessage(msg); +} + void QmlEngine::sendCommandNow(const QmlCommand &cmd) { ++m_inAir; @@ -743,5 +875,131 @@ void QmlEngine::messageReceived(const QByteArray &message) } +QString QmlEngine::errorMessage(QProcess::ProcessError error) +{ + switch (error) { + case QProcess::FailedToStart: + return tr("The Gdb process failed to start. Either the " + "invoked program is missing, or you may have insufficient " + "permissions to invoke the program."); + case QProcess::Crashed: + return tr("The Gdb process crashed some time after starting " + "successfully."); + case QProcess::Timedout: + return tr("The last waitFor...() function timed out. " + "The state of QProcess is unchanged, and you can try calling " + "waitFor...() again."); + case QProcess::WriteError: + return tr("An error occurred when attempting to write " + "to the Gdb process. For example, the process may not be running, " + "or it may have closed its input channel."); + case QProcess::ReadError: + return tr("An error occurred when attempting to read from " + "the Gdb process. For example, the process may not be running."); + default: + return tr("An unknown error in the Gdb process occurred. "); + } +} + +void QmlEngine::handleProcError(QProcess::ProcessError error) +{ + showMessage(_("HANDLE QML ERROR")); + switch (error) { + case QProcess::Crashed: + break; // will get a processExited() as well + // impossible case QProcess::FailedToStart: + case QProcess::ReadError: + case QProcess::WriteError: + case QProcess::Timedout: + default: + m_proc.kill(); + setState(EngineShuttingDown, true); + plugin()->showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"), + errorMessage(error)); + break; + } +} + +void QmlEngine::handleProcFinished(int code, QProcess::ExitStatus type) +{ + showMessage(_("QML VIEWER PROCESS FINISHED, status %1, code %2").arg(type).arg(code)); + setState(DebuggerNotReady, true); +} + +void QmlEngine::readProcStandardError() +{ + qDebug() << "STD ERR" << m_proc.readAllStandardError(); + if (!m_conn) + setupConnection(); +} + +void QmlEngine::readProcStandardOutput() +{ + qDebug() << "STD ERR" << m_proc.readAllStandardOutput(); +} + +void QmlEngine::connectionStateChanged() +{ + QTC_ASSERT(m_conn, return); + QAbstractSocket::SocketState state = m_conn->state(); + qDebug() << "CONNECTION STATE: " << state; + switch (state) { + case QAbstractSocket::UnconnectedState: + { + showStatusMessage(tr("[QmlEngine] disconnected.\n\n")); + + delete m_engineQuery; + m_engineQuery = 0; + delete m_contextQuery; + m_contextQuery = 0; + +// resetViews(); + +// updateMenuActions(); + + break; + } + case QAbstractSocket::HostLookupState: + showStatusMessage(tr("[QmlEngine] resolving host...")); + break; + case QAbstractSocket::ConnectingState: + showStatusMessage(tr("[QmlEngine] connecting to debug server...")); + break; + case QAbstractSocket::ConnectedState: + showStatusMessage(tr("[QmlEngine] connected.\n")); + //setupConnection() + break; + case QAbstractSocket::ClosingState: + showStatusMessage(tr("[QmlEngine] closing...")); + break; + case QAbstractSocket::BoundState: + showStatusMessage(tr("[QmlEngine] bound state")); + break; + case QAbstractSocket::ListeningState: + showStatusMessage(tr("[QmlEngine] listening state")); + break; + default: + showStatusMessage(tr("[QmlEngine] unknown state: %1").arg(state)); + break; + } +} + +void QmlEngine::connectionError() +{ + QTC_ASSERT(m_conn, return); + showStatusMessage(tr("[QmlEngine] error: (%1) %2", "%1=error code, %2=error message") + .arg(m_conn->error()).arg(m_conn->errorString())); +} + +void QmlEngine::connectionConnected() +{ + QTC_ASSERT(m_conn, return); + showStatusMessage(tr("[QmlEngine] error: (%1) %2", "%1=error code, %2=error message") + .arg(m_conn->error()).arg(m_conn->errorString())); +} + + } // namespace Internal } // namespace Debugger + +#include "qmlengine.moc" diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 5fc3c3ca86f4db0af7ccde9ace626c162d0b7358..bec97673375b473c102a4f5cd7a9ee085257ab8e 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -36,14 +36,20 @@ #include <QtCore/QHash> #include <QtCore/QObject> #include <QtCore/QPoint> +#include <QtCore/QProcess> #include <QtCore/QQueue> #include <QtCore/QTimer> #include <QtCore/QVariant> #include <QtNetwork/QAbstractSocket> +#include <QtNetwork/QTcpSocket> QT_BEGIN_NAMESPACE class QTcpSocket; +class QDeclarativeDebugConnection; +class QDeclarativeEngineDebug; +class QDeclarativeDebugEnginesQuery; +class QDeclarativeDebugRootContextQuery; QT_END_NAMESPACE namespace Debugger { @@ -52,6 +58,8 @@ namespace Internal { class ScriptAgent; class WatchData; class QmlResponse; +class CanvasFrameRate; +class QmlDebuggerClient; class DEBUGGER_EXPORT QmlEngine : public DebuggerEngine { @@ -120,7 +128,22 @@ private: unsigned int debuggerCapabilities() const; Q_SLOT void startDebugging(); + void setupConnection(); + void sendMessage(const QByteArray &msg); + +private slots: + void handleProcFinished(int, QProcess::ExitStatus status); + void handleProcError(QProcess::ProcessError error); + void readProcStandardOutput(); + void readProcStandardError(); + + void connectionError(); + void connectionConnected(); + void connectionStateChanged(); + +private: + QString errorMessage(QProcess::ProcessError error); typedef void (QmlEngine::*QmlCommandCallback) (const QmlResponse &record, const QVariant &cookie); @@ -159,9 +182,13 @@ private: QTcpSocket *m_socket; QByteArray m_inbuffer; QList<QByteArray> m_services; + QProcess m_proc; -signals: - void sendMessage(const QByteArray &); + QDeclarativeDebugConnection *m_conn; + QmlDebuggerClient *m_client; + QDeclarativeDebugEnginesQuery *m_engineQuery; + QDeclarativeDebugRootContextQuery *m_contextQuery; + CanvasFrameRate *m_frameRate; }; } // namespace Internal