OSDN Git Service

Delegate javascript debugging to Script and V8 debugger clients.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / qml / qmladapter.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
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.
18 **
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.
22 **
23 ** Other Usage
24 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qmladapter.h"
34
35 #include "debuggerstartparameters.h"
36 #include "qscriptdebuggerclient.h"
37 #include "qmlv8debuggerclient.h"
38 #include "qmljsprivateapi.h"
39
40 #include "qmlengine.h"
41
42 #include <extensionsystem/pluginmanager.h>
43 #include <utils/qtcassert.h>
44
45 #include <QtCore/QTimer>
46 #include <QtCore/QDebug>
47
48 namespace Debugger {
49 namespace Internal {
50
51 class QmlAdapterPrivate
52 {
53 public:
54     explicit QmlAdapterPrivate(DebuggerEngine *engine)
55         : m_engine(engine)
56         , m_qmlClient(0)
57         , m_connectionAttempts(0)
58         , m_maxConnectionAttempts(50) // overall time: 50 x 200ms
59         , m_conn(0)
60     {
61         m_connectionTimer.setInterval(200);
62     }
63
64     QWeakPointer<DebuggerEngine> m_engine;
65     QmlDebuggerClient *m_qmlClient;
66
67     QTimer m_connectionTimer;
68     int m_connectionAttempts;
69     int m_maxConnectionAttempts;
70     QDeclarativeDebugConnection *m_conn;
71     QHash<QString, QmlDebuggerClient*> debugClients;
72 };
73
74 } // namespace Internal
75
76 QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent)
77     : QObject(parent), d(new Internal::QmlAdapterPrivate(engine))
78 {
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)));
85
86     ExtensionSystem::PluginManager *pluginManager =
87         ExtensionSystem::PluginManager::instance();
88     pluginManager->addObject(this);
89 }
90
91 QmlAdapter::~QmlAdapter()
92 {
93     ExtensionSystem::PluginManager *pluginManager =
94         ExtensionSystem::PluginManager::instance();
95
96     if (pluginManager->allObjects().contains(this)) {
97         pluginManager->removeObject(this);
98     }
99 }
100
101 void QmlAdapter::beginConnection()
102 {
103     d->m_connectionAttempts = 0;
104     d->m_connectionTimer.start();
105 }
106
107 void QmlAdapter::closeConnection()
108 {
109     if (d->m_connectionTimer.isActive()) {
110         d->m_connectionTimer.stop();
111     } else {
112         if (d->m_conn) {
113             d->m_conn->close();
114         }
115     }
116 }
117
118 void QmlAdapter::pollInferior()
119 {
120     ++d->m_connectionAttempts;
121
122     if (isConnected()) {
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();
129     } else {
130         connectToViewer();
131     }
132 }
133
134 void QmlAdapter::connectToViewer()
135 {
136     if (d->m_engine.isNull()
137             || (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
138         return;
139
140     const DebuggerStartParameters &parameters = 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);
145     } else {
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);
150     }
151 }
152
153 void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
154 {
155     showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
156                                 .arg(socketError).arg(d->m_conn->errorString()));
157
158     // this is only an error if we are already connected and something goes wrong.
159     if (isConnected())
160         emit connectionError(socketError);
161 }
162
163 void QmlAdapter::clientStatusChanged(QDeclarativeDebugClient::Status status)
164 {
165     QString serviceName;
166     if (QDeclarativeDebugClient *client = qobject_cast<QDeclarativeDebugClient*>(sender()))
167         serviceName = client->name();
168
169     logServiceStatusChange(serviceName, status);
170
171     if (status == QDeclarativeDebugClient::Enabled) {
172         d->m_qmlClient = d->debugClients.value(serviceName);
173         d->m_qmlClient->flushSendBuffer();
174     }
175 }
176
177 void QmlAdapter::connectionStateChanged()
178 {
179     switch (d->m_conn->state()) {
180     case QAbstractSocket::UnconnectedState:
181     {
182         showConnectionStatusMessage(tr("disconnected.\n\n"));
183         emit disconnected();
184
185         break;
186     }
187     case QAbstractSocket::HostLookupState:
188         showConnectionStatusMessage(tr("resolving host..."));
189         break;
190     case QAbstractSocket::ConnectingState:
191         showConnectionStatusMessage(tr("connecting to debug server..."));
192         break;
193     case QAbstractSocket::ConnectedState:
194     {
195         showConnectionStatusMessage(tr("connected.\n"));
196
197         if (!d->m_qmlClient)
198             createDebuggerClients();
199
200         //reloadEngines();
201         emit connected();
202         break;
203     }
204     case QAbstractSocket::ClosingState:
205         showConnectionStatusMessage(tr("closing..."));
206         break;
207     case QAbstractSocket::BoundState:
208     case QAbstractSocket::ListeningState:
209         break;
210     }
211 }
212
213 void QmlAdapter::createDebuggerClients()
214 {
215
216     Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn);
217     connect(client1, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
218             this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
219
220     Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
221     connect(client2, SIGNAL(newStatus(QDeclarativeDebugClient::Status)),
222             this, SLOT(clientStatusChanged(QDeclarativeDebugClient::Status)));
223
224     d->debugClients.insert(client1->name(),client1);
225     d->debugClients.insert(client2->name(),client2);
226
227
228     client1->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
229     client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
230
231     //engine->startSuccessful();  // FIXME: AAA: port to new debugger states
232 }
233
234 bool QmlAdapter::isConnected() const
235 {
236     return d->m_conn && d->m_qmlClient && d->m_conn->state() == QAbstractSocket::ConnectedState;
237 }
238
239 QDeclarativeDebugConnection *QmlAdapter::connection() const
240 {
241     return d->m_conn;
242 }
243
244 void QmlAdapter::showConnectionStatusMessage(const QString &message)
245 {
246     if (!d->m_engine.isNull())
247         d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogStatus);
248 }
249
250 void QmlAdapter::showConnectionErrorMessage(const QString &message)
251 {
252     if (!d->m_engine.isNull())
253         d->m_engine.data()->showMessage(QLatin1String("QmlDebugger: ") + message, LogError);
254 }
255
256 bool QmlAdapter::disableJsDebugging(bool block)
257 {
258     if (d->m_engine.isNull())
259         return block;
260
261     bool isBlocked = d->m_engine.data()->state() == InferiorRunOk;
262
263     if (isBlocked == block)
264         return block;
265
266     if (block) {
267         d->m_engine.data()->continueInferior();
268     } else {
269         d->m_engine.data()->requestInterruptInferior();
270     }
271
272     return isBlocked;
273 }
274
275 Internal::QmlDebuggerClient *QmlAdapter::activeDebuggerClient()
276 {
277     return d->m_qmlClient;
278 }
279
280 QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
281 {
282     return d->debugClients;
283 }
284 void QmlAdapter::logServiceStatusChange(const QString &service,
285                                         QDeclarativeDebugClient::Status newStatus)
286 {
287     switch (newStatus) {
288     case QDeclarativeDebugClient::Unavailable: {
289         showConnectionStatusMessage(tr("Debug service '%1' became unavailable.").arg(service));
290         emit serviceConnectionError(service);
291         break;
292     }
293     case QDeclarativeDebugClient::Enabled: {
294         showConnectionStatusMessage(tr("Connected to debug service '%1'.").arg(service));
295         break;
296     }
297
298     case QDeclarativeDebugClient::NotConnected: {
299         showConnectionStatusMessage(tr("Not connected to debug service '%1'.").arg(service));
300         break;
301     }
302     }
303 }
304
305 void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
306 {
307     if (!d->m_engine.isNull())
308         d->m_engine.data()->showMessage(QString("%1 %2").arg(service, logMessage), LogDebug);
309 }
310
311 } // namespace Debugger