From 17a2f6711e8bff73a2fb178a3be623daa97acb0b Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Wed, 9 Jun 2010 16:13:47 +0200 Subject: [PATCH] debugger: start second shot at Qml debugging --- src/plugins/debugger/debugger.pro | 1 + src/plugins/debugger/debuggermanager.cpp | 30 +- src/plugins/debugger/debuggermanager.h | 4 + src/plugins/debugger/debuggerplugin.cpp | 10 +- src/plugins/debugger/debuggerrunner.cpp | 7 +- src/plugins/debugger/qml/qml.pri | 9 + src/plugins/debugger/qml/qmlengine.cpp | 544 +++++++++++++++++++++++ src/plugins/debugger/qml/qmlengine.h | 168 +++++++ 8 files changed, 759 insertions(+), 14 deletions(-) create mode 100644 src/plugins/debugger/qml/qml.pri create mode 100644 src/plugins/debugger/qml/qmlengine.cpp create mode 100644 src/plugins/debugger/qml/qmlengine.h diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 57b53ead9e8..528495e55d9 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -109,6 +109,7 @@ include(cdb/cdb.pri) include(gdb/gdb.pri) include(script/script.pri) include(pdb/pdb.pri) +include(qml/qml.pri) include(tcf/tcf.pri) include(shared/shared.pri) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 66e9cf6151c..b4e91393de0 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -160,6 +160,7 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *parent); IDebuggerEngine *createScriptEngine(DebuggerManager *parent); IDebuggerEngine *createPdbEngine(DebuggerManager *parent); IDebuggerEngine *createTcfEngine(DebuggerManager *parent); +IDebuggerEngine *createQmlEngine(DebuggerManager *parent); // The createCdbEngine function takes a list of options pages it can add to. // This allows for having a "enabled" toggle on the page independently @@ -254,6 +255,7 @@ static Debugger::Internal::IDebuggerEngine *gdbEngine = 0; static Debugger::Internal::IDebuggerEngine *scriptEngine = 0; static Debugger::Internal::IDebuggerEngine *cdbEngine = 0; static Debugger::Internal::IDebuggerEngine *pdbEngine = 0; +static Debugger::Internal::IDebuggerEngine *qmlEngine = 0; static Debugger::Internal::IDebuggerEngine *tcfEngine = 0; struct DebuggerManagerPrivate @@ -351,6 +353,7 @@ DebuggerManager::~DebuggerManager() doDelete(gdbEngine); doDelete(cdbEngine); doDelete(tcfEngine); + doDelete(qmlEngine); doDelete(d->m_breakHandler); doDelete(d->m_threadsHandler); @@ -359,11 +362,6 @@ DebuggerManager::~DebuggerManager() doDelete(d->m_snapshotHandler); doDelete(d->m_stackHandler); doDelete(d->m_watchHandler); - - doDelete(gdbEngine); - doDelete(scriptEngine); - doDelete(cdbEngine); - doDelete(tcfEngine); # undef doDelete DebuggerManagerPrivate::instance = 0; delete d; @@ -692,6 +690,11 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTy tcfEngine->addOptionPages(&rc); } + if (enabledTypeFlags & QmlEngineType) { + qmlEngine = createQmlEngine(this); + //qmlEngine->addOptionPages(&rc); + } + d->m_engine = 0; STATE_DEBUG(gdbEngine << cdbEngine << scriptEngine << pdbEngine << rc.size()); @@ -976,6 +979,15 @@ static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable, QString *errorMessage, QString *settingsIdHint) { + if (executable.endsWith(_("qmlviewer"))) { + qDebug() << "HERE"; + if (!qmlEngine) { + *errorMessage = msgEngineNotAvailable("Qml Engine"); + return 0; + } + return qmlEngine; + } + if (executable.endsWith(_(".js"))) { if (!scriptEngine) { *errorMessage = msgEngineNotAvailable("Script Engine"); @@ -1016,7 +1028,8 @@ static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable, // We need the CDB debugger in order to be able to debug VS // executables - if (!DebuggerManager::instance()->checkDebugConfiguration(ProjectExplorer::ToolChain::MSVC, errorMessage, 0 , settingsIdHint)) + if (!DebuggerManager::instance()->checkDebugConfiguration( + ProjectExplorer::ToolChain::MSVC, errorMessage, 0, settingsIdHint)) return 0; return cdbEngine; #endif @@ -1049,6 +1062,7 @@ static IDebuggerEngine *debuggerEngineForMode(DebuggerStartMode startMode, QStri void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp) { + qDebug() << "TARGET: " << sp->executable; if (d->m_state != DebuggerNotReady) return; d->m_startParameters = sp; @@ -1067,7 +1081,9 @@ void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp) // Figure out engine: toolchain, executable, attach or default const DebuggerStartMode startMode = sp->startMode; - if (sp->executable.endsWith(_(".js"))) + if (sp->executable.endsWith(_("qmlviewer"))) + d->m_engine = qmlEngine; + else if (sp->executable.endsWith(_(".js"))) d->m_engine = scriptEngine; else if (sp->executable.endsWith(_(".py"))) d->m_engine = pdbEngine; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 0210b706c53..74be97a9c65 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -95,6 +95,7 @@ class CdbDumperInitThread; class CdbExceptionLoggerEventCallback; class GdbEngine; class TcfEngine; +class QmlEngine; class CdbDebugEngine; class CdbDebugEnginePrivate; class TrkGdbAdapter; @@ -145,11 +146,13 @@ enum DebuggerEngineTypeFlags CdbEngineType = 0x04, PdbEngineType = 0x08, TcfEngineType = 0x10, + QmlEngineType = 0x20, AllEngineTypes = GdbEngineType | ScriptEngineType | CdbEngineType | PdbEngineType | TcfEngineType + | QmlEngineType }; QDebug operator<<(QDebug d, DebuggerState state); @@ -178,6 +181,7 @@ public: friend class Internal::ScriptEngine; friend class Internal::PdbEngine; friend class Internal::TcfEngine; + friend class Internal::QmlEngine; friend class Internal::CdbDebugEngine; friend class Internal::CdbDebugEnginePrivate; friend class Internal::TrkGdbAdapter; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 7a625b45bba..45ee41015ae 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -637,11 +637,15 @@ static bool parseArgument(QStringList::const_iterator &it, *enabledEngines &= ~Debugger::GdbEngineType; return true; } + if (option == _("-disable-qmldb")) { + *enabledEngines &= ~Debugger::QmlEngineType; + return true; + } if (option == _("-disable-sdb")) { *enabledEngines &= ~Debugger::ScriptEngineType; return true; } - if (option == QLatin1String("-disable-tcf")) { + if (option == _("-disable-tcf")) { *enabledEngines &= ~TcfEngineType; return true; } @@ -1358,7 +1362,6 @@ void DebuggerPlugin::languageChanged(const QString &language) m_attachCoreAction->setVisible(debuggerIsCPP); m_startRemoteAction->setVisible(debuggerIsCPP); m_detachAction->setVisible(debuggerIsCPP); - } void DebuggerPlugin::writeSettings() const @@ -1398,12 +1401,9 @@ void DebuggerPlugin::onModeChanged(IMode *mode) if (isCurrentProjectCppBased()) m_uiSwitcher->setActiveLanguage(LANG_CPP); - } } - - void DebuggerPlugin::showSettingsDialog() { Core::ICore::instance()->showOptionsDialog( diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 9ee192f6a31..d7c606dc2e0 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -48,6 +48,7 @@ namespace Debugger { namespace Internal { +using ProjectExplorer::BuildConfiguration; using ProjectExplorer::RunConfiguration; using ProjectExplorer::RunControl; using ProjectExplorer::LocalApplicationRunConfiguration; @@ -65,6 +66,7 @@ DebuggerRunControlFactory::DebuggerRunControlFactory(DebuggerManager *manager) bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const { +// return mode == ProjectExplorer::Constants::DEBUGMODE; return mode == ProjectExplorer::Constants::DEBUGMODE && qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration); } @@ -130,8 +132,9 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager, break; } if (runConfiguration->target()->project()) { - m_startParameters->buildDirectory = - runConfiguration->target()->activeBuildConfiguration()->buildDirectory(); + BuildConfiguration *bc = runConfiguration->target()->activeBuildConfiguration(); + if (bc) + m_startParameters->buildDirectory = bc->buildDirectory(); } m_startParameters->useTerminal = runConfiguration->runMode() == LocalApplicationRunConfiguration::Console; diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri new file mode 100644 index 00000000000..dc9d548c57b --- /dev/null +++ b/src/plugins/debugger/qml/qml.pri @@ -0,0 +1,9 @@ +HEADERS += \ + $$PWD/qmlengine.h \ + +SOURCES += \ + $$PWD/qmlengine.cpp \ + +FORMS += + +RESOURCES += diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp new file mode 100644 index 00000000000..3ff65a1dfe5 --- /dev/null +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -0,0 +1,544 @@ +/************************************************************************** +** +** 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 "qmlengine.h" + +#include "debuggerstringutils.h" +#include "debuggerdialogs.h" +#include "breakhandler.h" +#include "debuggerconstants.h" +#include "debuggermanager.h" +#include "moduleshandler.h" +#include "registerhandler.h" +#include "stackhandler.h" +#include "watchhandler.h" +#include "watchutils.h" +#include "moduleshandler.h" + +#include <utils/qtcassert.h> + +#include <QtCore/QDateTime> +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QTimer> + +#include <QtGui/QAction> +#include <QtGui/QApplication> +#include <QtGui/QMainWindow> +#include <QtGui/QMessageBox> +#include <QtGui/QToolTip> + +#include <QtNetwork/QTcpSocket> + +#define DEBUG_QML 1 +#if DEBUG_QML +# define SDEBUG(s) qDebug() << s +#else +# define SDEBUG(s) +#endif +# define XSDEBUG(s) qDebug() << s + +#define CB(callback) &QmlEngine::callback, STRINGIFY(callback) + +//#define USE_CONGESTION_CONTROL + + +namespace Debugger { +namespace Internal { + + +class QmlResponse +{ +public: + QmlResponse() {} + QmlResponse(const QByteArray &data_) : data(data_) {} + + QString toString() const { return data; } + + QByteArray data; +}; + +/////////////////////////////////////////////////////////////////////// +// +// QmlCommand +// +/////////////////////////////////////////////////////////////////////// + + +QString QmlEngine::QmlCommand::toString() const +{ + return quoteUnprintableLatin1(command); +} + + +/////////////////////////////////////////////////////////////////////// +// +// QmlEngine +// +/////////////////////////////////////////////////////////////////////// + +QmlEngine::QmlEngine(DebuggerManager *manager) + : IDebuggerEngine(manager) +{ + m_congestion = 0; + m_inAir = 0; + + m_sendTimer.setSingleShot(true); + m_sendTimer.setInterval(100); // ms + connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer())); + + m_socket = new QTcpSocket(this); + connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected())); + connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(socketError(QAbstractSocket::SocketError))); + + //void aboutToClose () + //void bytesWritten ( qint64 bytes ) + //void readChannelFinished () + connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead())); + + //connect(m_socket, SIGNAL(hostFound()) + //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *))) + //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + // thism SLOT(socketStateChanged(QAbstractSocket::SocketState))); +} + +QmlEngine::~QmlEngine() +{ +} + +void QmlEngine::socketReadyRead() +{ + //XSDEBUG("QmlEngine::socketReadyRead()"); + m_inbuffer.append(m_socket->readAll()); + int pos = 0; + while (1) { + // the "\3" is followed by either "\1" or "\2" + int next = m_inbuffer.indexOf("\3", pos); + //qDebug() << "pos: " << pos << "next: " << next; + if (next == -1) + break; + handleResponse(m_inbuffer.mid(pos, next - pos)); + pos = next + 2; + } + m_inbuffer.clear(); +} + +void QmlEngine::socketConnected() +{ + showStatusMessage("Socket connected."); + m_socket->waitForConnected(2000); + //sendCommand("Locator", "redirect", "ID"); +} + +void QmlEngine::socketDisconnected() +{ + XSDEBUG("FIXME: QmlEngine::socketDisconnected()"); +} + +void QmlEngine::socketError(QAbstractSocket::SocketError) +{ + QString msg = tr("%1.").arg(m_socket->errorString()); + //QMessageBox::critical(q->mainWindow(), tr("Error"), msg); + showStatusMessage(msg); + manager()->notifyInferiorExited(); +} + +void QmlEngine::executeDebuggerCommand(const QString &command) +{ + QByteArray cmd = command.toUtf8(); + cmd = cmd.mid(cmd.indexOf(' ') + 1); + QByteArray null; + null.append('\0'); + // FIXME: works for single-digit escapes only + cmd.replace("\\0", null); + cmd.replace("\\1", "\1"); + cmd.replace("\\3", "\3"); + QmlCommand tcf; + tcf.command = cmd; + enqueueCommand(tcf); +} + +void QmlEngine::shutdown() +{ + m_congestion = 0; + m_inAir = 0; + m_services.clear(); + exitDebugger(); +} + +void QmlEngine::exitDebugger() +{ + SDEBUG("QmlEngine::exitDebugger()"); + manager()->notifyInferiorExited(); +} + +void QmlEngine::startDebugger(const DebuggerStartParametersPtr &sp) +{ + qDebug() << "STARTING QML ENGINE"; + setState(InferiorRunningRequested); + showStatusMessage(tr("Running requested..."), 5000); + 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); + emit startSuccessful(); +} + +void QmlEngine::continueInferior() +{ + SDEBUG("QmlEngine::continueInferior()"); +} + +void QmlEngine::runInferior() +{ +} + +void QmlEngine::interruptInferior() +{ + XSDEBUG("QmlEngine::interruptInferior()"); +} + +void QmlEngine::executeStep() +{ + //SDEBUG("QmlEngine::executeStep()"); +} + +void QmlEngine::executeStepI() +{ + //SDEBUG("QmlEngine::executeStepI()"); +} + +void QmlEngine::executeStepOut() +{ + //SDEBUG("QmlEngine::executeStepOut()"); +} + +void QmlEngine::executeNext() +{ + //SDEBUG("QmlEngine::nextExec()"); +} + +void QmlEngine::executeNextI() +{ + //SDEBUG("QmlEngine::executeNextI()"); +} + +void QmlEngine::executeRunToLine(const QString &fileName, int lineNumber) +{ + Q_UNUSED(fileName) + Q_UNUSED(lineNumber) + SDEBUG("FIXME: QmlEngine::executeRunToLine()"); +} + +void QmlEngine::executeRunToFunction(const QString &functionName) +{ + Q_UNUSED(functionName) + XSDEBUG("FIXME: QmlEngine::executeRunToFunction()"); +} + +void QmlEngine::executeJumpToLine(const QString &fileName, int lineNumber) +{ + Q_UNUSED(fileName) + Q_UNUSED(lineNumber) + XSDEBUG("FIXME: QmlEngine::executeJumpToLine()"); +} + +void QmlEngine::activateFrame(int index) +{ + Q_UNUSED(index) +} + +void QmlEngine::selectThread(int index) +{ + Q_UNUSED(index) +} + +void QmlEngine::attemptBreakpointSynchronization() +{ +} + +void QmlEngine::loadSymbols(const QString &moduleName) +{ + Q_UNUSED(moduleName) +} + +void QmlEngine::loadAllSymbols() +{ +} + +void QmlEngine::reloadModules() +{ +} + +void QmlEngine::requestModuleSymbols(const QString &moduleName) +{ + Q_UNUSED(moduleName) +} + + +void QmlEngine::handleResponse(const QByteArray &response) +{ + Q_UNUSED(response); +/* + static QTime lastTime; + + //debugMessage(_(" "), currentTime()); + QList<QByteArray> parts = response.split('\0'); + if (parts.size() < 2 || !parts.last().isEmpty()) { + SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts); + //if (response.isEmpty()) + acknowledgeResult(); + return; + } + parts.removeLast(); // always empty + QByteArray tag = parts.at(0); + int n = parts.size(); + if (n == 2 && tag == "N") { // unidentified command + int token = parts.at(1).toInt(); + QmlCommand tcf = m_cookieForToken[token]; + SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString()); + showDebuggerOutput(LogOutput, QString::number(token) + "^" + + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response)); + acknowledgeResult(); + } else if (n == 2 && tag == "F") { // flow control + m_congestion = parts.at(1).toInt(); + SDEBUG("CONGESTION: " << m_congestion); + } else if (n == 4 && tag == "R") { // result data + acknowledgeResult(); + int token = parts.at(1).toInt(); + QByteArray message = parts.at(2); + QmlResponse data(parts.at(3)); + showDebuggerOutput(LogOutput, QString("%1^%2%3").arg(token) + .arg(quoteUnprintableLatin1(response)) + .arg(QString::fromUtf8(data.toString()))); + QmlCommand tcf = m_cookieForToken[token]; + QmlResponse result(data); + SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response)); + if (tcf.callback) + (this->*(tcf.callback))(result, tcf.cookie); + } else if (n == 3 && tag == "P") { // progress data (partial result) + //int token = parts.at(1).toInt(); + QByteArray data = parts.at(2); + SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response)); + } else if (n == 4 && tag == "E") { // an event + QByteArray service = parts.at(1); + QByteArray eventName = parts.at(2); + QmlResponse data(parts.at(3)); + if (eventName != "peerHeartBeat") + SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response) + << data.toString()); + if (service == "Locator" && eventName == "Hello") { + m_services.clear(); + foreach (const QmlResponse &service, data.children()) + m_services.append(service.data()); + QTimer::singleShot(0, this, SLOT(startDebugging())); + } + } else { + SDEBUG("UNKNOWN RESPONSE PACKET:" + << quoteUnprintableLatin1(response) << parts); + } +*/ +} + +void QmlEngine::startDebugging() +{ + qDebug() << "START"; +} + +void QmlEngine::postCommand(const QByteArray &cmd, + QmlCommandCallback callback, const char *callbackName) +{ +/* + static int token = 20; + ++token; + + //const char marker_eom = -1; + //const char marker_eos = -2; + //const char marker_null = -3; + + QByteArray ba = "C"; + ba.append('\0'); + ba.append(QByteArray::number(token)); + ba.append('\0'); + ba.append(cmd); + ba.append('\0'); + ba.append('\3'); + ba.append('\1'); + + QmlCommand tcf; + tcf.command = ba; + tcf.callback = callback; + tcf.callbackName = callbackName; + tcf.token = token; + + m_cookieForToken[token] = tcf; + + enqueueCommand(tcf); +*/ +} + +// Congestion control does not seem to work that way. Basically it's +// already too late when we get a flow control packet +void QmlEngine::enqueueCommand(const QmlCommand &cmd) +{ +/* +#ifdef USE_CONGESTION_CONTROL + // congestion controled + if (m_congestion <= 0 && m_sendQueue.isEmpty()) { + //SDEBUG("DIRECT SEND" << cmd.toString()); + sendCommandNow(cmd); + } else { + SDEBUG("QUEUE " << cmd.toString()); + m_sendQueue.enqueue(cmd); + m_sendTimer.start(); + } +#else + // synchrounously + if (m_inAir == 0) + sendCommandNow(cmd); + else + m_sendQueue.enqueue(cmd); +#endif +*/ +} + +void QmlEngine::handleSendTimer() +{ +/* + QTC_ASSERT(!m_sendQueue.isEmpty(), return); + + if (m_congestion > 0) { + // not ready... + SDEBUG("WAITING FOR CONGESTION TO GO DOWN..."); + m_sendTimer.start(); + } else { + // go! + sendCommandNow(m_sendQueue.dequeue()); + } +*/ +} + +void QmlEngine::sendCommandNow(const QmlCommand &cmd) +{ + ++m_inAir; + int result = m_socket->write(cmd.command); + Q_UNUSED(result) + m_socket->flush(); + showDebuggerInput(LogInput, QString::number(cmd.token) + " " + cmd.toString()); + SDEBUG("SEND " << cmd.toString()); //<< " " << QString::number(result)); +} + +void QmlEngine::acknowledgeResult() +{ +#if !defined(USE_CONGESTION_CONTROL) + QTC_ASSERT(m_inAir == 1, /**/); + m_inAir = 0; + if (!m_sendQueue.isEmpty()) + sendCommandNow(m_sendQueue.dequeue()); +#endif +} + +void QmlEngine::handleRunControlSuspend(const QmlResponse &data, const QVariant &) +{ + SDEBUG("HANDLE RESULT" << data.toString()); +} + +void QmlEngine::handleRunControlGetChildren(const QmlResponse &data, const QVariant &) +{ + SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString()); +} + +void QmlEngine::handleSysMonitorGetChildren(const QmlResponse &data, const QVariant &) +{ + SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString()); +} + + +////////////////////////////////////////////////////////////////////// +// +// Tooltip specific stuff +// +////////////////////////////////////////////////////////////////////// + +static WatchData m_toolTip; +static QPoint m_toolTipPos; +static QHash<QString, WatchData> m_toolTipCache; + +void QmlEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos) +{ + Q_UNUSED(mousePos) + Q_UNUSED(editor) + Q_UNUSED(cursorPos) +} + +////////////////////////////////////////////////////////////////////// +// +// Watch specific stuff +// +////////////////////////////////////////////////////////////////////// + +void QmlEngine::assignValueInDebugger(const QString &expression, + const QString &value) +{ + XSDEBUG("ASSIGNING: " << expression + '=' + value); + updateLocals(); +} + +void QmlEngine::updateLocals() +{ +} + +void QmlEngine::updateWatchData(const WatchData &) +{ + //qq->watchHandler()->rebuildModel(); + showStatusMessage(tr("Stopped."), 5000); +} + +void QmlEngine::updateSubItem(const WatchData &data0) +{ + Q_UNUSED(data0) + QTC_ASSERT(false, return); +} + +void QmlEngine::debugMessage(const QString &msg) +{ + showDebuggerOutput(LogDebug, msg); +} + +IDebuggerEngine *createQmlEngine(DebuggerManager *manager) +{ + return new QmlEngine(manager); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h new file mode 100644 index 00000000000..3b85c3c9dbc --- /dev/null +++ b/src/plugins/debugger/qml/qmlengine.h @@ -0,0 +1,168 @@ +/************************************************************************** +** +** 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 DEBUGGER_QMLENGINE_H +#define DEBUGGER_QMLENGINE_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> + +#include <QtNetwork/QAbstractSocket> + +QT_BEGIN_NAMESPACE +class QTcpSocket; +QT_END_NAMESPACE + +#include "idebuggerengine.h" +#include "debuggermanager.h" + +namespace Debugger { +namespace Internal { + +class ScriptAgent; +class WatchData; +class QmlResponse; + +class QmlEngine : public IDebuggerEngine +{ + Q_OBJECT + +public: + explicit QmlEngine(DebuggerManager *parent); + ~QmlEngine(); + +private: + // IDebuggerEngine implementation + void executeStep(); + void executeStepOut(); + void executeNext(); + void executeStepI(); + void executeNextI(); + + void shutdown(); + void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); + void startDebugger(const DebuggerStartParametersPtr &sp); + void exitDebugger(); + + void continueInferior(); + Q_SLOT void runInferior(); + void interruptInferior(); + + void executeRunToLine(const QString &fileName, int lineNumber); + void executeRunToFunction(const QString &functionName); + void executeJumpToLine(const QString &fileName, int lineNumber); + + void activateFrame(int index); + void selectThread(int index); + + void attemptBreakpointSynchronization(); + + void assignValueInDebugger(const QString &expr, const QString &value); + void executeDebuggerCommand(const QString & command); + + void loadSymbols(const QString &moduleName); + void loadAllSymbols(); + void requestModuleSymbols(const QString &moduleName); + void reloadModules(); + void reloadRegisters() {} + void reloadSourceFiles() {} + void reloadFullStack() {} + + bool supportsThreads() const { return true; } + void maybeBreakNow(bool byFunction); + void updateWatchData(const WatchData &data); + void updateLocals(); + void updateSubItem(const WatchData &data); + + Q_SLOT void socketConnected(); + Q_SLOT void socketDisconnected(); + Q_SLOT void socketError(QAbstractSocket::SocketError); + Q_SLOT void socketReadyRead(); + + void handleResponse(const QByteArray &ba); + void handleRunControlSuspend(const QmlResponse &response, const QVariant &); + void handleRunControlGetChildren(const QmlResponse &response, const QVariant &); + void handleSysMonitorGetChildren(const QmlResponse &response, const QVariant &); + +private: + Q_SLOT void startDebugging(); + + typedef void (QmlEngine::*QmlCommandCallback) + (const QmlResponse &record, const QVariant &cookie); + + struct QmlCommand + { + QmlCommand() : flags(0), token(-1), callback(0), callbackName(0) {} + + QString toString() const; + + int flags; + int token; + QmlCommandCallback callback; + const char *callbackName; + QByteArray command; + QVariant cookie; + }; + + void postCommand(const QByteArray &cmd, + QmlCommandCallback callback = 0, const char *callbackName = 0); + void sendCommandNow(const QmlCommand &command); + void debugMessage(const QString &msg); + + QHash<int, QmlCommand> m_cookieForToken; + + QQueue<QmlCommand> m_sendQueue; + + // timer based congestion control. does not seem to work well. + void enqueueCommand(const QmlCommand &command); + Q_SLOT void handleSendTimer(); + int m_congestion; + QTimer m_sendTimer; + + // synchrounous communication + void acknowledgeResult(); + int m_inAir; + + QTcpSocket *m_socket; + QByteArray m_inbuffer; + QList<QByteArray> m_services; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_QMLENGINE_H -- GitLab