1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
31 **************************************************************************/
33 #include "qmladapter.h"
35 #include "debuggerstartparameters.h"
36 #include "qscriptdebuggerclient.h"
37 #include "qmlv8debuggerclient.h"
38 #include "qmljsprivateapi.h"
40 #include "qmlengine.h"
42 #include <extensionsystem/pluginmanager.h>
43 #include <utils/qtcassert.h>
45 #include <QtCore/QTimer>
46 #include <QtCore/QDebug>
51 class QmlAdapterPrivate
54 explicit QmlAdapterPrivate(DebuggerEngine *engine)
57 , m_connectionAttempts(0)
58 , m_maxConnectionAttempts(50) // overall time: 50 x 200ms
61 m_connectionTimer.setInterval(200);
64 QWeakPointer<DebuggerEngine> m_engine;
65 QmlDebuggerClient *m_qmlClient;
67 QTimer m_connectionTimer;
68 int m_connectionAttempts;
69 int m_maxConnectionAttempts;
70 QDeclarativeDebugConnection *m_conn;
71 QHash<QString, QmlDebuggerClient*> debugClients;
74 } // namespace Internal
76 QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent)
77 : QObject(parent), d(new Internal::QmlAdapterPrivate(engine))
79 connect(&d->m_connectionTimer, SIGNAL(timeout()), SLOT(pollInferior()));
80 d->m_conn = new QDeclarativeDebugConnection(this);
81 connect(d->m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
82 SLOT(connectionStateChanged()));
83 connect(d->m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
84 SLOT(connectionErrorOccurred(QAbstractSocket::SocketError)));
86 ExtensionSystem::PluginManager *pluginManager =
87 ExtensionSystem::PluginManager::instance();
88 pluginManager->addObject(this);
91 QmlAdapter::~QmlAdapter()
93 ExtensionSystem::PluginManager *pluginManager =
94 ExtensionSystem::PluginManager::instance();
96 if (pluginManager->allObjects().contains(this)) {
97 pluginManager->removeObject(this);
101 void QmlAdapter::beginConnection()
103 d->m_connectionAttempts = 0;
104 d->m_connectionTimer.start();
107 void QmlAdapter::closeConnection()
109 if (d->m_connectionTimer.isActive()) {
110 d->m_connectionTimer.stop();
118 void QmlAdapter::pollInferior()
120 ++d->m_connectionAttempts;
123 d->m_connectionTimer.stop();
124 d->m_connectionAttempts = 0;
125 } else if (d->m_connectionAttempts == d->m_maxConnectionAttempts) {
126 d->m_connectionTimer.stop();
127 d->m_connectionAttempts = 0;
128 emit connectionStartupFailed();
134 void QmlAdapter::connectToViewer()
136 if (d->m_engine.isNull()
137 || (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
140 const DebuggerStartParameters ¶meters = d->m_engine.data()->startParameters();
141 if (parameters.communicationChannel == DebuggerStartParameters::CommunicationChannelUsb) {
142 const QString &port = parameters.remoteChannel;
143 showConnectionStatusMessage(tr("Connecting to debug server on %1").arg(port));
144 d->m_conn->connectToOst(port);
146 const QString &address = parameters.qmlServerAddress;
147 quint16 port = parameters.qmlServerPort;
148 showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg(QString::number(port)));
149 d->m_conn->connectToHost(address, port);
153 void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
155 showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
156 .arg(socketError).arg(d->m_conn->errorString()));
158 // this is only an error if we are already connected and something goes wrong.
160 emit connectionError(socketError);
163 void QmlAdapter::clientStatusChanged(QDeclarativeDebugClient::Status status)
166 if (QDeclarativeDebugClient *client = qobject_cast<QDeclarativeDebugClient*>(sender()))
167 serviceName = client->name();
169 logServiceStatusChange(serviceName, status);
171 if (status == QDeclarativeDebugClient::Enabled) {
172 d->m_qmlClient = d->debugClients.value(serviceName);
173 d->m_qmlClient->flushSendBuffer();
177 void QmlAdapter::connectionStateChanged()
179 switch (d->m_conn->state()) {
180 case QAbstractSocket::UnconnectedState:
182 showConnectionStatusMessage(tr("disconnected.\n\n"));
187 case QAbstractSocket::HostLookupState:
188 showConnectionStatusMessage(tr("resolving host..."));
190 case QAbstractSocket::ConnectingState:
191 showConnectionStatusMessage(tr("connecting to debug server..."));
193 case QAbstractSocket::ConnectedState:
195 showConnectionStatusMessage(tr("connected.\n"));
198 createDebuggerClients();
204 case QAbstractSocket::ClosingState:
205 showConnectionStatusMessage(tr("closing..."));
207 case QAbstractSocket::BoundState:
208 case QAbstractSocket::ListeningState:
213 void QmlAdapter::createDebuggerClients()
216 Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn);
217 connect(client1, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
218 this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
220 Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
221 connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
222 this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
224 d->debugClients.insert(client1->name(),client1);
225 d->debugClients.insert(client2->name(),client2);
228 client1->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
229 client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
231 //engine->startSuccessful(); // FIXME: AAA: port to new debugger states
234 bool QmlAdapter::isConnected() const
236 return d->m_conn && d->m_qmlClient && d->m_conn->state() == QAbstractSocket::ConnectedState;
239 QDeclarativeDebugConnection *QmlAdapter::connection() const
244 void QmlAdapter::showConnectionStatusMessage(const QString &message)
246 if (!d->m_engine.isNull())
247 d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogStatus);
250 void QmlAdapter::showConnectionErrorMessage(const QString &message)
252 if (!d->m_engine.isNull())
253 d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogError);
256 bool QmlAdapter::disableJsDebugging(bool block)
258 if (d->m_engine.isNull())
261 bool isBlocked = d->m_engine.data()->state() == InferiorRunOk;
263 if (isBlocked == block)
267 d->m_engine.data()->continueInferior();
269 d->m_engine.data()->requestInterruptInferior();
275 Internal::QmlDebuggerClient *QmlAdapter::activeDebuggerClient()
277 return d->m_qmlClient;
280 QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
282 return d->debugClients;
284 void QmlAdapter::logServiceStatusChange(const QString &service,
285 QDeclarativeDebugClient::Status newStatus)
288 case QDeclarativeDebugClient::Unavailable: {
289 showConnectionStatusMessage(tr("Debug service '%1' became unavailable.").arg(service));
290 emit serviceConnectionError(service);
293 case QDeclarativeDebugClient::Enabled: {
294 showConnectionStatusMessage(tr("Connected to debug service '%1'.").arg(service));
298 case QDeclarativeDebugClient::NotConnected: {
299 showConnectionStatusMessage(tr("Not connected to debug service '%1'.").arg(service));
305 void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
307 if (!d->m_engine.isNull())
308 d->m_engine.data()->showMessage(QString("%1 %2").arg(service, logMessage), LogDebug);
311 } // namespace Debugger