qmladapter.cpp 11.4 KB
Newer Older
Lasse Holmstedt's avatar
Lasse Holmstedt committed
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
Lasse Holmstedt's avatar
Lasse Holmstedt committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
Lasse Holmstedt's avatar
Lasse Holmstedt committed
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
Lasse Holmstedt's avatar
Lasse Holmstedt committed
30 31 32 33
**
**************************************************************************/

#include "qmladapter.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
34

35 36
#include "qscriptdebuggerclient.h"
#include "qmlv8debuggerclient.h"
Lasse Holmstedt's avatar
Lasse Holmstedt committed
37 38
#include "qmljsprivateapi.h"

39
#include "qmlengine.h"
Lasse Holmstedt's avatar
Lasse Holmstedt committed
40

41 42 43
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h>

44 45
#include <qmljsdebugclient/qdebugmessageclient.h>

46 47
#include <QTimer>
#include <QDebug>
48
#include <QWeakPointer>
Lasse Holmstedt's avatar
Lasse Holmstedt committed
49 50

namespace Debugger {
hjk's avatar
hjk committed
51
namespace Internal {
52

hjk's avatar
hjk committed
53 54 55 56 57 58
class QmlAdapterPrivate
{
public:
    explicit QmlAdapterPrivate(DebuggerEngine *engine)
        : m_engine(engine)
        , m_qmlClient(0)
59
        , m_engineDebugClient(0)
hjk's avatar
hjk committed
60
        , m_conn(0)
61
        , m_currentSelectedDebugId(-1)
62
        , m_msgClient(0)
hjk's avatar
hjk committed
63
    {
64 65
        m_connectionTimer.setInterval(4000);
        m_connectionTimer.setSingleShot(true);
hjk's avatar
hjk committed
66
    }
67 68

    QWeakPointer<DebuggerEngine> m_engine;
69
    QmlDebuggerClient *m_qmlClient;
70
    QmlJsDebugClient::QmlEngineDebugClient *m_engineDebugClient;
hjk's avatar
hjk committed
71
    QTimer m_connectionTimer;
72
    QDeclarativeDebugConnection *m_conn;
73
    QHash<QString, QmlDebuggerClient*> debugClients;
74 75
    int m_currentSelectedDebugId;
    QString m_currentSelectedDebugName;
76
    QmlJsDebugClient::QDebugMessageClient *m_msgClient;
77 78
};

hjk's avatar
hjk committed
79
} // namespace Internal
Lasse Holmstedt's avatar
Lasse Holmstedt committed
80 81

QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent)
hjk's avatar
hjk committed
82
    : QObject(parent), d(new Internal::QmlAdapterPrivate(engine))
83
{
84
    connect(&d->m_connectionTimer, SIGNAL(timeout()), SLOT(checkConnectionState()));
85 86 87 88 89 90
    d->m_conn = new QDeclarativeDebugConnection(this);
    connect(d->m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            SLOT(connectionStateChanged()));
    connect(d->m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
            SLOT(connectionErrorOccurred(QAbstractSocket::SocketError)));

91 92 93
    ExtensionSystem::PluginManager *pluginManager =
        ExtensionSystem::PluginManager::instance();
    pluginManager->addObject(this);
94 95

    createDebuggerClients();
96 97 98
    d->m_msgClient = new QmlJsDebugClient::QDebugMessageClient(d->m_conn);
    connect(d->m_msgClient, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
            this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
99
}
Lasse Holmstedt's avatar
Lasse Holmstedt committed
100

101
QmlAdapter::~QmlAdapter()
Lasse Holmstedt's avatar
Lasse Holmstedt committed
102
{
103 104 105
    ExtensionSystem::PluginManager *pluginManager =
        ExtensionSystem::PluginManager::instance();

hjk's avatar
hjk committed
106
    if (pluginManager->allObjects().contains(this))
107
        pluginManager->removeObject(this);
hjk's avatar
hjk committed
108
    delete d;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
109 110
}

111
void QmlAdapter::beginConnectionTcp(const QString &address, quint16 port)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
112
{
Kai Koehne's avatar
Kai Koehne committed
113 114
    if (d->m_engine.isNull()
            || (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
115
        return;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg(
                                    QString::number(port)));
    d->m_conn->connectToHost(address, port);

    //A timeout to check the connection state
    d->m_connectionTimer.start();
}

void QmlAdapter::beginConnectionOst(const QString &channel)
{
    if (d->m_engine.isNull()
            || (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
        return;

    showConnectionStatusMessage(tr("Connecting to debug server on %1").arg(channel));
    d->m_conn->connectToOst(channel);
133 134 135 136 137 138 139 140 141 142 143 144 145 146

    //A timeout to check the connection state
    d->m_connectionTimer.start();
}

void QmlAdapter::closeConnection()
{
    if (d->m_connectionTimer.isActive()) {
        d->m_connectionTimer.stop();
    } else {
        if (d->m_conn) {
            d->m_conn->close();
        }
    }
Lasse Holmstedt's avatar
Lasse Holmstedt committed
147 148
}

149
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
150
{
151
    showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
152
                                .arg(socketError).arg(d->m_conn->errorString()));
Lasse Holmstedt's avatar
Lasse Holmstedt committed
153 154

    // this is only an error if we are already connected and something goes wrong.
155
    if (isConnected()) {
156
        emit connectionError(socketError);
157 158 159 160
    } else {
        d->m_connectionTimer.stop();
        emit connectionStartupFailed();
    }
Lasse Holmstedt's avatar
Lasse Holmstedt committed
161 162
}

163 164 165
void QmlAdapter::clientStatusChanged(QDeclarativeDebugClient::Status status)
{
    QString serviceName;
Kai Koehne's avatar
Kai Koehne committed
166
    if (QDeclarativeDebugClient *client = qobject_cast<QDeclarativeDebugClient*>(sender()))
167 168 169
        serviceName = client->name();

    logServiceStatusChange(serviceName, status);
170
}
171

172
void QmlAdapter::debugClientStatusChanged(QDeclarativeDebugClient::Status status)
173
{
174 175
    if (status != QDeclarativeDebugClient::Enabled)
        return;
176 177 178 179 180
    QDeclarativeDebugClient *client = qobject_cast<QDeclarativeDebugClient*>(sender());
    QTC_ASSERT(client, return);

    d->m_qmlClient =  qobject_cast<Internal::QmlDebuggerClient *>(client);
    d->m_qmlClient->startSession();
181 182
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
183 184
void QmlAdapter::connectionStateChanged()
{
185
    switch (d->m_conn->state()) {
Kai Koehne's avatar
Kai Koehne committed
186 187 188 189
    case QAbstractSocket::UnconnectedState:
    {
        showConnectionStatusMessage(tr("disconnected.\n\n"));
        emit disconnected();
Lasse Holmstedt's avatar
Lasse Holmstedt committed
190

Kai Koehne's avatar
Kai Koehne committed
191 192 193 194 195 196 197 198 199 200 201 202
        break;
    }
    case QAbstractSocket::HostLookupState:
        showConnectionStatusMessage(tr("resolving host..."));
        break;
    case QAbstractSocket::ConnectingState:
        showConnectionStatusMessage(tr("connecting to debug server..."));
        break;
    case QAbstractSocket::ConnectedState:
    {
        showConnectionStatusMessage(tr("connected.\n"));

203
        d->m_connectionTimer.stop();
204

Kai Koehne's avatar
Kai Koehne committed
205 206 207 208 209 210 211 212 213 214
        //reloadEngines();
        emit connected();
        break;
    }
    case QAbstractSocket::ClosingState:
        showConnectionStatusMessage(tr("closing..."));
        break;
    case QAbstractSocket::BoundState:
    case QAbstractSocket::ListeningState:
        break;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
215 216 217
    }
}

218 219 220 221 222 223 224 225
void QmlAdapter::checkConnectionState()
{
    if (!isConnected()) {
        closeConnection();
        emit connectionStartupFailed();
    }
}

226
void QmlAdapter::createDebuggerClients()
Lasse Holmstedt's avatar
Lasse Holmstedt committed
227 228
{

229 230
    Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn);
    connect(client1, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
231
            this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
232 233
    connect(client1, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
            this, SLOT(debugClientStatusChanged(QDeclarativeDebugClient::Status)));
234 235 236 237

    Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
    connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
            this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
238 239
    connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
            this, SLOT(debugClientStatusChanged(QDeclarativeDebugClient::Status)));
240 241 242 243 244 245 246

    d->debugClients.insert(client1->name(),client1);
    d->debugClients.insert(client2->name(),client2);


    client1->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
    client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
Lasse Holmstedt's avatar
Lasse Holmstedt committed
247 248 249 250 251 252

    //engine->startSuccessful();  // FIXME: AAA: port to new debugger states
}

bool QmlAdapter::isConnected() const
{
253
    return d->m_conn && d->m_qmlClient && d->m_conn->state() == QAbstractSocket::ConnectedState;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
254 255 256 257
}

QDeclarativeDebugConnection *QmlAdapter::connection() const
{
258
    return d->m_conn;
Lasse Holmstedt's avatar
Lasse Holmstedt committed
259 260
}

261 262 263 264 265
DebuggerEngine *QmlAdapter::debuggerEngine() const
{
    return d->m_engine.data();
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
266 267
void QmlAdapter::showConnectionStatusMessage(const QString &message)
{
268
    if (!d->m_engine.isNull())
269
        d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogStatus);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
270 271 272 273
}

void QmlAdapter::showConnectionErrorMessage(const QString &message)
{
274
    if (!d->m_engine.isNull())
275
        d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogError);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
276 277
}

278 279 280 281 282 283 284 285 286 287
bool QmlAdapter::disableJsDebugging(bool block)
{
    if (d->m_engine.isNull())
        return block;

    bool isBlocked = d->m_engine.data()->state() == InferiorRunOk;

    if (isBlocked == block)
        return block;

Kai Koehne's avatar
Kai Koehne committed
288
    if (block) {
289
        d->m_engine.data()->continueInferior();
Kai Koehne's avatar
Kai Koehne committed
290
    } else {
291
        d->m_engine.data()->requestInterruptInferior();
Kai Koehne's avatar
Kai Koehne committed
292
    }
293 294 295 296

    return isBlocked;
}

297 298 299 300 301 302 303 304 305
Internal::QmlDebuggerClient *QmlAdapter::activeDebuggerClient()
{
    return d->m_qmlClient;
}

QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
{
    return d->debugClients;
}
306

307
QmlJsDebugClient::QmlEngineDebugClient *QmlAdapter::engineDebugClient() const
308 309 310 311
{
    return d->m_engineDebugClient;
}

312
void QmlAdapter::setEngineDebugClient(QmlJsDebugClient::QmlEngineDebugClient *client)
313
{
314 315 316 317 318 319
    Internal::QmlEngine *engine =
            qobject_cast<Internal::QmlEngine *>(d->m_engine.data());
    if (engine && d->m_engineDebugClient)
        disconnect(d->m_engineDebugClient, SIGNAL(result(quint32,QVariant)),
                engine,
                SLOT(expressionEvaluated(quint32,QVariant)));
320
    d->m_engineDebugClient = client;
321 322 323 324
    if (engine && d->m_engineDebugClient)
        connect(d->m_engineDebugClient, SIGNAL(result(quint32,QVariant)),
                engine,
                SLOT(expressionEvaluated(quint32,QVariant)));
325 326
}

327 328 329 330 331
QmlJsDebugClient::QDebugMessageClient *QmlAdapter::messageClient() const
{
    return d->m_msgClient;
}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
int QmlAdapter::currentSelectedDebugId() const
{
    return d->m_currentSelectedDebugId;
}

QString QmlAdapter::currentSelectedDisplayName() const
{
    return d->m_currentSelectedDebugName;
}

void QmlAdapter::setCurrentSelectedDebugInfo(int currentDebugId, const QString &displayName)
{
    d->m_currentSelectedDebugId = currentDebugId;
    d->m_currentSelectedDebugName = displayName;
    emit selectionChanged();
}

Kai Koehne's avatar
Kai Koehne committed
349 350
void QmlAdapter::logServiceStatusChange(const QString &service,
                                        QDeclarativeDebugClient::Status newStatus)
351 352 353
{
    switch (newStatus) {
    case QDeclarativeDebugClient::Unavailable: {
354
        showConnectionStatusMessage(tr("Status of '%1' changed to 'unavailable'.").arg(service));
355 356 357
        break;
    }
    case QDeclarativeDebugClient::Enabled: {
358
        showConnectionStatusMessage(tr("Status of '%1' changed to 'enabled'.").arg(service));
359 360 361 362
        break;
    }

    case QDeclarativeDebugClient::NotConnected: {
363
        showConnectionStatusMessage(tr("Status of '%1' changed to 'not connected'.").arg(service));
364 365 366 367 368
        break;
    }
    }
}

369 370
void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
{
371
    if (!d->m_engine.isNull())
372
        d->m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
373 374
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
375
} // namespace Debugger