source: trunk/src/scripttools/debugging/qscriptdebugger.cpp@ 160

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

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

File size: 61.2 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 "qscriptdebugger_p.h"
43#include "qscriptdebuggerconsole_p.h"
44#include "qscriptdebuggerconsolecommandmanager_p.h"
45#include "qscriptdebuggerconsolecommandjob_p.h"
46#include "qscriptstdmessagehandler_p.h"
47#include "qscriptdebuggerfrontend_p.h"
48#include "qscriptdebuggereventhandlerinterface_p.h"
49#include "qscriptdebuggerresponsehandlerinterface_p.h"
50#include "qscriptdebuggerjobschedulerinterface_p.h"
51#include "qscriptdebuggerconsolewidgetinterface_p.h"
52#include "qscriptcompletionproviderinterface_p.h"
53#include "qscriptcompletiontask_p.h"
54#include "qscripttooltipproviderinterface_p.h"
55#include "qscriptdebuggerstackwidgetinterface_p.h"
56#include "qscriptdebuggerstackmodel_p.h"
57#include "qscriptdebuggerscriptswidgetinterface_p.h"
58#include "qscriptdebuggerscriptsmodel_p.h"
59#include "qscriptdebuggerlocalswidgetinterface_p.h"
60#include "qscriptdebuggerlocalsmodel_p.h"
61#include "qscriptdebuggercodewidgetinterface_p.h"
62#include "qscriptdebuggercodeviewinterface_p.h"
63#include "qscriptdebuggercodefinderwidgetinterface_p.h"
64#include "qscriptbreakpointswidgetinterface_p.h"
65#include "qscriptbreakpointsmodel_p.h"
66#include "qscriptdebugoutputwidgetinterface_p.h"
67#include "qscripterrorlogwidgetinterface_p.h"
68#include "qscriptdebuggerwidgetfactoryinterface_p.h"
69#include "qscriptdebuggerevent_p.h"
70#include "qscriptdebuggervalue_p.h"
71#include "qscriptdebuggerresponse_p.h"
72#include "qscriptdebuggercommand_p.h"
73#include "qscriptdebuggercommandschedulerfrontend_p.h"
74#include "qscriptdebuggercommandschedulerjob_p.h"
75#include "qscriptdebuggerjob_p_p.h"
76#include "qscriptxmlparser_p.h"
77
78#include "qscriptenginedebuggerfrontend_p.h"
79#include "qscriptdebuggerbackend_p.h"
80#include <QtScript/qscriptengine.h>
81
82#include "private/qobject_p.h"
83
84#include <QtScript/qscriptcontext.h>
85#include <QtScript/qscriptcontextinfo.h>
86
87#include <QtCore/qcoreapplication.h>
88#include <QtCore/qdir.h>
89#include <QtCore/qfileinfo.h>
90#include <QtCore/qstringlist.h>
91#include <QtCore/qdebug.h>
92
93#include <QtGui/qaction.h>
94#include <QtGui/qevent.h>
95#include <QtGui/qicon.h>
96#include <QtGui/qinputdialog.h>
97
98QT_BEGIN_NAMESPACE
99typedef QPair<QList<qint64>, QList<qint64> > QScriptScriptsDelta;
100typedef QPair<QList<qint64>, QList<qint64> > QScriptContextsDelta;
101QT_END_NAMESPACE
102
103Q_DECLARE_METATYPE(QScriptScriptsDelta)
104
105QT_BEGIN_NAMESPACE
106
107Q_SCRIPT_EXPORT QString qt_scriptToXml(const QString &program, int lineNumber = 1);
108
109namespace {
110
111static int scriptDebuggerCount = 0;
112static bool eventCallbackRegistered = false;
113static bool widgetInPaintEvent = false;
114
115static bool scriptDebuggerEventCallback(void **data)
116{
117 QEvent *event = reinterpret_cast<QEvent*>(data[1]);
118 if (event->type() == QEvent::Paint) {
119 QObject *receiver = reinterpret_cast<QObject*>(data[0]);
120 bool was = widgetInPaintEvent;
121 widgetInPaintEvent = true;
122 QCoreApplication::instance()->notify(receiver, event);
123 widgetInPaintEvent = was;
124 bool *result = reinterpret_cast<bool*>(data[2]);
125 *result = true;
126 return true;
127 }
128 return false;
129}
130
131}
132
133/*!
134 \since 4.5
135 \class QScriptDebugger
136 \internal
137
138 \brief The QScriptDebugger class provides a Qt Script debugger.
139
140 \ingroup scripttools
141 \mainclass
142*/
143
144class QScriptDebuggerPrivate
145 : public QObjectPrivate,
146 public QScriptDebuggerCommandSchedulerInterface,
147 public QScriptDebuggerJobSchedulerInterface,
148 public QScriptDebuggerEventHandlerInterface,
149 public QScriptDebuggerResponseHandlerInterface,
150 public QScriptCompletionProviderInterface,
151 public QScriptToolTipProviderInterface
152{
153 Q_DECLARE_PUBLIC(QScriptDebugger)
154public:
155 QScriptDebuggerPrivate();
156 ~QScriptDebuggerPrivate();
157
158 int scheduleJob(QScriptDebuggerJob *job);
159 void finishJob(QScriptDebuggerJob *job);
160 void hibernateUntilEvaluateFinished(QScriptDebuggerJob *job);
161
162 void maybeStartNewJob();
163
164 int scheduleCommand(const QScriptDebuggerCommand &command,
165 QScriptDebuggerResponseHandlerInterface *responseHandler);
166
167 void handleResponse(
168 const QScriptDebuggerResponse &response, int commandId);
169 bool debuggerEvent(const QScriptDebuggerEvent &event);
170
171 QScriptCompletionTaskInterface *createCompletionTask(
172 const QString &contents, int cursorPosition, int frameIndex, int options);
173
174 QString toolTip(int frameIndex, int lineNumber,
175 const QStringList &path);
176
177 static QPixmap pixmap(const QString &path);
178
179 void startInteraction(QScriptDebuggerEvent::Type type,
180 qint64 scriptId, int lineNumber);
181 void sync();
182 void loadLocals(int frameIndex);
183 QScriptDebuggerLocalsModel *createLocalsModel();
184 void selectScriptForFrame(int frameIndex);
185 void emitStoppedSignal();
186
187 void maybeDelete(QWidget *widget);
188
189 // private slots
190 void _q_onLineEntered(const QString &contents);
191 void _q_onCurrentFrameChanged(int frameIndex);
192 void _q_onCurrentScriptChanged(qint64 scriptId);
193 void _q_onScriptLocationSelected(int lineNumber);
194 void _q_interrupt();
195 void _q_continue();
196 void _q_stepInto();
197 void _q_stepOver();
198 void _q_stepOut();
199 void _q_runToCursor();
200 void _q_runToNewScript();
201 void _q_toggleBreakpoint();
202 void _q_clearDebugOutput();
203 void _q_clearErrorLog();
204 void _q_clearConsole();
205 void _q_findInScript();
206 void _q_findNextInScript();
207 void _q_findPreviousInScript();
208 void _q_onFindCodeRequest(const QString &, int);
209 void _q_goToLine();
210
211 void executeConsoleCommand(const QString &command);
212 void findCode(const QString &exp, int options);
213
214 QScriptDebuggerFrontend *frontend;
215
216 bool interactive;
217 QScriptDebuggerConsole *console;
218
219 int nextJobId;
220 QList<QScriptDebuggerJob*> pendingJobs;
221 QList<int> pendingJobIds;
222 QScriptDebuggerJob *activeJob;
223 bool activeJobHibernating;
224 QHash<int, QScriptDebuggerCommand> watchedCommands;
225 QHash<int, QScriptDebuggerResponseHandlerInterface*> responseHandlers;
226
227 QScriptDebuggerConsoleWidgetInterface *consoleWidget;
228 QScriptDebuggerStackWidgetInterface *stackWidget;
229 QScriptDebuggerStackModel *stackModel;
230 QScriptDebuggerScriptsWidgetInterface *scriptsWidget;
231 QScriptDebuggerScriptsModel *scriptsModel;
232 QScriptDebuggerLocalsWidgetInterface *localsWidget;
233 QHash<int, QScriptDebuggerLocalsModel*> localsModels;
234 QScriptDebuggerCodeWidgetInterface *codeWidget;
235 QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget;
236 QScriptBreakpointsWidgetInterface *breakpointsWidget;
237 QScriptBreakpointsModel *breakpointsModel;
238 QScriptDebugOutputWidgetInterface *debugOutputWidget;
239 QScriptErrorLogWidgetInterface *errorLogWidget;
240 QScriptDebuggerWidgetFactoryInterface *widgetFactory;
241
242 QAction *interruptAction;
243 QAction *continueAction;
244 QAction *stepIntoAction;
245 QAction *stepOverAction;
246 QAction *stepOutAction;
247 QAction *runToCursorAction;
248 QAction *runToNewScriptAction;
249
250 QAction *toggleBreakpointAction;
251
252 QAction *clearDebugOutputAction;
253 QAction *clearErrorLogAction;
254 QAction *clearConsoleAction;
255
256 QAction *findInScriptAction;
257 QAction *findNextInScriptAction;
258 QAction *findPreviousInScriptAction;
259 QAction *goToLineAction;
260
261 int updatesEnabledTimerId;
262};
263
264QScriptDebuggerPrivate::QScriptDebuggerPrivate()
265{
266 frontend = 0;
267 activeJob = 0;
268 activeJobHibernating = false;
269 nextJobId = 0;
270 interactive = false;
271
272 console = new QScriptDebuggerConsole();
273 QString scriptsPath = QLatin1String(":/qt/scripttools/debugging/scripts/commands");
274 QScriptStdMessageHandler tmp;
275 console->loadScriptedCommands(scriptsPath, &tmp);
276
277 consoleWidget = 0;
278 stackWidget = 0;
279 stackModel = 0;
280 scriptsWidget = 0;
281 scriptsModel = 0;
282 localsWidget = 0;
283 codeWidget = 0;
284 codeFinderWidget = 0;
285 breakpointsWidget = 0;
286 breakpointsModel = 0;
287 debugOutputWidget = 0;
288 errorLogWidget = 0;
289 widgetFactory = 0;
290
291 interruptAction = 0;
292 continueAction = 0;
293 stepIntoAction = 0;
294 stepOverAction = 0;
295 stepOutAction = 0;
296 runToCursorAction = 0;
297 runToNewScriptAction = 0;
298
299 toggleBreakpointAction = 0;
300
301 clearErrorLogAction = 0;
302 clearDebugOutputAction = 0;
303 clearConsoleAction = 0;
304
305 findInScriptAction = 0;
306 findNextInScriptAction = 0;
307 findPreviousInScriptAction = 0;
308 goToLineAction = 0;
309
310 updatesEnabledTimerId = -1;
311}
312
313QScriptDebuggerPrivate::~QScriptDebuggerPrivate()
314{
315 delete console;
316 qDeleteAll(pendingJobs);
317 delete activeJob;
318 maybeDelete(consoleWidget);
319 maybeDelete(stackWidget);
320 maybeDelete(scriptsWidget);
321 maybeDelete(localsWidget);
322 maybeDelete(codeWidget);
323 maybeDelete(codeFinderWidget);
324 maybeDelete(breakpointsWidget);
325 maybeDelete(debugOutputWidget);
326 maybeDelete(errorLogWidget);
327}
328
329void QScriptDebuggerPrivate::maybeDelete(QWidget *widget)
330{
331 if (widget && !widget->parent())
332 delete widget;
333}
334
335QPixmap QScriptDebuggerPrivate::pixmap(const QString &path)
336{
337 static QString prefix = QString::fromLatin1(":/qt/scripttools/debugging/images/");
338 return QPixmap(prefix + path);
339}
340
341/*!
342 \reimp
343*/
344int QScriptDebuggerPrivate::scheduleJob(QScriptDebuggerJob *job)
345{
346 QScriptDebuggerJobPrivate *priv = QScriptDebuggerJobPrivate::get(job);
347 Q_ASSERT(priv->jobScheduler == 0);
348 priv->jobScheduler = this;
349 int id = nextJobId;
350 pendingJobs.append(job);
351 pendingJobIds.append(id);
352 maybeStartNewJob();
353 return id;
354}
355
356/*!
357 \reimp
358*/
359void QScriptDebuggerPrivate::finishJob(QScriptDebuggerJob *job)
360{
361 Q_UNUSED(job);
362 Q_ASSERT(activeJob == job);
363 delete activeJob;
364 activeJob = 0;
365 activeJobHibernating = false;
366 maybeStartNewJob();
367}
368
369/*!
370 \reimp
371*/
372void QScriptDebuggerPrivate::hibernateUntilEvaluateFinished(QScriptDebuggerJob *job)
373{
374 Q_UNUSED(job);
375 Q_ASSERT(activeJob == job);
376 activeJobHibernating = true;
377}
378
379/*!
380 Starts a new job if appropriate.
381*/
382void QScriptDebuggerPrivate::maybeStartNewJob()
383{
384 if (activeJob || pendingJobs.isEmpty())
385 return;
386 activeJob = pendingJobs.takeFirst();
387 activeJob->start();
388}
389
390/*!
391 \reimp
392*/
393int QScriptDebuggerPrivate::scheduleCommand(
394 const QScriptDebuggerCommand &command,
395 QScriptDebuggerResponseHandlerInterface *responseHandler)
396{
397 if (!frontend)
398 return -1;
399 int id = frontend->scheduleCommand(command, this);
400 if (responseHandler && (responseHandler != this))
401 responseHandlers.insert(id, responseHandler);
402 if ((command.type() == QScriptDebuggerCommand::SetBreakpoint)
403 || (command.type() == QScriptDebuggerCommand::SetBreakpointData)
404 || (command.type() == QScriptDebuggerCommand::DeleteBreakpoint)) {
405 // need to watch this command and update the breakpoints model afterwards
406 watchedCommands.insert(id, command);
407 }
408 return id;
409}
410
411/*!
412 \reimp
413*/
414void QScriptDebuggerPrivate::handleResponse(
415 const QScriptDebuggerResponse &response, int commandId)
416{
417 Q_Q(QScriptDebugger);
418 if (watchedCommands.contains(commandId)) {
419 QScriptDebuggerCommand command = watchedCommands.take(commandId);
420 if (response.error() == QScriptDebuggerResponse::NoError) {
421 if (!breakpointsModel)
422 breakpointsModel = new QScriptBreakpointsModel(this, this, q);
423 switch (command.type()) {
424 case QScriptDebuggerCommand::SetBreakpoint: {
425 int breakpointId = response.resultAsInt();
426 QScriptBreakpointData data = command.breakpointData();
427 breakpointsModel->addBreakpoint(breakpointId, data);
428 } break;
429 case QScriptDebuggerCommand::SetBreakpointData: {
430 int breakpointId = command.breakpointId();
431 QScriptBreakpointData data = command.breakpointData();
432 breakpointsModel->modifyBreakpoint(breakpointId, data);
433 } break;
434 case QScriptDebuggerCommand::DeleteBreakpoint: {
435 int breakpointId = command.breakpointId();
436 breakpointsModel->removeBreakpoint(breakpointId);
437 } break;
438 default:
439 Q_ASSERT(false);
440 }
441 }
442 } else if (response.async()) {
443 interactive = false;
444 // disable/invalidate/enable stuff
445 if (continueAction)
446 continueAction->setEnabled(false);
447 if (stepIntoAction)
448 stepIntoAction->setEnabled(false);
449 if (stepOverAction)
450 stepOverAction->setEnabled(false);
451 if (stepOutAction)
452 stepOutAction->setEnabled(false);
453 if (runToCursorAction)
454 runToCursorAction->setEnabled(false);
455 if (runToNewScriptAction)
456 runToNewScriptAction->setEnabled(false);
457 if (interruptAction)
458 interruptAction->setEnabled(true);
459
460 // the timer is to avoid flicker when stepping
461 if (stackWidget) {
462 stackWidget->setUpdatesEnabled(false);
463 stackWidget->setEnabled(false);
464 if (updatesEnabledTimerId == -1)
465 updatesEnabledTimerId = q->startTimer(75);
466 }
467 if (localsWidget) {
468 localsWidget->setUpdatesEnabled(false);
469 localsWidget->setEnabled(false);
470 if (updatesEnabledTimerId == -1)
471 updatesEnabledTimerId = q->startTimer(75);
472 }
473 if (codeWidget)
474 codeWidget->invalidateExecutionLineNumbers();
475
476 emit q->started();
477 }
478
479 QScriptDebuggerResponseHandlerInterface *realHandler = responseHandlers.take(commandId);
480 if (realHandler)
481 realHandler->handleResponse(response, commandId);
482}
483
484/*!
485 \reimp
486
487 Handles a debugger event from the frontend.
488*/
489bool QScriptDebuggerPrivate::debuggerEvent(const QScriptDebuggerEvent &event)
490{
491 Q_Q(QScriptDebugger);
492 switch (event.type()) {
493 case QScriptDebuggerEvent::None:
494 case QScriptDebuggerEvent::UserEvent:
495 case QScriptDebuggerEvent::MaxUserEvent:
496 Q_ASSERT(false);
497 break;
498
499 case QScriptDebuggerEvent::Trace:
500 if (!debugOutputWidget && widgetFactory)
501 q->setDebugOutputWidget(widgetFactory->createDebugOutputWidget());
502 if (debugOutputWidget)
503 debugOutputWidget->message(QtDebugMsg, event.message());
504 return true; // trace doesn't stall execution
505
506 case QScriptDebuggerEvent::SteppingFinished: {
507 if (!consoleWidget && widgetFactory)
508 q->setConsoleWidget(widgetFactory->createConsoleWidget());
509 if (consoleWidget) {
510 QString msg = event.message();
511 if (!msg.isEmpty())
512 consoleWidget->message(QtDebugMsg, msg);
513 }
514 } break;
515
516 case QScriptDebuggerEvent::Interrupted:
517 case QScriptDebuggerEvent::LocationReached:
518 break;
519
520 case QScriptDebuggerEvent::Breakpoint: {
521 int bpId = event.breakpointId();
522 if (!consoleWidget && widgetFactory)
523 q->setConsoleWidget(widgetFactory->createConsoleWidget());
524 if (consoleWidget) {
525 consoleWidget->message(QtDebugMsg,
526 QString::fromLatin1("Breakpoint %0 at %1, line %2.")
527 .arg(bpId).arg(event.fileName())
528 .arg(event.lineNumber()));
529 }
530 if (breakpointsModel->breakpointData(bpId).isSingleShot())
531 breakpointsModel->removeBreakpoint(bpId);
532 } break;
533
534 case QScriptDebuggerEvent::Exception: {
535 if (event.hasExceptionHandler()) {
536 // Let the exception be handled like normal.
537 // We may want to add a "Break on all exceptions" option
538 // to be able to customize this behavior.
539 return true;
540 }
541 if (!consoleWidget && widgetFactory)
542 q->setConsoleWidget(widgetFactory->createConsoleWidget());
543 if (!errorLogWidget && widgetFactory)
544 q->setErrorLogWidget(widgetFactory->createErrorLogWidget());
545 if (consoleWidget || errorLogWidget) {
546 QString fn = event.fileName();
547 if (fn.isEmpty()) {
548 if (event.scriptId() != -1)
549 fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId());
550 else
551 fn = QString::fromLatin1("<native>");
552 }
553 QString msg = QString::fromLatin1("Uncaught exception at %0:%1: %2").arg(fn)
554 .arg(event.lineNumber()).arg(event.message());
555 if (consoleWidget)
556 consoleWidget->message(QtCriticalMsg, msg);
557 if (errorLogWidget)
558 errorLogWidget->message(QtCriticalMsg, msg);
559 }
560 } break;
561
562 case QScriptDebuggerEvent::InlineEvalFinished: {
563 QScriptDebuggerValue result = event.scriptValue();
564 Q_ASSERT(console != 0);
565 int action = console->evaluateAction();
566 console->setEvaluateAction(0);
567 switch (action) {
568 case 0: { // eval command
569 if (activeJob) {
570 if (activeJobHibernating) {
571 activeJobHibernating = false;
572 activeJob->evaluateFinished(result);
573 }
574 } else if (consoleWidget) {
575 // ### if the result is an object, need to do a tostring job on it
576// messageHandler->message(QtDebugMsg, result.toString());
577 if (result.type() != QScriptDebuggerValue::UndefinedValue)
578 consoleWidget->message(QtDebugMsg, event.message());
579 }
580 } break;
581 case 1: { // return command
582 QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
583 frontend.scheduleForceReturn(console->currentFrameIndex(), result);
584 } return false;
585 }
586 if (!event.isNestedEvaluate()) {
587 // in the case when evaluate() was called while the
588 // engine was not running, we don't want to enter interactive mode
589 return true;
590 }
591 } break;
592
593 case QScriptDebuggerEvent::DebuggerInvocationRequest: {
594 if (!consoleWidget && widgetFactory)
595 q->setConsoleWidget(widgetFactory->createConsoleWidget());
596 if (consoleWidget) {
597 QString fn = event.fileName();
598 if (fn.isEmpty())
599 fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId());
600 consoleWidget->message(QtDebugMsg,
601 QString::fromLatin1("Debugger invoked from %1, line %2.")
602 .arg(fn).arg(event.lineNumber()));
603 }
604 } break;
605
606 case QScriptDebuggerEvent::ForcedReturn: {
607 } break;
608
609 }
610
611 if (widgetInPaintEvent) {
612 QString msg = QString::fromLatin1("Suspending evaluation in paintEvent() is not supported; resuming.");
613 if (!consoleWidget && widgetFactory)
614 q->setConsoleWidget(widgetFactory->createConsoleWidget());
615 if (!errorLogWidget && widgetFactory)
616 q->setErrorLogWidget(widgetFactory->createErrorLogWidget());
617 if (consoleWidget)
618 consoleWidget->message(QtWarningMsg, msg);
619 if (errorLogWidget)
620 errorLogWidget->message(QtCriticalMsg, msg);
621 return true;
622 }
623
624 if (activeJobHibernating) {
625 // evaluate() did not finish normally (e.g. due to a breakpoint),
626 // so cancel the job that's waiting for it
627 delete activeJob;
628 activeJob = 0;
629 activeJobHibernating = false;
630 }
631
632 startInteraction(event.type(), event.scriptId(), event.lineNumber());
633 return !interactive;
634}
635
636/*!
637 \reimp
638*/
639QString QScriptDebuggerPrivate::toolTip(int frameIndex, int lineNumber,
640 const QStringList &path)
641{
642 if (frameIndex == -1) {
643 if (stackWidget)
644 frameIndex = stackWidget->currentFrameIndex();
645 else
646 frameIndex = console->currentFrameIndex();
647 }
648 // ### cheating for now, need to use async API
649 QScriptEngineDebuggerFrontend *edf = static_cast<QScriptEngineDebuggerFrontend*>(frontend);
650 QScriptDebuggerBackend *backend = edf->backend();
651 QScriptContext *ctx = backend->context(frameIndex);
652 if (!ctx || path.isEmpty())
653 return QString();
654 QScriptContextInfo ctxInfo(ctx);
655 if (ctx->callee().isValid()
656 && ((lineNumber < ctxInfo.functionStartLineNumber())
657 || (lineNumber > ctxInfo.functionEndLineNumber()))) {
658 return QString();
659 }
660 QScriptValueList objects;
661 int pathIndex = 0;
662 if (path.at(0) == QLatin1String("this")) {
663 objects.append(ctx->thisObject());
664 ++pathIndex;
665 } else {
666#if QT_VERSION >= 0x040500
667 objects << ctx->scopeChain();
668#else
669 objects.append(ctx->activationObject());
670#endif
671 }
672 for (int i = 0; i < objects.size(); ++i) {
673 QScriptValue val = objects.at(i);
674 for (int j = pathIndex; val.isValid() && (j < path.size()); ++j) {
675 val = val.property(path.at(j));
676 }
677 if (val.isValid()) {
678 bool hadException = (ctx->state() == QScriptContext::ExceptionState);
679 QString str = val.toString();
680 if (!hadException && backend->engine()->hasUncaughtException())
681 backend->engine()->clearExceptions();
682 return str;
683 }
684 }
685 return QString();
686}
687
688/*!
689 \reimp
690*/
691QScriptCompletionTaskInterface *QScriptDebuggerPrivate::createCompletionTask(
692 const QString &contents, int cursorPosition, int frameIndex, int options)
693{
694 return new QScriptCompletionTask(
695 contents, cursorPosition, frameIndex, frontend,
696 (options & QScriptCompletionProviderInterface::ConsoleCommandCompletion) ? console : 0);
697}
698
699/*!
700 Slot called when a line has been entered in the console widget.
701*/
702void QScriptDebuggerPrivate::_q_onLineEntered(const QString &contents)
703{
704 QScriptDebuggerConsoleCommandJob *commandJob;
705 commandJob = console->consumeInput(contents, consoleWidget, this);
706 if (commandJob != 0) {
707 scheduleJob(commandJob);
708 consoleWidget->setLineContinuationMode(false);
709 } else if (console->hasIncompleteInput()) {
710 consoleWidget->setLineContinuationMode(true);
711 }
712}
713
714/*!
715 Slot called when the current index has changed in the stack widget.
716*/
717void QScriptDebuggerPrivate::_q_onCurrentFrameChanged(int frameIndex)
718{
719 loadLocals(frameIndex);
720 selectScriptForFrame(frameIndex);
721}
722
723/*!
724 Slot called when the current script has changed in the scripts widget.
725*/
726void QScriptDebuggerPrivate::_q_onCurrentScriptChanged(qint64 scriptId)
727{
728 if (codeWidget && (codeWidget->currentScriptId() != scriptId)) {
729 codeWidget->setCurrentScript(scriptId);
730 QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
731 if (view)
732 view->setExecutionLineNumber(-1, /*error=*/false);
733 }
734}
735
736void QScriptDebuggerPrivate::_q_onScriptLocationSelected(int lineNumber)
737{
738 QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
739 if (!view)
740 return;
741 view->gotoLine(lineNumber);
742}
743
744void QScriptDebuggerPrivate::_q_interrupt()
745{
746 executeConsoleCommand(QString::fromLatin1("interrupt"));
747}
748
749void QScriptDebuggerPrivate::_q_continue()
750{
751 executeConsoleCommand(QString::fromLatin1("continue"));
752}
753
754void QScriptDebuggerPrivate::_q_stepInto()
755{
756 executeConsoleCommand(QString::fromLatin1("step"));
757}
758
759void QScriptDebuggerPrivate::_q_stepOver()
760{
761 executeConsoleCommand(QString::fromLatin1("next"));
762}
763
764void QScriptDebuggerPrivate::_q_stepOut()
765{
766 executeConsoleCommand(QString::fromLatin1("finish"));
767}
768
769void QScriptDebuggerPrivate::_q_runToCursor()
770{
771 qint64 scriptId = codeWidget->currentScriptId();
772 int lineNumber = codeWidget->currentView()->cursorLineNumber();
773 QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
774 frontend.scheduleRunToLocation(scriptId, lineNumber);
775}
776
777void QScriptDebuggerPrivate::_q_runToNewScript()
778{
779 QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
780 frontend.scheduleRunToLocation(QString(), -1);
781}
782
783void QScriptDebuggerPrivate::_q_toggleBreakpoint()
784{
785 Q_ASSERT(codeWidget != 0);
786 QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
787 if (!view)
788 return;
789 qint64 scriptId = codeWidget->currentScriptId();
790 int lineNumber = view->cursorLineNumber();
791 Q_ASSERT(breakpointsModel != 0);
792 int bpId = breakpointsModel->resolveBreakpoint(scriptId, lineNumber);
793 if (bpId != -1) {
794 breakpointsModel->deleteBreakpoint(bpId);
795 } else {
796 QScriptBreakpointData data(scriptId, lineNumber);
797 if (scriptsModel)
798 data.setFileName(scriptsModel->scriptData(scriptId).fileName());
799 breakpointsModel->setBreakpoint(data);
800 }
801}
802
803void QScriptDebuggerPrivate::_q_clearDebugOutput()
804{
805 if (debugOutputWidget)
806 debugOutputWidget->clear();
807}
808
809void QScriptDebuggerPrivate::_q_clearErrorLog()
810{
811 if (errorLogWidget)
812 errorLogWidget->clear();
813}
814
815void QScriptDebuggerPrivate::_q_clearConsole()
816{
817 if (consoleWidget)
818 consoleWidget->clear();
819}
820
821void QScriptDebuggerPrivate::executeConsoleCommand(const QString &command)
822{
823 QString tmp = console->incompleteInput();
824 console->setIncompleteInput(QString());
825 QScriptDebuggerJob *job = console->consumeInput(console->commandPrefix() + command, debugOutputWidget, this);
826 console->setIncompleteInput(tmp);
827 if (job != 0) {
828 scheduleJob(job);
829 // once to send the command...
830 QCoreApplication::processEvents();
831 // ... and once to receive the response
832 QCoreApplication::processEvents();
833 }
834}
835
836void QScriptDebuggerPrivate::_q_findInScript()
837{
838 if (!codeFinderWidget && widgetFactory)
839 q_func()->setCodeFinderWidget(widgetFactory->createCodeFinderWidget());
840 if (codeFinderWidget) {
841 codeFinderWidget->show();
842 codeFinderWidget->setFocus(Qt::OtherFocusReason);
843 }
844}
845
846void QScriptDebuggerPrivate::_q_findNextInScript()
847{
848 findCode(codeFinderWidget->text(), codeFinderWidget->findOptions());
849}
850
851void QScriptDebuggerPrivate::_q_findPreviousInScript()
852{
853 int options = codeFinderWidget->findOptions();
854 options |= QTextDocument::FindBackward;
855 findCode(codeFinderWidget->text(), options);
856}
857
858void QScriptDebuggerPrivate::_q_onFindCodeRequest(
859 const QString &exp, int options)
860{
861 findCode(exp, options);
862 if (findNextInScriptAction)
863 findNextInScriptAction->setEnabled(!exp.isEmpty());
864 if (findPreviousInScriptAction)
865 findPreviousInScriptAction->setEnabled(!exp.isEmpty());
866}
867
868void QScriptDebuggerPrivate::findCode(const QString &exp, int options)
869{
870 QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
871 if (!view)
872 return;
873 int result = view->find(exp, options);
874 codeFinderWidget->setOK(((result & 0x1) != 0) || exp.isEmpty());
875 codeFinderWidget->setWrapped((result & 0x2) != 0);
876}
877
878void QScriptDebuggerPrivate::_q_goToLine()
879{
880 QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
881 if (!view)
882 return;
883 bool ok = false;
884 int lineNumber = QInputDialog::getInteger(0, QObject::tr("Go to Line"),
885 QObject::tr("Line:"),
886 view->cursorLineNumber(),
887 1, INT_MAX, 1, &ok);
888 if (ok)
889 view->gotoLine(lineNumber);
890}
891
892class QScriptDebuggerShowLineJob : public QScriptDebuggerCommandSchedulerJob
893{
894public:
895 QScriptDebuggerShowLineJob(qint64 scriptId, int lineNumber,
896 QScriptMessageHandlerInterface *messageHandler,
897 QScriptDebuggerCommandSchedulerInterface *scheduler)
898 : QScriptDebuggerCommandSchedulerJob(scheduler),
899 m_scriptId(scriptId), m_lineNumber(lineNumber),
900 m_messageHandler(messageHandler) {}
901
902 void start()
903 {
904 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
905 frontend.scheduleGetScriptData(m_scriptId);
906 }
907 void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
908 {
909 QScriptScriptData data = response.resultAsScriptData();
910 QString line = data.lines(m_lineNumber, 1).value(0);
911 m_messageHandler->message(QtDebugMsg, QString::fromLatin1("%0\t%1")
912 .arg(m_lineNumber).arg(line));
913 finish();
914 }
915
916private:
917 qint64 m_scriptId;
918 int m_lineNumber;
919 QScriptMessageHandlerInterface *m_messageHandler;
920};
921
922namespace {
923
924class SyncStackJob : public QScriptDebuggerCommandSchedulerJob
925{
926public:
927 SyncStackJob(QScriptDebuggerPrivate *debugger)
928 : QScriptDebuggerCommandSchedulerJob(debugger),
929 m_debugger(debugger), m_index(0) {}
930 void start()
931 {
932 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
933 frontend.scheduleGetContextInfo(m_index); // ### getContextInfos()
934 }
935 void handleResponse(const QScriptDebuggerResponse &response,
936 int)
937 {
938 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
939 if (response.error() != QScriptDebuggerResponse::InvalidContextIndex) {
940 m_infos.append(response.resultAsContextInfo());
941 frontend.scheduleGetContextInfo(++m_index);
942 } else {
943 m_debugger->stackModel->setContextInfos(m_infos);
944 if (m_debugger->stackWidget->currentFrameIndex() == -1)
945 m_debugger->stackWidget->setCurrentFrameIndex(0);
946 m_debugger->stackWidget->setUpdatesEnabled(true);
947 m_debugger->stackWidget->setEnabled(true);
948 finish();
949 }
950 }
951
952private:
953 QScriptDebuggerPrivate *m_debugger;
954 int m_index;
955 QList<QScriptContextInfo> m_infos;
956};
957
958class SyncScriptsJob : public QScriptDebuggerCommandSchedulerJob
959{
960public:
961 SyncScriptsJob(QScriptDebuggerPrivate *debugger)
962 : QScriptDebuggerCommandSchedulerJob(debugger),
963 m_debugger(debugger), m_index(-1) {}
964
965 void start()
966 {
967 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
968 frontend.scheduleScriptsCheckpoint();
969 }
970 void handleResponse(const QScriptDebuggerResponse &response,
971 int)
972 {
973 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
974 if (m_index == -1) {
975 QScriptScriptsDelta delta;
976 delta = qvariant_cast<QScriptScriptsDelta>(response.result());
977
978 const QList<qint64> &removed = delta.second;
979 for (int i = 0; i < removed.size(); ++i)
980 m_debugger->scriptsModel->removeScript(removed.at(i));
981
982 m_added = delta.first;
983 if (!m_added.isEmpty()) {
984 frontend.scheduleGetScriptData(m_added.at(++m_index));
985 } else {
986 m_debugger->scriptsModel->commit();
987 finish();
988 }
989 } else {
990 QScriptScriptData data = response.resultAsScriptData();
991 qint64 scriptId = m_added.at(m_index);
992 m_debugger->scriptsModel->addScript(scriptId, data);
993
994#if QT_VERSION >= 0x040500
995 // ### could be slow, might want to do this in a separate thread
996 QString xml = qt_scriptToXml(data.contents(), data.baseLineNumber());
997 QScriptXmlParser::Result extraInfo = QScriptXmlParser::parse(xml);
998 m_debugger->scriptsModel->addExtraScriptInfo(
999 scriptId, extraInfo.functionsInfo, extraInfo.executableLineNumbers);
1000#endif
1001
1002 if (++m_index < m_added.size())
1003 frontend.scheduleGetScriptData(m_added.at(m_index));
1004 else {
1005 m_debugger->scriptsModel->commit();
1006 finish();
1007 }
1008 }
1009 }
1010
1011private:
1012 QScriptDebuggerPrivate *m_debugger;
1013 int m_index;
1014 QList<qint64> m_added;
1015};
1016
1017class SyncBreakpointsJob : public QScriptDebuggerCommandSchedulerJob
1018{
1019public:
1020 SyncBreakpointsJob(QScriptDebuggerPrivate *debugger)
1021 : QScriptDebuggerCommandSchedulerJob(debugger),
1022 m_debugger(debugger) {}
1023 void start()
1024 {
1025 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1026 frontend.scheduleGetBreakpoints();
1027 }
1028 void handleResponse(const QScriptDebuggerResponse &response,
1029 int)
1030 {
1031 QScriptBreakpointMap breakpoints = response.resultAsBreakpoints();
1032 QScriptBreakpointMap::const_iterator it;
1033 for (it = breakpoints.constBegin(); it != breakpoints.constEnd(); ++it) {
1034 int id = it.key();
1035 QScriptBreakpointData newData = it.value();
1036 QScriptBreakpointData existingData = m_debugger->breakpointsModel->breakpointData(id);
1037 if (existingData.isValid() && (existingData != newData))
1038 m_debugger->breakpointsModel->modifyBreakpoint(id, newData);
1039 }
1040 finish();
1041 }
1042
1043private:
1044 QScriptDebuggerPrivate *m_debugger;
1045 int m_index;
1046 QList<QScriptContextInfo> m_infos;
1047};
1048
1049class SyncLocalsJob : public QScriptDebuggerCommandSchedulerJob
1050{
1051public:
1052 SyncLocalsJob(QScriptDebuggerPrivate *debugger)
1053 : QScriptDebuggerCommandSchedulerJob(debugger),
1054 m_debugger(debugger) {}
1055
1056 void start()
1057 {
1058 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1059 frontend.scheduleContextsCheckpoint();
1060 }
1061 void handleResponse(const QScriptDebuggerResponse &response,
1062 int)
1063 {
1064 QScriptContextsDelta delta = qvariant_cast<QScriptContextsDelta>(response.result());
1065 for (int i = 0; i < delta.first.size(); ++i) {
1066 QScriptDebuggerLocalsModel *model = m_debugger->localsModels.take(delta.first.at(i));
1067 delete model;
1068 }
1069 finish();
1070 }
1071
1072private:
1073 QScriptDebuggerPrivate *m_debugger;
1074};
1075
1076class LoadLocalsJob : public QScriptDebuggerCommandSchedulerJob
1077{
1078public:
1079 LoadLocalsJob(QScriptDebuggerPrivate *debugger, int frameIndex)
1080 : QScriptDebuggerCommandSchedulerJob(debugger),
1081 m_debugger(debugger), m_frameIndex(frameIndex), m_state(0) {}
1082
1083 void start()
1084 {
1085 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1086 frontend.scheduleGetContextId(m_frameIndex);
1087 }
1088 void handleResponse(const QScriptDebuggerResponse &response,
1089 int)
1090 {
1091 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1092 qint64 contextId = response.resultAsLongLong();
1093 QScriptDebuggerLocalsModel *model = m_debugger->localsModels.value(contextId);
1094 if (model) {
1095 model->sync(m_frameIndex);
1096 } else {
1097 model = m_debugger->createLocalsModel();
1098 m_debugger->localsModels.insert(contextId, model);
1099 model->init(m_frameIndex);
1100 }
1101 if (m_debugger->localsWidget) {
1102 if (m_debugger->localsWidget->localsModel() != model) // ### bug in qtreeview
1103 m_debugger->localsWidget->setLocalsModel(model);
1104 m_debugger->localsWidget->setUpdatesEnabled(true);
1105 m_debugger->localsWidget->setEnabled(true);
1106 }
1107 finish();
1108 }
1109
1110private:
1111 QScriptDebuggerPrivate *m_debugger;
1112 int m_frameIndex;
1113 int m_state;
1114};
1115
1116class EmitStoppedSignalJob : public QScriptDebuggerJob
1117{
1118public:
1119 EmitStoppedSignalJob(QScriptDebuggerPrivate *debugger)
1120 : m_debugger(debugger) {}
1121
1122 void start()
1123 {
1124 m_debugger->emitStoppedSignal();
1125 finish();
1126 }
1127
1128private:
1129 QScriptDebuggerPrivate *m_debugger;
1130};
1131
1132} // namespace
1133
1134void QScriptDebuggerPrivate::startInteraction(QScriptDebuggerEvent::Type type,
1135 qint64 scriptId, int lineNumber)
1136{
1137 Q_Q(QScriptDebugger);
1138 if (type != QScriptDebuggerEvent::InlineEvalFinished) {
1139 if (stackWidget)
1140 stackWidget->setCurrentFrameIndex(0);
1141 console->setCurrentFrameIndex(0);
1142 console->setCurrentScriptId(scriptId);
1143 console->setCurrentLineNumber(lineNumber);
1144 }
1145
1146 if ((scriptId != -1) && consoleWidget) {
1147 QScriptDebuggerJob *job = new QScriptDebuggerShowLineJob(scriptId, lineNumber, consoleWidget, this);
1148 scheduleJob(job);
1149 }
1150
1151 sync();
1152
1153 if (!interactive) {
1154 interactive = true;
1155 if (updatesEnabledTimerId != -1) {
1156 q->killTimer(updatesEnabledTimerId);
1157 updatesEnabledTimerId = -1;
1158 }
1159 console->bumpSessionId();
1160 scheduleJob(new EmitStoppedSignalJob(this));
1161 }
1162
1163 if (consoleWidget)
1164 consoleWidget->activateWindow();
1165 else if (codeWidget)
1166 codeWidget->activateWindow();
1167
1168 if (continueAction)
1169 continueAction->setEnabled(true);
1170 if (stepIntoAction)
1171 stepIntoAction->setEnabled(true);
1172 if (stepOverAction)
1173 stepOverAction->setEnabled(true);
1174 if (stepOutAction)
1175 stepOutAction->setEnabled(true);
1176 if (runToCursorAction)
1177 runToCursorAction->setEnabled(true);
1178 if (runToNewScriptAction)
1179 runToNewScriptAction->setEnabled(true);
1180 if (interruptAction)
1181 interruptAction->setEnabled(false);
1182
1183 bool hasScript = (codeWidget != 0);
1184 if (findInScriptAction)
1185 findInScriptAction->setEnabled(hasScript);
1186 if (toggleBreakpointAction)
1187 toggleBreakpointAction->setEnabled(hasScript);
1188 if (goToLineAction)
1189 goToLineAction->setEnabled(hasScript);
1190}
1191
1192void QScriptDebuggerPrivate::sync()
1193{
1194 if (localsWidget) {
1195 QScriptDebuggerJob *job = new SyncLocalsJob(this);
1196 scheduleJob(job);
1197 }
1198 if (scriptsModel) {
1199 QScriptDebuggerJob *job = new SyncScriptsJob(this);
1200 scheduleJob(job);
1201 }
1202 if (stackModel) {
1203 QScriptDebuggerJob *job = new SyncStackJob(this);
1204 scheduleJob(job);
1205 }
1206 if (breakpointsModel) {
1207 // need to sync because the ignore-count could have changed
1208 QScriptDebuggerJob *job = new SyncBreakpointsJob(this);
1209 scheduleJob(job);
1210 }
1211
1212 if (stackWidget && (stackWidget->currentFrameIndex() != -1)) {
1213 int index = stackWidget->currentFrameIndex();
1214 loadLocals(index);
1215 selectScriptForFrame(index);
1216 } else if (codeWidget && (console->currentFrameIndex() != -1)) {
1217 selectScriptForFrame(console->currentFrameIndex());
1218 }
1219}
1220
1221void QScriptDebuggerPrivate::loadLocals(int frameIndex)
1222{
1223 LoadLocalsJob *job = new LoadLocalsJob(this, frameIndex);
1224 scheduleJob(job);
1225}
1226
1227QScriptDebuggerLocalsModel *QScriptDebuggerPrivate::createLocalsModel()
1228{
1229 return new QScriptDebuggerLocalsModel(this, this, q_func());
1230}
1231
1232namespace {
1233
1234class ShowFrameCodeJob : public QScriptDebuggerCommandSchedulerJob
1235{
1236public:
1237 ShowFrameCodeJob(QScriptDebuggerPrivate *debugger, int frameIndex)
1238 : QScriptDebuggerCommandSchedulerJob(debugger),
1239 m_debugger(debugger), m_frameIndex(frameIndex) {}
1240
1241 void start()
1242 {
1243 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1244 frontend.scheduleGetContextInfo(m_frameIndex);
1245 }
1246 void handleResponse(const QScriptDebuggerResponse &response,
1247 int)
1248 {
1249 if (m_info.isNull()) {
1250 m_info = response.resultAsContextInfo();
1251 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
1252 frontend.scheduleGetContextState(m_frameIndex);
1253 } else {
1254 int contextState = response.resultAsInt();
1255 bool error = (contextState == QScriptContext::ExceptionState);
1256 if (m_debugger->scriptsWidget) {
1257 m_debugger->scriptsWidget->setCurrentScript(m_info.scriptId());
1258 }
1259 if (m_debugger->codeWidget) {
1260 m_debugger->codeWidget->setCurrentScript(m_info.scriptId());
1261 QScriptDebuggerCodeViewInterface *view = m_debugger->codeWidget->currentView();
1262 if (view)
1263 view->setExecutionLineNumber(m_info.lineNumber(), error);
1264 }
1265 finish();
1266 }
1267 }
1268
1269private:
1270 QScriptDebuggerPrivate *m_debugger;
1271 int m_frameIndex;
1272 QScriptContextInfo m_info;
1273};
1274
1275} // namespace
1276
1277void QScriptDebuggerPrivate::selectScriptForFrame(int frameIndex)
1278{
1279 QScriptDebuggerJob *job = new ShowFrameCodeJob(this, frameIndex);
1280 scheduleJob(job);
1281}
1282
1283void QScriptDebuggerPrivate::emitStoppedSignal()
1284{
1285 emit q_func()->stopped();
1286}
1287
1288/*!
1289 Constructs a new QScriptDebugger object.
1290*/
1291QScriptDebugger::QScriptDebugger(QObject *parent)
1292 : QObject(*new QScriptDebuggerPrivate, parent)
1293{
1294 ++scriptDebuggerCount;
1295}
1296
1297/*!
1298 Destroys this QScriptDebugger.
1299*/
1300QScriptDebugger::~QScriptDebugger()
1301{
1302 --scriptDebuggerCount;
1303 if ((scriptDebuggerCount == 0) && eventCallbackRegistered) {
1304 eventCallbackRegistered = false;
1305 QInternal::unregisterCallback(QInternal::EventNotifyCallback,
1306 scriptDebuggerEventCallback);
1307 }
1308}
1309
1310/*!
1311 \internal
1312*/
1313QScriptDebugger::QScriptDebugger(QScriptDebuggerPrivate &dd, QObject *parent)
1314 : QObject(dd, parent)
1315{
1316}
1317
1318QScriptDebuggerFrontend *QScriptDebugger::frontend() const
1319{
1320 Q_D(const QScriptDebugger);
1321 return d->frontend;
1322}
1323
1324void QScriptDebugger::setFrontend(QScriptDebuggerFrontend *frontend)
1325{
1326 Q_D(QScriptDebugger);
1327 if (d->frontend)
1328 d->frontend->setEventHandler(0);
1329 d->frontend = frontend;
1330 if (frontend) {
1331 frontend->setEventHandler(d);
1332 if (!eventCallbackRegistered) {
1333 eventCallbackRegistered = true;
1334 QInternal::registerCallback(QInternal::EventNotifyCallback,
1335 scriptDebuggerEventCallback);
1336 }
1337 }
1338}
1339
1340QScriptDebuggerConsoleWidgetInterface *QScriptDebugger::consoleWidget() const
1341{
1342 Q_D(const QScriptDebugger);
1343 return d->consoleWidget;
1344}
1345
1346void QScriptDebugger::setConsoleWidget(QScriptDebuggerConsoleWidgetInterface *consoleWidget)
1347{
1348 Q_D(QScriptDebugger);
1349 if (d->consoleWidget) {
1350 QObject::disconnect(d->consoleWidget, 0, this, 0);
1351 }
1352 d->consoleWidget = consoleWidget;
1353 if (consoleWidget) {
1354 consoleWidget->setCommandHistorian(d->console);
1355 consoleWidget->setCompletionProvider(d);
1356 QObject::connect(consoleWidget, SIGNAL(lineEntered(QString)),
1357 this, SLOT(_q_onLineEntered(QString)));
1358
1359 d->console->showDebuggerInfoMessage(consoleWidget);
1360 }
1361}
1362
1363QScriptDebuggerStackWidgetInterface *QScriptDebugger::stackWidget() const
1364{
1365 Q_D(const QScriptDebugger);
1366 return d->stackWidget;
1367}
1368
1369void QScriptDebugger::setStackWidget(QScriptDebuggerStackWidgetInterface *stackWidget)
1370{
1371 Q_D(QScriptDebugger);
1372 if (d->stackWidget) {
1373 QObject::disconnect(d->stackWidget, 0, this, 0);
1374 }
1375 d->stackWidget = stackWidget;
1376 if (stackWidget) {
1377 if (!d->stackModel) {
1378 d->stackModel = new QScriptDebuggerStackModel(this);
1379 if (d->interactive)
1380 d->scheduleJob(new SyncStackJob(d));
1381 }
1382 stackWidget->setStackModel(d->stackModel);
1383 QObject::connect(stackWidget, SIGNAL(currentFrameChanged(int)),
1384 this, SLOT(_q_onCurrentFrameChanged(int)));
1385 }
1386}
1387
1388QScriptDebuggerScriptsWidgetInterface *QScriptDebugger::scriptsWidget() const
1389{
1390 Q_D(const QScriptDebugger);
1391 return d->scriptsWidget;
1392}
1393
1394void QScriptDebugger::setScriptsWidget(QScriptDebuggerScriptsWidgetInterface *scriptsWidget)
1395{
1396 Q_D(QScriptDebugger);
1397 if (d->scriptsWidget) {
1398 QObject::disconnect(d->scriptsWidget, 0, this, 0);
1399 }
1400 d->scriptsWidget = scriptsWidget;
1401 if (scriptsWidget) {
1402 if (!d->scriptsModel) {
1403 d->scriptsModel = new QScriptDebuggerScriptsModel(this);
1404 if (d->interactive)
1405 d->scheduleJob(new SyncScriptsJob(d));
1406 }
1407 scriptsWidget->setScriptsModel(d->scriptsModel);
1408 QObject::connect(scriptsWidget, SIGNAL(currentScriptChanged(qint64)),
1409 this, SLOT(_q_onCurrentScriptChanged(qint64)));
1410 QObject::connect(d->scriptsWidget, SIGNAL(scriptLocationSelected(int)),
1411 this, SLOT(_q_onScriptLocationSelected(int)));
1412 }
1413}
1414
1415QScriptDebuggerLocalsWidgetInterface *QScriptDebugger::localsWidget() const
1416{
1417 Q_D(const QScriptDebugger);
1418 return d->localsWidget;
1419}
1420
1421void QScriptDebugger::setLocalsWidget(QScriptDebuggerLocalsWidgetInterface *localsWidget)
1422{
1423 Q_D(QScriptDebugger);
1424 if (d->localsWidget) {
1425 // ### d->localsWidget->setLocalsModel(0);
1426 }
1427 localsWidget->setCompletionProvider(d);
1428 d->localsWidget = localsWidget;
1429}
1430
1431QScriptDebuggerCodeWidgetInterface *QScriptDebugger::codeWidget() const
1432{
1433 Q_D(const QScriptDebugger);
1434 return d->codeWidget;
1435}
1436
1437void QScriptDebugger::setCodeWidget(QScriptDebuggerCodeWidgetInterface *codeWidget)
1438{
1439 Q_D(QScriptDebugger);
1440 if (d->codeWidget) {
1441 d->codeWidget->removeEventFilter(this);
1442 }
1443 d->codeWidget = codeWidget;
1444 if (codeWidget) {
1445 if (!d->scriptsModel) {
1446 d->scriptsModel = new QScriptDebuggerScriptsModel(this);
1447 if (d->interactive)
1448 d->scheduleJob(new SyncScriptsJob(d));
1449 }
1450 codeWidget->setScriptsModel(d->scriptsModel);
1451 if (!d->breakpointsModel) {
1452 d->breakpointsModel = new QScriptBreakpointsModel(d, d, this);
1453 if (d->interactive)
1454 d->scheduleJob(new SyncBreakpointsJob(d));
1455 }
1456 codeWidget->setBreakpointsModel(d->breakpointsModel);
1457 codeWidget->setToolTipProvider(d);
1458 codeWidget->installEventFilter(this);
1459 }
1460 bool hasScript = (codeWidget != 0) && (codeWidget->currentView() != 0);
1461 if (d->findInScriptAction)
1462 d->findInScriptAction->setEnabled(hasScript && (d->codeFinderWidget != 0));
1463 if (d->goToLineAction)
1464 d->goToLineAction->setEnabled(hasScript);
1465 if (d->toggleBreakpointAction)
1466 d->toggleBreakpointAction->setEnabled(hasScript);
1467}
1468
1469QScriptDebuggerCodeFinderWidgetInterface *QScriptDebugger::codeFinderWidget() const
1470{
1471 Q_D(const QScriptDebugger);
1472 return d->codeFinderWidget;
1473}
1474
1475void QScriptDebugger::setCodeFinderWidget(QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget)
1476{
1477 Q_D(QScriptDebugger);
1478 if (d->codeFinderWidget) {
1479 QObject::disconnect(d->codeFinderWidget, 0, this, 0);
1480 }
1481 d->codeFinderWidget = codeFinderWidget;
1482 if (codeFinderWidget) {
1483 QObject::connect(codeFinderWidget, SIGNAL(findRequest(QString,int)),
1484 this, SLOT(_q_onFindCodeRequest(QString,int)));
1485 }
1486 if (d->findInScriptAction) {
1487 d->findInScriptAction->setEnabled(
1488 (codeFinderWidget != 0)
1489 && (d->codeWidget != 0)
1490 && (d->codeWidget->currentView() != 0));
1491 }
1492}
1493
1494QScriptDebugOutputWidgetInterface *QScriptDebugger::debugOutputWidget() const
1495{
1496 Q_D(const QScriptDebugger);
1497 return d->debugOutputWidget;
1498}
1499
1500void QScriptDebugger::setDebugOutputWidget(QScriptDebugOutputWidgetInterface *debugOutputWidget)
1501{
1502 Q_D(QScriptDebugger);
1503 d->debugOutputWidget = debugOutputWidget;
1504}
1505
1506QScriptBreakpointsWidgetInterface *QScriptDebugger::breakpointsWidget() const
1507{
1508 Q_D(const QScriptDebugger);
1509 return d->breakpointsWidget;
1510}
1511
1512void QScriptDebugger::setBreakpointsWidget(QScriptBreakpointsWidgetInterface *breakpointsWidget)
1513{
1514 Q_D(QScriptDebugger);
1515 if (d->breakpointsWidget) {
1516 // ### invalidate
1517 }
1518 d->breakpointsWidget = breakpointsWidget;
1519 if (breakpointsWidget) {
1520 if (!d->breakpointsModel) {
1521 d->breakpointsModel = new QScriptBreakpointsModel(d, d, this);
1522 if (d->interactive)
1523 d->scheduleJob(new SyncBreakpointsJob(d));
1524 }
1525 d->breakpointsWidget->setBreakpointsModel(d->breakpointsModel);
1526 d->breakpointsWidget->setScriptsModel(d->scriptsModel);
1527 }
1528}
1529
1530QScriptErrorLogWidgetInterface *QScriptDebugger::errorLogWidget() const
1531{
1532 Q_D(const QScriptDebugger);
1533 return d->errorLogWidget;
1534}
1535
1536void QScriptDebugger::setErrorLogWidget(QScriptErrorLogWidgetInterface *errorLogWidget)
1537{
1538 Q_D(QScriptDebugger);
1539 d->errorLogWidget = errorLogWidget;
1540}
1541
1542QScriptDebuggerWidgetFactoryInterface *QScriptDebugger::widgetFactory() const
1543{
1544 Q_D(const QScriptDebugger);
1545 return d->widgetFactory;
1546}
1547
1548void QScriptDebugger::setWidgetFactory(QScriptDebuggerWidgetFactoryInterface *factory)
1549{
1550 Q_D(QScriptDebugger);
1551 d->widgetFactory = factory;
1552}
1553
1554QAction *QScriptDebugger::interruptAction(QObject *parent) const
1555{
1556 Q_D(const QScriptDebugger);
1557 if (!d->interruptAction) {
1558 QIcon interruptIcon;
1559 interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("interrupt.png")), QIcon::Normal);
1560 interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_interrupt.png")), QIcon::Disabled);
1561 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1562 that->d_func()->interruptAction = new QAction(interruptIcon, QObject::tr("Interrupt"), parent);
1563 d->interruptAction->setEnabled(!d->interactive);
1564 d->interruptAction->setShortcut(QObject::tr("Shift+F5"));
1565 QObject::connect(d->interruptAction, SIGNAL(triggered()),
1566 that, SLOT(_q_interrupt()));
1567 }
1568 return d->interruptAction;
1569}
1570
1571QAction *QScriptDebugger::continueAction(QObject *parent) const
1572{
1573 Q_D(const QScriptDebugger);
1574 if (!d->continueAction) {
1575 QIcon continueIcon;
1576 continueIcon.addPixmap(d->pixmap(QString::fromLatin1("play.png")), QIcon::Normal);
1577 continueIcon.addPixmap(d->pixmap(QString::fromLatin1("d_play.png")), QIcon::Disabled);
1578 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1579 that->d_func()->continueAction = new QAction(continueIcon, QObject::tr("Continue"), parent);
1580 d->continueAction->setEnabled(d->interactive);
1581 d->continueAction->setShortcut(QObject::tr("F5"));
1582 QObject::connect(d->continueAction, SIGNAL(triggered()),
1583 that, SLOT(_q_continue()));
1584 }
1585 return d->continueAction;
1586}
1587
1588QAction *QScriptDebugger::stepIntoAction(QObject *parent) const
1589{
1590 Q_D(const QScriptDebugger);
1591 if (!d->stepIntoAction) {
1592 QIcon stepIntoIcon;
1593 stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("stepinto.png")), QIcon::Normal);
1594 stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepinto.png")), QIcon::Disabled);
1595 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1596 that->d_func()->stepIntoAction = new QAction(stepIntoIcon, QObject::tr("Step Into"), parent);
1597 d->stepIntoAction->setEnabled(d->interactive);
1598 d->stepIntoAction->setShortcut(QObject::tr("F11"));
1599 QObject::connect(d->stepIntoAction, SIGNAL(triggered()),
1600 that, SLOT(_q_stepInto()));
1601 }
1602 return d->stepIntoAction;
1603}
1604
1605QAction *QScriptDebugger::stepOverAction(QObject *parent) const
1606{
1607 Q_D(const QScriptDebugger);
1608 if (!d->stepOverAction) {
1609 QIcon stepOverIcon;
1610 stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("stepover.png")), QIcon::Normal);
1611 stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepover.png")), QIcon::Disabled);
1612 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1613 that->d_func()->stepOverAction = new QAction(stepOverIcon, QObject::tr("Step Over"), parent);
1614 d->stepOverAction->setEnabled(d->interactive);
1615 d->stepOverAction->setShortcut(QObject::tr("F10"));
1616 QObject::connect(d->stepOverAction, SIGNAL(triggered()),
1617 that, SLOT(_q_stepOver()));
1618 }
1619 return d->stepOverAction;
1620}
1621
1622QAction *QScriptDebugger::stepOutAction(QObject *parent) const
1623{
1624 Q_D(const QScriptDebugger);
1625 if (!d->stepOutAction) {
1626 QIcon stepOutIcon;
1627 stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("stepout.png")), QIcon::Normal);
1628 stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepout.png")), QIcon::Disabled);
1629 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1630 that->d_func()->stepOutAction = new QAction(stepOutIcon, QObject::tr("Step Out"), parent);
1631 d->stepOutAction->setEnabled(d->interactive);
1632 d->stepOutAction->setShortcut(QObject::tr("Shift+F11"));
1633 QObject::connect(d->stepOutAction, SIGNAL(triggered()),
1634 that, SLOT(_q_stepOut()));
1635 }
1636 return d->stepOutAction;
1637}
1638
1639QAction *QScriptDebugger::runToCursorAction(QObject *parent) const
1640{
1641 Q_D(const QScriptDebugger);
1642 if (!d->runToCursorAction) {
1643 QIcon runToCursorIcon;
1644 runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("runtocursor.png")), QIcon::Normal);
1645 runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("d_runtocursor.png")), QIcon::Disabled);
1646 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1647 that->d_func()->runToCursorAction = new QAction(runToCursorIcon, QObject::tr("Run to Cursor"), parent);
1648 d->runToCursorAction->setEnabled(d->interactive);
1649 d->runToCursorAction->setShortcut(QObject::tr("Ctrl+F10"));
1650 QObject::connect(d->runToCursorAction, SIGNAL(triggered()),
1651 that, SLOT(_q_runToCursor()));
1652 }
1653 return d->runToCursorAction;
1654}
1655
1656QAction *QScriptDebugger::runToNewScriptAction(QObject *parent) const
1657{
1658 Q_D(const QScriptDebugger);
1659 if (!d->runToNewScriptAction) {
1660 QIcon runToNewScriptIcon;
1661 runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("runtonewscript.png")), QIcon::Normal);
1662 runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_breakonscriptload.png")), QIcon::Disabled);
1663 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1664 that->d_func()->runToNewScriptAction = new QAction(runToNewScriptIcon,
1665 QObject::tr("Run to New Script"), parent);
1666 d->runToNewScriptAction->setEnabled(d->interactive);
1667 QObject::connect(d->runToNewScriptAction, SIGNAL(triggered()),
1668 that, SLOT(_q_runToNewScript()));
1669 }
1670 return d->runToNewScriptAction;
1671}
1672
1673QAction *QScriptDebugger::toggleBreakpointAction(QObject *parent) const
1674{
1675 Q_D(const QScriptDebugger);
1676 if (!d->toggleBreakpointAction) {
1677 QIcon toggleBreakpointIcon;
1678 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1679 that->d_func()->toggleBreakpointAction = new QAction(toggleBreakpointIcon,
1680 QObject::tr("Toggle Breakpoint"), parent);
1681 d->toggleBreakpointAction->setShortcut(QObject::tr("F9"));
1682 d->toggleBreakpointAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0));
1683 QObject::connect(d->toggleBreakpointAction, SIGNAL(triggered()),
1684 that, SLOT(_q_toggleBreakpoint()));
1685 }
1686 return d->toggleBreakpointAction;
1687}
1688
1689QAction *QScriptDebugger::clearDebugOutputAction(QObject *parent) const
1690{
1691 Q_D(const QScriptDebugger);
1692 if (!d->clearDebugOutputAction) {
1693 QIcon clearDebugOutputIcon;
1694 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1695 that->d_func()->clearDebugOutputAction = new QAction(clearDebugOutputIcon, QObject::tr("Clear Debug Output"), parent);
1696 QObject::connect(d->clearDebugOutputAction, SIGNAL(triggered()),
1697 that, SLOT(_q_clearDebugOutput()));
1698 }
1699 return d->clearDebugOutputAction;
1700}
1701
1702QAction *QScriptDebugger::clearErrorLogAction(QObject *parent) const
1703{
1704 Q_D(const QScriptDebugger);
1705 if (!d->clearErrorLogAction) {
1706 QIcon clearErrorLogIcon;
1707 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1708 that->d_func()->clearErrorLogAction = new QAction(clearErrorLogIcon, QObject::tr("Clear Error Log"), parent);
1709 QObject::connect(d->clearErrorLogAction, SIGNAL(triggered()),
1710 that, SLOT(_q_clearErrorLog()));
1711 }
1712 return d->clearErrorLogAction;
1713}
1714
1715QAction *QScriptDebugger::clearConsoleAction(QObject *parent) const
1716{
1717 Q_D(const QScriptDebugger);
1718 if (!d->clearConsoleAction) {
1719 QIcon clearConsoleIcon;
1720 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1721 that->d_func()->clearConsoleAction = new QAction(clearConsoleIcon, QObject::tr("Clear Console"), parent);
1722 QObject::connect(d->clearConsoleAction, SIGNAL(triggered()),
1723 that, SLOT(_q_clearConsole()));
1724 }
1725 return d->clearConsoleAction;
1726}
1727
1728QAction *QScriptDebugger::findInScriptAction(QObject *parent) const
1729{
1730 Q_D(const QScriptDebugger);
1731 if (!d->findInScriptAction) {
1732 QIcon findInScriptIcon;
1733 findInScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("find.png")), QIcon::Normal);
1734 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1735 that->d_func()->findInScriptAction = new QAction(findInScriptIcon, QObject::tr("&Find in Script..."), parent);
1736 d->findInScriptAction->setShortcut(QObject::tr("Ctrl+F"));
1737 d->findInScriptAction->setEnabled(
1738 (d->codeFinderWidget != 0)
1739 && (d->codeWidget != 0)
1740 && (d->codeWidget->currentView() != 0));
1741 QObject::connect(d->findInScriptAction, SIGNAL(triggered()),
1742 that, SLOT(_q_findInScript()));
1743 }
1744 return d->findInScriptAction;
1745}
1746
1747QAction *QScriptDebugger::findNextInScriptAction(QObject *parent) const
1748{
1749 Q_D(const QScriptDebugger);
1750 if (!d->findNextInScriptAction) {
1751 QIcon findNextInScriptIcon;
1752 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1753 that->d_func()->findNextInScriptAction = new QAction(findNextInScriptIcon, QObject::tr("Find &Next"), parent);
1754 d->findNextInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty());
1755 d->findNextInScriptAction->setShortcut(QObject::tr("F3"));
1756 QObject::connect(d->findNextInScriptAction, SIGNAL(triggered()),
1757 that, SLOT(_q_findNextInScript()));
1758 }
1759 return d->findNextInScriptAction;
1760}
1761
1762QAction *QScriptDebugger::findPreviousInScriptAction(QObject *parent) const
1763{
1764 Q_D(const QScriptDebugger);
1765 if (!d->findPreviousInScriptAction) {
1766 QIcon findPreviousInScriptIcon;
1767 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1768 that->d_func()->findPreviousInScriptAction = new QAction(findPreviousInScriptIcon, QObject::tr("Find &Previous"), parent);
1769 d->findPreviousInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty());
1770 d->findPreviousInScriptAction->setShortcut(QObject::tr("Shift+F3"));
1771 QObject::connect(d->findPreviousInScriptAction, SIGNAL(triggered()),
1772 that, SLOT(_q_findPreviousInScript()));
1773 }
1774 return d->findPreviousInScriptAction;
1775}
1776
1777QAction *QScriptDebugger::goToLineAction(QObject *parent) const
1778{
1779 Q_D(const QScriptDebugger);
1780 if (!d->goToLineAction) {
1781 QIcon goToLineIcon;
1782 QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
1783 that->d_func()->goToLineAction = new QAction(goToLineIcon, QObject::tr("Go to Line"), parent);
1784 d->goToLineAction->setShortcut(QObject::tr("Ctrl+G"));
1785 d->goToLineAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0));
1786 QObject::connect(d->goToLineAction, SIGNAL(triggered()),
1787 that, SLOT(_q_goToLine()));
1788 }
1789 return d->goToLineAction;
1790}
1791
1792/*!
1793 \reimp
1794*/
1795bool QScriptDebugger::eventFilter(QObject *watched, QEvent *e)
1796{
1797 Q_D(QScriptDebugger);
1798 if (watched == d->codeWidget) {
1799 if (e->type() == QEvent::KeyPress) {
1800 d->_q_findInScript();
1801 d->codeFinderWidget->setText(static_cast<QKeyEvent*>(e)->text());
1802 return true;
1803 }
1804 }
1805 return false;
1806}
1807
1808/*!
1809 \reimp
1810*/
1811void QScriptDebugger::timerEvent(QTimerEvent *e)
1812{
1813 Q_D(QScriptDebugger);
1814 if (e->timerId() == d->updatesEnabledTimerId) {
1815 killTimer(d->updatesEnabledTimerId);
1816 d->updatesEnabledTimerId = -1;
1817 if (d->stackWidget)
1818 d->stackWidget->setUpdatesEnabled(true);
1819 if (d->localsWidget)
1820 d->localsWidget->setUpdatesEnabled(true);
1821 } else {
1822 QObject::timerEvent(e);
1823 }
1824}
1825
1826QT_END_NAMESPACE
1827
1828#include "moc_qscriptdebugger_p.cpp"
Note: See TracBrowser for help on using the repository browser.