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