forked from qt-creator/qt-creator
debugger: incorporate ogoffart's first shot at qml debugging
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
include(debugger_dependencies.pri)
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
LIBS *= -l$$qtLibraryTarget(Debugger)
|
||||
|
||||
@@ -112,8 +112,8 @@ class WatchHandler;
|
||||
|
||||
class DebuggerEnginePrivate;
|
||||
|
||||
|
||||
class DebuggerEngine : public QObject
|
||||
// FIXME: DEBUGGER_EXPORT?
|
||||
class DEBUGGER_EXPORT DebuggerEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -204,18 +204,25 @@ void QmlEngine::startDebugger()
|
||||
qDebug() << "STARTING QML ENGINE";
|
||||
setState(InferiorRunningRequested);
|
||||
showStatusMessage(tr("Running requested..."), 5000);
|
||||
const DebuggerStartParameters &sp = startParameters();
|
||||
/* 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();
|
||||
//QTimer::singleShot(0, this, SLOT(runInferior()));
|
||||
m_socket->connectToHost(host, port);
|
||||
m_socket->connectToHost(host, port); */
|
||||
startSuccessful();
|
||||
setState(InferiorRunning); // FIXME
|
||||
}
|
||||
|
||||
void QmlEngine::continueInferior()
|
||||
{
|
||||
SDEBUG("QmlEngine::continueInferior()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("CONTINUE");
|
||||
sendMessage(reply);
|
||||
setState(InferiorRunningRequested);
|
||||
setState(InferiorRunning);
|
||||
}
|
||||
|
||||
void QmlEngine::runInferior()
|
||||
@@ -224,32 +231,59 @@ void QmlEngine::runInferior()
|
||||
|
||||
void QmlEngine::interruptInferior()
|
||||
{
|
||||
XSDEBUG("QmlEngine::interruptInferior()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("INTERRUPT");
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void QmlEngine::executeStep()
|
||||
{
|
||||
//SDEBUG("QmlEngine::executeStep()");
|
||||
SDEBUG("QmlEngine::executeStep()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("STEPINTO");
|
||||
sendMessage(reply);
|
||||
setState(InferiorRunningRequested);
|
||||
setState(InferiorRunning);
|
||||
}
|
||||
|
||||
void QmlEngine::executeStepI()
|
||||
{
|
||||
//SDEBUG("QmlEngine::executeStepI()");
|
||||
SDEBUG("QmlEngine::executeStepI()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("STEPINTO");
|
||||
sendMessage(reply);
|
||||
setState(InferiorRunningRequested);
|
||||
setState(InferiorRunning);
|
||||
}
|
||||
|
||||
void QmlEngine::executeStepOut()
|
||||
{
|
||||
//SDEBUG("QmlEngine::executeStepOut()");
|
||||
SDEBUG("QmlEngine::executeStepOut()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("STEPOUT");
|
||||
sendMessage(reply);
|
||||
setState(InferiorRunningRequested);
|
||||
setState(InferiorRunning);
|
||||
}
|
||||
|
||||
void QmlEngine::executeNext()
|
||||
{
|
||||
//SDEBUG("QmlEngine::nextExec()");
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("STEPOVER");
|
||||
sendMessage(reply);
|
||||
setState(InferiorRunningRequested);
|
||||
setState(InferiorRunning);
|
||||
SDEBUG("QmlEngine::nextExec()");
|
||||
}
|
||||
|
||||
void QmlEngine::executeNextI()
|
||||
{
|
||||
//SDEBUG("QmlEngine::executeNextI()");
|
||||
SDEBUG("QmlEngine::executeNextI()");
|
||||
}
|
||||
|
||||
void QmlEngine::executeRunToLine(const QString &fileName, int lineNumber)
|
||||
@@ -275,6 +309,8 @@ void QmlEngine::executeJumpToLine(const QString &fileName, int lineNumber)
|
||||
void QmlEngine::activateFrame(int index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
qDebug() << Q_FUNC_INFO << index;
|
||||
gotoLocation(stackHandler()->frames().value(index), true);
|
||||
}
|
||||
|
||||
void QmlEngine::selectThread(int index)
|
||||
@@ -284,6 +320,22 @@ void QmlEngine::selectThread(int index)
|
||||
|
||||
void QmlEngine::attemptBreakpointSynchronization()
|
||||
{
|
||||
BreakHandler *handler = breakHandler();
|
||||
//bool updateNeeded = false;
|
||||
QSet< QPair<QString, qint32> > breakList;
|
||||
for (int index = 0; index != handler->size(); ++index) {
|
||||
BreakpointData *data = handler->at(index);
|
||||
breakList << qMakePair(data->fileName, data->lineNumber.toInt());
|
||||
}
|
||||
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("BREAKPOINTS");
|
||||
rs << breakList;
|
||||
//qDebug() << Q_FUNC_INFO << breakList;
|
||||
sendMessage(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlEngine::loadSymbols(const QString &moduleName)
|
||||
@@ -521,10 +573,26 @@ void QmlEngine::updateLocals()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlEngine::updateWatchData(const WatchData &)
|
||||
void QmlEngine::updateWatchData(const WatchData &data)
|
||||
{
|
||||
//watchHandler()->rebuildModel();
|
||||
showStatusMessage(tr("Stopped."), 5000);
|
||||
|
||||
if (!data.name.isEmpty()) {
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("EXEC");
|
||||
rs << data.iname << data.name;
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
{
|
||||
QByteArray reply;
|
||||
QDataStream rs(&reply, QIODevice::WriteOnly);
|
||||
rs << QByteArray("WATCH_EXPRESSIONS");
|
||||
rs << watchHandler()->watchedExpressions();
|
||||
sendMessage(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlEngine::updateSubItem(const WatchData &data0)
|
||||
@@ -538,5 +606,142 @@ DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp)
|
||||
return new QmlEngine(sp);
|
||||
}
|
||||
|
||||
unsigned QmlEngine::debuggerCapabilities() const
|
||||
{
|
||||
return AddWatcherCapability;
|
||||
/*ReverseSteppingCapability | SnapshotCapability
|
||||
| AutoDerefPointersCapability | DisassemblerCapability
|
||||
| RegisterCapability | ShowMemoryCapability
|
||||
| JumpToLineCapability | ReloadModuleCapability
|
||||
| ReloadModuleSymbolsCapability | BreakOnThrowAndCatchCapability
|
||||
| ReturnFromFunctionCapability
|
||||
| CreateFullBacktraceCapability
|
||||
| WatchpointCapability
|
||||
| AddWatcherCapability;*/
|
||||
}
|
||||
|
||||
static void updateWatchDataFromVariant(const QVariant &value, WatchData &data)
|
||||
{
|
||||
switch (value.userType()) {
|
||||
case QVariant::Bool:
|
||||
data.setType(QLatin1String("Bool"), false);
|
||||
data.setValue(value.toBool() ? QLatin1String("true") : QLatin1String("false"));
|
||||
data.setHasChildren(false);
|
||||
break;
|
||||
case QVariant::Date:
|
||||
case QVariant::DateTime:
|
||||
case QVariant::Time:
|
||||
data.setType(QLatin1String("Date"), false);
|
||||
data.setValue(value.toDateTime().toString());
|
||||
data.setHasChildren(false);
|
||||
break;
|
||||
/*} else if (ob.isError()) {
|
||||
data.setType(QLatin1String("Error"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));
|
||||
} else if (ob.isFunction()) {
|
||||
data.setType(QLatin1String("Function"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));*/
|
||||
case QVariant::Invalid:{
|
||||
const QString nullValue = QLatin1String("<null>");
|
||||
data.setType(nullValue, false);
|
||||
data.setValue(nullValue);
|
||||
break;}
|
||||
case QVariant::UInt:
|
||||
case QVariant::Int:
|
||||
case QVariant::Double:
|
||||
//FIXME FLOAT
|
||||
data.setType(QLatin1String("Number"), false);
|
||||
data.setValue(QString::number(value.toDouble()));
|
||||
data.setHasChildren(false);
|
||||
break;
|
||||
/* } else if (ob.isObject()) {
|
||||
data.setType(QLatin1String("Object"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));
|
||||
} else if (ob.isQMetaObject()) {
|
||||
data.setType(QLatin1String("QMetaObject"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));
|
||||
} else if (ob.isQObject()) {
|
||||
data.setType(QLatin1String("QObject"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));
|
||||
} else if (ob.isRegExp()) {
|
||||
data.setType(QLatin1String("RegExp"), false);
|
||||
data.setValue(ob.toRegExp().pattern());
|
||||
} else if (ob.isString()) {*/
|
||||
case QVariant::String:
|
||||
data.setType(QLatin1String("String"), false);
|
||||
data.setValue(value.toString());
|
||||
/* } else if (ob.isVariant()) {
|
||||
data.setType(QLatin1String("Variant"), false);
|
||||
data.setValue(QString(QLatin1Char(' ')));
|
||||
} else if (ob.isUndefined()) {
|
||||
data.setType(QLatin1String("<undefined>"), false);
|
||||
data.setValue(QLatin1String("<unknown>"));
|
||||
data.setHasChildren(false);
|
||||
} else {*/
|
||||
default:{
|
||||
const QString unknown = QLatin1String("<unknown>");
|
||||
data.setType(unknown, false);
|
||||
data.setValue(unknown);
|
||||
data.setHasChildren(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlEngine::messageReceived(const QByteArray &message)
|
||||
{
|
||||
QByteArray rwData = message;
|
||||
QDataStream stream(&rwData, QIODevice::ReadOnly);
|
||||
|
||||
QByteArray command;
|
||||
stream >> command;
|
||||
|
||||
if(command == "STOPPED") {
|
||||
QList<QPair<QString, QPair<QString, qint32> > > backtrace;
|
||||
QList<QPair<QString, QVariant> > watches;
|
||||
stream >> backtrace >> watches;
|
||||
|
||||
QList<StackFrame> stackFrames;
|
||||
typedef QPair<QString, QPair<QString, qint32> > Iterator;
|
||||
foreach (const Iterator &it, backtrace) {
|
||||
StackFrame frame;
|
||||
frame.file = it.second.first;
|
||||
frame.line = it.second.second;
|
||||
frame.function = it.first;
|
||||
stackFrames << frame;
|
||||
}
|
||||
|
||||
gotoLocation(stackFrames.value(0), true);
|
||||
stackHandler()->setFrames(stackFrames);
|
||||
|
||||
watchHandler()->beginCycle();
|
||||
|
||||
typedef QPair<QString, QVariant > Iterator2;
|
||||
foreach (const Iterator2 &it, watches) {
|
||||
WatchData data;
|
||||
data.name = it.first;
|
||||
data.exp = it.first.toUtf8();
|
||||
data.iname = watchHandler()->watcherName(data.exp);
|
||||
updateWatchDataFromVariant(it.second, data);
|
||||
watchHandler()->insertData(data);
|
||||
}
|
||||
|
||||
watchHandler()->endCycle();
|
||||
|
||||
setState(InferiorStopping);
|
||||
setState(InferiorStopped);
|
||||
} else if (command == "RESULT") {
|
||||
WatchData data;
|
||||
QVariant variant;
|
||||
stream >> data.iname >> data.name >> variant;
|
||||
data.exp = data.name.toUtf8();
|
||||
updateWatchDataFromVariant(variant, data);
|
||||
qDebug() << Q_FUNC_INFO << this << data.name << data.iname << variant;
|
||||
watchHandler()->insertData(data);
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
@@ -30,14 +30,13 @@
|
||||
#ifndef DEBUGGER_QMLENGINE_H
|
||||
#define DEBUGGER_QMLENGINE_H
|
||||
|
||||
#include "debuggerengine.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPoint>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QQueue>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
@@ -47,9 +46,6 @@ QT_BEGIN_NAMESPACE
|
||||
class QTcpSocket;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "debuggerengine.h"
|
||||
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
@@ -57,7 +53,7 @@ class ScriptAgent;
|
||||
class WatchData;
|
||||
class QmlResponse;
|
||||
|
||||
class QmlEngine : public DebuggerEngine
|
||||
class DEBUGGER_EXPORT QmlEngine : public DebuggerEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -65,6 +61,9 @@ public:
|
||||
explicit QmlEngine(const DebuggerStartParameters &startParameters);
|
||||
~QmlEngine();
|
||||
|
||||
void messageReceived(const QByteArray &message);
|
||||
using DebuggerEngine::setState;
|
||||
|
||||
private:
|
||||
// DebuggerEngine implementation
|
||||
void executeStep();
|
||||
@@ -118,7 +117,8 @@ private:
|
||||
void handleRunControlGetChildren(const QmlResponse &response, const QVariant &);
|
||||
void handleSysMonitorGetChildren(const QmlResponse &response, const QVariant &);
|
||||
|
||||
private:
|
||||
unsigned int debuggerCapabilities() const;
|
||||
|
||||
Q_SLOT void startDebugging();
|
||||
|
||||
typedef void (QmlEngine::*QmlCommandCallback)
|
||||
@@ -159,6 +159,9 @@ private:
|
||||
QTcpSocket *m_socket;
|
||||
QByteArray m_inbuffer;
|
||||
QList<QByteArray> m_services;
|
||||
|
||||
signals:
|
||||
void sendMessage(const QByteArray &);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -176,6 +176,8 @@ public:
|
||||
|
||||
void addTypeFormats(const QString &type, const QStringList &formats);
|
||||
|
||||
QByteArray watcherName(const QByteArray &exp);
|
||||
|
||||
private:
|
||||
friend class WatchModel;
|
||||
|
||||
@@ -194,7 +196,6 @@ private:
|
||||
EditHandlers m_editHandlers;
|
||||
|
||||
QHash<QByteArray, int> m_watcherNames;
|
||||
QByteArray watcherName(const QByteArray &exp);
|
||||
QHash<QString, int> m_typeFormats;
|
||||
QHash<QByteArray, int> m_individualFormats; // Indexed by iname.
|
||||
QHash<QString, QStringList> m_reportedTypeFormats;
|
||||
|
||||
@@ -44,7 +44,10 @@
|
||||
#include <debugger/debuggerplugin.h>
|
||||
#include <debugger/debuggerrunner.h>
|
||||
#include <debugger/debuggeruiswitcher.h>
|
||||
#include <debugger/watchdata.h>
|
||||
#include <debugger/watchhandler.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/styledbar.h>
|
||||
#include <utils/fancymainwindow.h>
|
||||
|
||||
@@ -77,11 +80,19 @@
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <private/qdeclarativedebug_p.h>
|
||||
#include <private/qdeclarativedebugclient_p.h>
|
||||
|
||||
#include "debugger/qml/qmlengine.h"
|
||||
//#include "debugger/debuggermanager.h"
|
||||
#include "debugger/stackframe.h"
|
||||
#include "debugger/stackhandler.h"
|
||||
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QtPlugin>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <QtGui/QToolButton>
|
||||
#include <QtGui/QToolBar>
|
||||
@@ -98,6 +109,40 @@
|
||||
|
||||
using namespace Qml;
|
||||
|
||||
using namespace Debugger;
|
||||
using namespace Debugger::Internal;
|
||||
|
||||
class DebuggerClient : public QDeclarativeDebugClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DebuggerClient(QDeclarativeDebugConnection *client, QmlEngine *engine)
|
||||
: QDeclarativeDebugClient(QLatin1String("Debugger"), client)
|
||||
, connection(client), engine(engine)
|
||||
{
|
||||
QObject::connect(engine, SIGNAL(sendMessage(QByteArray)),
|
||||
this, SLOT(slotSendMessage(QByteArray)));
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
void messageReceived(const QByteArray &data)
|
||||
{
|
||||
engine->messageReceived(data);
|
||||
}
|
||||
|
||||
|
||||
QDeclarativeDebugConnection *connection;
|
||||
QmlEngine *engine;
|
||||
|
||||
public slots:
|
||||
void slotSendMessage(const QByteArray &message)
|
||||
{
|
||||
QDeclarativeDebugClient::sendMessage(message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Qml {
|
||||
|
||||
namespace Internal {
|
||||
@@ -266,10 +311,17 @@ bool QmlInspector::connectToViewer()
|
||||
emit statusMessage(tr("[Inspector] set to connect to debug server %1:%2").arg(host).arg(port));
|
||||
m_conn->connectToHost(host, port);
|
||||
// blocks until connected; if no connection is available, will fail immediately
|
||||
if (m_conn->waitForConnected())
|
||||
return true;
|
||||
|
||||
if (!m_conn->waitForConnected())
|
||||
return false;
|
||||
|
||||
QTC_ASSERT(m_debuggerRunControl, return false);
|
||||
QmlEngine *engine = qobject_cast<QmlEngine *>(m_debuggerRunControl->engine());
|
||||
QTC_ASSERT(engine, return false);
|
||||
|
||||
(void) new DebuggerClient(m_conn, engine);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlInspector::disconnectFromViewer()
|
||||
@@ -855,6 +907,7 @@ QmlInspector *QmlInspector::instance()
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
} // Qml
|
||||
}
|
||||
|
||||
|
||||
#include "qmlinspector.moc"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLINSPECTORMODE_H
|
||||
#define QMLINSPECTORMODE_H
|
||||
|
||||
@@ -38,12 +39,11 @@
|
||||
#include <QtCore/QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDockWidget;
|
||||
class QToolButton;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QSpinBox;
|
||||
class QLabel;
|
||||
class QToolButton;
|
||||
|
||||
class QDeclarativeEngineDebug;
|
||||
class QDeclarativeDebugConnection;
|
||||
@@ -110,8 +110,8 @@ public:
|
||||
|
||||
static QmlInspector *instance();
|
||||
bool canEditProperty(const QString &propertyType);
|
||||
QDeclarativeDebugExpressionQuery *executeExpression(int objectDebugId, const QString &objectId,
|
||||
const QString &propertyName, const QVariant &value);
|
||||
QDeclarativeDebugExpressionQuery *executeExpression(int objectDebugId,
|
||||
const QString &objectId, const QString &propertyName, const QVariant &value);
|
||||
|
||||
signals:
|
||||
void statusMessage(const QString &text);
|
||||
@@ -135,10 +135,12 @@ private slots:
|
||||
|
||||
private:
|
||||
void updateMenuActions();
|
||||
Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
|
||||
Debugger::DebuggerRunControl *createDebuggerRunControl(
|
||||
ProjectExplorer::RunConfiguration *runConfig,
|
||||
const QString &executableFile = QString(),
|
||||
const QString &executableArguments = QString());
|
||||
QString executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment);
|
||||
QString executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl,
|
||||
ProjectExplorer::Environment *environment);
|
||||
QString attachToQmlViewerAsExternalApp(ProjectExplorer::Project *project);
|
||||
QString attachToExternalCppAppWithQml(ProjectExplorer::Project *project);
|
||||
|
||||
@@ -185,6 +187,7 @@ private:
|
||||
bool m_connectionInitialized;
|
||||
bool m_simultaneousCppAndQmlDebugMode;
|
||||
DebugMode m_debugMode;
|
||||
Debugger::DebuggerRunControl *m_debuggerRunControl;
|
||||
|
||||
static QmlInspector *m_instance;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user