source: trunk/src/scripttools/debugging/qscriptenginedebuggerfrontend.cpp@ 324

Last change on this file since 324 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 9.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtSCriptTools module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptenginedebuggerfrontend_p.h"
43#include "qscriptdebuggerfrontend_p_p.h"
44#include "qscriptdebuggerbackend_p.h"
45#include "qscriptdebuggerbackend_p_p.h"
46#include "qscriptdebuggerevent_p.h"
47#include "qscriptdebuggercommandexecutor_p.h"
48#include "qscriptdebuggerresponse_p.h"
49
50#include <QtCore/qcoreapplication.h>
51#include <QtCore/qeventloop.h>
52#include <QtCore/qlist.h>
53#include <QtScript/qscriptvalue.h>
54
55QT_BEGIN_NAMESPACE
56
57/*!
58 \class QScriptEngineDebuggerFrontend
59 \since 4.5
60 \internal
61
62 \brief The QScriptEngineDebuggerFrontend class provides an in-process debugger frontend.
63
64 This type of frontend is used when the QScriptEngine being debugged
65 lives in the same process as the debugger.
66
67 Call the attachTo() function to attach to an engine.
68*/
69
70class QScriptDebuggerCommandEvent : public QEvent
71{
72public:
73 QScriptDebuggerCommandEvent(int id, const QScriptDebuggerCommand &command)
74 : QEvent(QEvent::Type(QEvent::User+3)), m_id(id), m_command(command) {}
75 ~QScriptDebuggerCommandEvent() {}
76 int id() const
77 { return m_id; }
78 const QScriptDebuggerCommand &command() const
79 { return m_command; }
80private:
81 int m_id;
82 QScriptDebuggerCommand m_command;
83};
84
85class QScriptDebuggerCommandFinishedEvent : public QEvent
86{
87public:
88 QScriptDebuggerCommandFinishedEvent(int id, const QScriptDebuggerResponse &response)
89 : QEvent(QEvent::Type(QEvent::User+4)), m_id(id), m_response(response) {}
90 ~QScriptDebuggerCommandFinishedEvent() {}
91 int id() const
92 { return m_id; }
93 const QScriptDebuggerResponse &response() const
94 { return m_response; }
95private:
96 int m_id;
97 QScriptDebuggerResponse m_response;
98};
99
100class QScriptEngineDebuggerBackendPrivate;
101class QScriptEngineDebuggerBackend : public QScriptDebuggerBackend
102{
103public:
104 QScriptEngineDebuggerBackend(QScriptEngineDebuggerFrontendPrivate *frontend);
105 ~QScriptEngineDebuggerBackend();
106
107 void processCommand(int id, const QScriptDebuggerCommand &command);
108 void resume();
109
110protected:
111 void event(const QScriptDebuggerEvent &event);
112
113private:
114 Q_DECLARE_PRIVATE(QScriptEngineDebuggerBackend)
115 Q_DISABLE_COPY(QScriptEngineDebuggerBackend)
116};
117
118class QScriptEngineDebuggerBackendPrivate
119 : public QScriptDebuggerBackendPrivate
120{
121 Q_DECLARE_PUBLIC(QScriptEngineDebuggerBackend)
122public:
123 QScriptEngineDebuggerBackendPrivate();
124 ~QScriptEngineDebuggerBackendPrivate();
125
126 bool event(QEvent *e);
127
128 QScriptEngineDebuggerFrontendPrivate *frontend;
129 QList<QEventLoop*> eventLoopPool;
130 QList<QEventLoop*> eventLoopStack;
131};
132
133class QScriptEngineDebuggerFrontendPrivate
134 : public QScriptDebuggerFrontendPrivate
135{
136 Q_DECLARE_PUBLIC(QScriptEngineDebuggerFrontend)
137public:
138 QScriptEngineDebuggerFrontendPrivate();
139 ~QScriptEngineDebuggerFrontendPrivate();
140
141 void postCommandFinished(int id, const QScriptDebuggerResponse &response);
142 bool event(QEvent *e);
143
144 QScriptEngineDebuggerBackend *backend;
145};
146
147QScriptEngineDebuggerBackendPrivate::QScriptEngineDebuggerBackendPrivate()
148{
149 frontend = 0;
150}
151
152QScriptEngineDebuggerBackendPrivate::~QScriptEngineDebuggerBackendPrivate()
153{
154 eventLoopPool << eventLoopStack;
155 eventLoopStack.clear();
156 while (!eventLoopPool.isEmpty()) {
157 QEventLoop *eventLoop = eventLoopPool.takeFirst();
158 if (eventLoop->isRunning()) {
159 eventLoop->quit();
160 eventLoop->deleteLater();
161 } else {
162 delete eventLoop;
163 }
164 }
165}
166
167/*!
168 \reimp
169*/
170bool QScriptEngineDebuggerBackendPrivate::event(QEvent *e)
171{
172 Q_Q(QScriptEngineDebuggerBackend);
173 if (e->type() == QEvent::User+3) {
174 QScriptDebuggerCommandEvent *ce = static_cast<QScriptDebuggerCommandEvent*>(e);
175 QScriptDebuggerCommandExecutor *executor = q->commandExecutor();
176 QScriptDebuggerResponse response = executor->execute(q, ce->command());
177 frontend->postCommandFinished(ce->id(), response);
178 return true;
179 }
180 return QScriptDebuggerBackendPrivate::event(e);
181}
182
183/*!
184 \internal
185
186 Creates a new QScriptEngineDebuggerBackend object for the given \a
187 engine. The back-end will forward events to the given \a frontend.
188*/
189QScriptEngineDebuggerBackend::QScriptEngineDebuggerBackend(
190 QScriptEngineDebuggerFrontendPrivate *frontend)
191 : QScriptDebuggerBackend(*new QScriptEngineDebuggerBackendPrivate)
192{
193 Q_D(QScriptEngineDebuggerBackend);
194 d->frontend = frontend;
195}
196
197QScriptEngineDebuggerBackend::~QScriptEngineDebuggerBackend()
198{
199}
200
201void QScriptEngineDebuggerBackend::processCommand(int id, const QScriptDebuggerCommand &command)
202{
203 Q_D(QScriptEngineDebuggerBackend);
204 d->postEvent(new QScriptDebuggerCommandEvent(id, command));
205}
206
207/*!
208 \reimp
209*/
210void QScriptEngineDebuggerBackend::event(const QScriptDebuggerEvent &event)
211{
212 Q_D(QScriptEngineDebuggerBackend);
213 if (d->eventLoopPool.isEmpty())
214 d->eventLoopPool.append(new QEventLoop());
215 QEventLoop *eventLoop = d->eventLoopPool.takeFirst();
216 Q_ASSERT(!eventLoop->isRunning());
217 d->eventLoopStack.prepend(eventLoop);
218
219 d->frontend->postEvent(new QScriptDebuggerEventEvent(event));
220
221 // Run an event loop until resume() is called.
222 // This effectively stalls script execution and makes it possible
223 // for the debugger to inspect the execution state in the meantime.
224 eventLoop->exec();
225
226 if (!d->eventLoopStack.isEmpty()) {
227 // the event loop was quit directly (i.e. not via resume())
228 d->eventLoopStack.takeFirst();
229 }
230 d->eventLoopPool.append(eventLoop);
231 doPendingEvaluate(/*postEvent=*/false);
232}
233
234/*!
235 \reimp
236*/
237void QScriptEngineDebuggerBackend::resume()
238{
239 Q_D(QScriptEngineDebuggerBackend);
240 // quitting the event loops will cause event() to return (see above)
241 while (!d->eventLoopStack.isEmpty()) {
242 QEventLoop *eventLoop = d->eventLoopStack.takeFirst();
243 if (eventLoop->isRunning())
244 eventLoop->quit();
245 }
246}
247
248QScriptEngineDebuggerFrontendPrivate::QScriptEngineDebuggerFrontendPrivate()
249{
250 backend = 0;
251}
252
253QScriptEngineDebuggerFrontendPrivate::~QScriptEngineDebuggerFrontendPrivate()
254{
255 delete backend;
256}
257
258void QScriptEngineDebuggerFrontendPrivate::postCommandFinished(
259 int id, const QScriptDebuggerResponse &response)
260{
261 postEvent(new QScriptDebuggerCommandFinishedEvent(id, response));
262}
263
264/*!
265 \reimp
266*/
267bool QScriptEngineDebuggerFrontendPrivate::event(QEvent *e)
268{
269 Q_Q(QScriptEngineDebuggerFrontend);
270 if (e->type() == QEvent::User+4) {
271 QScriptDebuggerCommandFinishedEvent *fe = static_cast<QScriptDebuggerCommandFinishedEvent*>(e);
272 q->notifyCommandFinished(fe->id(), fe->response());
273 return true;
274 }
275 return QScriptDebuggerFrontendPrivate::event(e);
276}
277
278QScriptEngineDebuggerFrontend::QScriptEngineDebuggerFrontend()
279 : QScriptDebuggerFrontend(*new QScriptEngineDebuggerFrontendPrivate)
280{
281}
282
283QScriptEngineDebuggerFrontend::~QScriptEngineDebuggerFrontend()
284{
285 detach();
286}
287
288/*!
289 Attaches this front-end to the given \a engine.
290*/
291void QScriptEngineDebuggerFrontend::attachTo(QScriptEngine *engine)
292{
293 Q_D(QScriptEngineDebuggerFrontend);
294 if (d->backend)
295 d->backend->detach();
296 else
297 d->backend = new QScriptEngineDebuggerBackend(d);
298 d->backend->attachTo(engine);
299}
300
301/*!
302 Detaches this front-end from the current script engine.
303*/
304void QScriptEngineDebuggerFrontend::detach()
305{
306 Q_D(QScriptEngineDebuggerFrontend);
307 if (d->backend)
308 d->backend->detach();
309}
310
311QScriptValue QScriptEngineDebuggerFrontend::traceFunction() const
312{
313 Q_D(const QScriptEngineDebuggerFrontend);
314 if (d->backend)
315 d->backend->traceFunction();
316 return QScriptValue();
317}
318
319QScriptDebuggerBackend *QScriptEngineDebuggerFrontend::backend() const
320{
321 Q_D(const QScriptEngineDebuggerFrontend);
322 return d->backend;
323}
324
325/*!
326 \reimp
327*/
328void QScriptEngineDebuggerFrontend::processCommand(int id, const QScriptDebuggerCommand &command)
329{
330 Q_D(QScriptEngineDebuggerFrontend);
331 Q_ASSERT(d->backend != 0);
332 d->backend->processCommand(id, command);
333}
334
335QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.