Commit e2159536 authored by hjk's avatar hjk

debugger: incorporate ogoffart's first shot at qml debugging

parent 112b7133
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;
return false;
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()
......@@ -542,7 +594,7 @@ QString QmlInspector::attachToQmlViewerAsExternalApp(ProjectExplorer::Project *p
customEnv.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(m_settings.externalPort()));
Debugger::DebuggerRunControl *debuggableRunControl =
createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
createDebuggerRunControl(runConfig, dlg.qmlViewerPath(), dlg.qmlViewerArguments());
return executeDebuggerRunControl(debuggableRunControl, &customEnv);
}
......@@ -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,
const QString &executableFile = QString(),
const QString &executableArguments = QString());
QString executeDebuggerRunControl(Debugger::DebuggerRunControl *debuggableRunControl, ProjectExplorer::Environment *environment);
Debugger::DebuggerRunControl *createDebuggerRunControl(
ProjectExplorer::RunConfiguration *runConfig,
const QString &executableFile = QString(),
const QString &executableArguments = QString());
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;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment