src/scripttools/debugging/qscriptdebugger.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtSCriptTools module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 "private/qobject_p.h"
       
    79 
       
    80 #include <QtScript/qscriptcontext.h>
       
    81 #include <QtScript/qscriptcontextinfo.h>
       
    82 
       
    83 #include <QtCore/qcoreapplication.h>
       
    84 #include <QtCore/qdir.h>
       
    85 #include <QtCore/qfileinfo.h>
       
    86 #include <QtCore/qstringlist.h>
       
    87 #include <QtCore/qdebug.h>
       
    88 
       
    89 #include <QtGui/qaction.h>
       
    90 #include <QtGui/qevent.h>
       
    91 #include <QtGui/qicon.h>
       
    92 #include <QtGui/qinputdialog.h>
       
    93 #include <QtGui/qmenu.h>
       
    94 #include <QtGui/qtoolbar.h>
       
    95 #include <QtGui/qtooltip.h>
       
    96 
       
    97 QT_BEGIN_NAMESPACE
       
    98 typedef QPair<QList<qint64>, QList<qint64> > QScriptScriptsDelta;
       
    99 typedef QPair<QList<qint64>, QList<qint64> > QScriptContextsDelta;
       
   100 QT_END_NAMESPACE
       
   101 
       
   102 Q_DECLARE_METATYPE(QScriptScriptsDelta)
       
   103 
       
   104 QT_BEGIN_NAMESPACE
       
   105 
       
   106 Q_SCRIPT_EXPORT QString qt_scriptToXml(const QString &program, int lineNumber = 1);
       
   107 
       
   108 namespace {
       
   109 
       
   110 static int scriptDebuggerCount = 0;
       
   111 static bool eventCallbackRegistered = false;
       
   112 static bool widgetInPaintEvent = false;
       
   113 
       
   114 static bool scriptDebuggerEventCallback(void **data)
       
   115 {
       
   116     QEvent *event = reinterpret_cast<QEvent*>(data[1]);
       
   117     if (event->type() == QEvent::Paint) {
       
   118         QObject *receiver = reinterpret_cast<QObject*>(data[0]);
       
   119         bool was = widgetInPaintEvent;
       
   120         widgetInPaintEvent = true;
       
   121         QCoreApplication::instance()->notify(receiver, event);
       
   122         widgetInPaintEvent = was;
       
   123         bool *result = reinterpret_cast<bool*>(data[2]);
       
   124         *result = true;
       
   125         return true;
       
   126     }
       
   127     return false;
       
   128 }
       
   129 
       
   130 }
       
   131 
       
   132 /*!
       
   133   \since 4.5
       
   134   \class QScriptDebugger
       
   135   \internal
       
   136 
       
   137   \brief The QScriptDebugger class provides a Qt Script debugger.
       
   138 
       
   139   \ingroup script
       
   140 
       
   141 */
       
   142 
       
   143 class QScriptDebuggerPrivate
       
   144     : public QObjectPrivate,
       
   145       public QScriptDebuggerCommandSchedulerInterface,
       
   146       public QScriptDebuggerJobSchedulerInterface,
       
   147       public QScriptDebuggerEventHandlerInterface,
       
   148       public QScriptDebuggerResponseHandlerInterface,
       
   149       public QScriptCompletionProviderInterface,
       
   150       public QScriptToolTipProviderInterface
       
   151 {
       
   152     Q_DECLARE_PUBLIC(QScriptDebugger)
       
   153 public:
       
   154     QScriptDebuggerPrivate();
       
   155     ~QScriptDebuggerPrivate();
       
   156 
       
   157     int scheduleJob(QScriptDebuggerJob *job);
       
   158     void finishJob(QScriptDebuggerJob *job);
       
   159     void hibernateUntilEvaluateFinished(QScriptDebuggerJob *job);
       
   160 
       
   161     void maybeStartNewJob();
       
   162 
       
   163     int scheduleCommand(const QScriptDebuggerCommand &command,
       
   164                         QScriptDebuggerResponseHandlerInterface *responseHandler);
       
   165 
       
   166     void handleResponse(
       
   167         const QScriptDebuggerResponse &response, int commandId);
       
   168     bool debuggerEvent(const QScriptDebuggerEvent &event);
       
   169 
       
   170     QScriptCompletionTaskInterface *createCompletionTask(
       
   171         const QString &contents, int cursorPosition, int frameIndex, int options);
       
   172 
       
   173     void showToolTip(const QPoint &pos, int frameIndex,
       
   174                      int lineNumber, const QStringList &path);
       
   175 
       
   176     static QPixmap pixmap(const QString &path);
       
   177 
       
   178     void startInteraction(QScriptDebuggerEvent::Type type,
       
   179                           qint64 scriptId, int lineNumber);
       
   180     void sync();
       
   181     void loadLocals(int frameIndex);
       
   182     QScriptDebuggerLocalsModel *createLocalsModel();
       
   183     void selectScriptForFrame(int frameIndex);
       
   184     void emitStoppedSignal();
       
   185 
       
   186     void maybeDelete(QWidget *widget);
       
   187 
       
   188     // private slots
       
   189     void _q_onLineEntered(const QString &contents);
       
   190     void _q_onCurrentFrameChanged(int frameIndex);
       
   191     void _q_onCurrentScriptChanged(qint64 scriptId);
       
   192     void _q_onScriptLocationSelected(int lineNumber);
       
   193     void _q_interrupt();
       
   194     void _q_continue();
       
   195     void _q_stepInto();
       
   196     void _q_stepOver();
       
   197     void _q_stepOut();
       
   198     void _q_runToCursor();
       
   199     void _q_runToNewScript();
       
   200     void _q_toggleBreakpoint();
       
   201     void _q_clearDebugOutput();
       
   202     void _q_clearErrorLog();
       
   203     void _q_clearConsole();
       
   204     void _q_findInScript();
       
   205     void _q_findNextInScript();
       
   206     void _q_findPreviousInScript();
       
   207     void _q_onFindCodeRequest(const QString &, int);
       
   208     void _q_goToLine();
       
   209 
       
   210     void executeConsoleCommand(const QString &command);
       
   211     void findCode(const QString &exp, int options);
       
   212 
       
   213     QScriptDebuggerFrontend *frontend;
       
   214 
       
   215     bool interactive;
       
   216     QScriptDebuggerConsole *console;
       
   217 
       
   218     int nextJobId;
       
   219     QList<QScriptDebuggerJob*> pendingJobs;
       
   220     QList<int> pendingJobIds;
       
   221     QScriptDebuggerJob *activeJob;
       
   222     bool activeJobHibernating;
       
   223     QHash<int, QScriptDebuggerCommand> watchedCommands;
       
   224     QHash<int, QScriptDebuggerResponseHandlerInterface*> responseHandlers;
       
   225 
       
   226     QScriptDebuggerConsoleWidgetInterface *consoleWidget;
       
   227     QScriptDebuggerStackWidgetInterface *stackWidget;
       
   228     QScriptDebuggerStackModel *stackModel;
       
   229     QScriptDebuggerScriptsWidgetInterface *scriptsWidget;
       
   230     QScriptDebuggerScriptsModel *scriptsModel;
       
   231     QScriptDebuggerLocalsWidgetInterface *localsWidget;
       
   232     QHash<int, QScriptDebuggerLocalsModel*> localsModels;
       
   233     QScriptDebuggerCodeWidgetInterface *codeWidget;
       
   234     QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget;
       
   235     QScriptBreakpointsWidgetInterface *breakpointsWidget;
       
   236     QScriptBreakpointsModel *breakpointsModel;
       
   237     QScriptDebugOutputWidgetInterface *debugOutputWidget;
       
   238     QScriptErrorLogWidgetInterface *errorLogWidget;
       
   239     QScriptDebuggerWidgetFactoryInterface *widgetFactory;
       
   240 
       
   241     QAction *interruptAction;
       
   242     QAction *continueAction;
       
   243     QAction *stepIntoAction;
       
   244     QAction *stepOverAction;
       
   245     QAction *stepOutAction;
       
   246     QAction *runToCursorAction;
       
   247     QAction *runToNewScriptAction;
       
   248 
       
   249     QAction *toggleBreakpointAction;
       
   250 
       
   251     QAction *clearDebugOutputAction;
       
   252     QAction *clearErrorLogAction;
       
   253     QAction *clearConsoleAction;
       
   254 
       
   255     QAction *findInScriptAction;
       
   256     QAction *findNextInScriptAction;
       
   257     QAction *findPreviousInScriptAction;
       
   258     QAction *goToLineAction;
       
   259 
       
   260     int updatesEnabledTimerId;
       
   261 };
       
   262 
       
   263 QScriptDebuggerPrivate::QScriptDebuggerPrivate()
       
   264 {
       
   265     frontend = 0;
       
   266     activeJob = 0;
       
   267     activeJobHibernating = false;
       
   268     nextJobId = 0;
       
   269     interactive = false;
       
   270 
       
   271     console = new QScriptDebuggerConsole();
       
   272     QString scriptsPath = QLatin1String(":/qt/scripttools/debugging/scripts/commands");
       
   273     QScriptStdMessageHandler tmp;
       
   274     console->loadScriptedCommands(scriptsPath, &tmp);
       
   275 
       
   276     consoleWidget = 0;
       
   277     stackWidget = 0;
       
   278     stackModel = 0;
       
   279     scriptsWidget = 0;
       
   280     scriptsModel = 0;
       
   281     localsWidget = 0;
       
   282     codeWidget = 0;
       
   283     codeFinderWidget = 0;
       
   284     breakpointsWidget = 0;
       
   285     breakpointsModel = 0;
       
   286     debugOutputWidget = 0;
       
   287     errorLogWidget = 0;
       
   288     widgetFactory = 0;
       
   289 
       
   290     interruptAction = 0;
       
   291     continueAction = 0;
       
   292     stepIntoAction = 0;
       
   293     stepOverAction = 0;
       
   294     stepOutAction = 0;
       
   295     runToCursorAction = 0;
       
   296     runToNewScriptAction = 0;
       
   297 
       
   298     toggleBreakpointAction = 0;
       
   299 
       
   300     clearErrorLogAction = 0;
       
   301     clearDebugOutputAction = 0;
       
   302     clearConsoleAction = 0;
       
   303 
       
   304     findInScriptAction = 0;
       
   305     findNextInScriptAction = 0;
       
   306     findPreviousInScriptAction = 0;
       
   307     goToLineAction = 0;
       
   308 
       
   309     updatesEnabledTimerId = -1;
       
   310 }
       
   311 
       
   312 QScriptDebuggerPrivate::~QScriptDebuggerPrivate()
       
   313 {
       
   314     delete console;
       
   315     qDeleteAll(pendingJobs);
       
   316     delete activeJob;
       
   317     maybeDelete(consoleWidget);
       
   318     maybeDelete(stackWidget);
       
   319     maybeDelete(scriptsWidget);
       
   320     maybeDelete(localsWidget);
       
   321     maybeDelete(codeWidget);
       
   322     maybeDelete(codeFinderWidget);
       
   323     maybeDelete(breakpointsWidget);
       
   324     maybeDelete(debugOutputWidget);
       
   325     maybeDelete(errorLogWidget);
       
   326 }
       
   327 
       
   328 void QScriptDebuggerPrivate::maybeDelete(QWidget *widget)
       
   329 {
       
   330     if (widget && !widget->parent())
       
   331         delete widget;
       
   332 }
       
   333 
       
   334 QPixmap QScriptDebuggerPrivate::pixmap(const QString &path)
       
   335 {
       
   336     static QString prefix = QString::fromLatin1(":/qt/scripttools/debugging/images/");
       
   337     return QPixmap(prefix + path);
       
   338 }
       
   339 
       
   340 /*!
       
   341   \reimp
       
   342 */
       
   343 int QScriptDebuggerPrivate::scheduleJob(QScriptDebuggerJob *job)
       
   344 {
       
   345     QScriptDebuggerJobPrivate *priv = QScriptDebuggerJobPrivate::get(job);
       
   346     Q_ASSERT(priv->jobScheduler == 0);
       
   347     priv->jobScheduler = this;
       
   348     int id = nextJobId;
       
   349     pendingJobs.append(job);
       
   350     pendingJobIds.append(id);
       
   351     maybeStartNewJob();
       
   352     return id;
       
   353 }
       
   354 
       
   355 /*!
       
   356   \reimp
       
   357 */
       
   358 void QScriptDebuggerPrivate::finishJob(QScriptDebuggerJob *job)
       
   359 {
       
   360     Q_UNUSED(job);
       
   361     Q_ASSERT(activeJob == job);
       
   362     delete activeJob;
       
   363     activeJob = 0;
       
   364     activeJobHibernating = false;
       
   365     maybeStartNewJob();
       
   366 }
       
   367 
       
   368 /*!
       
   369   \reimp
       
   370 */
       
   371 void QScriptDebuggerPrivate::hibernateUntilEvaluateFinished(QScriptDebuggerJob *job)
       
   372 {
       
   373     Q_UNUSED(job);
       
   374     Q_ASSERT(activeJob == job);
       
   375     activeJobHibernating = true;
       
   376 }
       
   377 
       
   378 /*!
       
   379   Starts a new job if appropriate.
       
   380 */
       
   381 void QScriptDebuggerPrivate::maybeStartNewJob()
       
   382 {
       
   383     if (activeJob || pendingJobs.isEmpty())
       
   384         return;
       
   385     activeJob = pendingJobs.takeFirst();
       
   386     activeJob->start();
       
   387 }
       
   388 
       
   389 /*!
       
   390   \reimp
       
   391 */
       
   392 int QScriptDebuggerPrivate::scheduleCommand(
       
   393     const QScriptDebuggerCommand &command,
       
   394     QScriptDebuggerResponseHandlerInterface *responseHandler)
       
   395 {
       
   396     if (!frontend)
       
   397         return -1;
       
   398     int id = frontend->scheduleCommand(command, this);
       
   399     if (responseHandler && (responseHandler != this))
       
   400         responseHandlers.insert(id, responseHandler);
       
   401     if ((command.type() == QScriptDebuggerCommand::SetBreakpoint)
       
   402         || (command.type() == QScriptDebuggerCommand::SetBreakpointData)
       
   403         || (command.type() == QScriptDebuggerCommand::DeleteBreakpoint)) {
       
   404         // need to watch this command and update the breakpoints model afterwards
       
   405         watchedCommands.insert(id, command);
       
   406     }
       
   407     return id;
       
   408 }
       
   409 
       
   410 /*!
       
   411   \reimp
       
   412 */
       
   413 void QScriptDebuggerPrivate::handleResponse(
       
   414     const QScriptDebuggerResponse &response, int commandId)
       
   415 {
       
   416     Q_Q(QScriptDebugger);
       
   417     if (watchedCommands.contains(commandId)) {
       
   418         QScriptDebuggerCommand command = watchedCommands.take(commandId);
       
   419         if (response.error() == QScriptDebuggerResponse::NoError) {
       
   420             if (!breakpointsModel)
       
   421                 breakpointsModel = new QScriptBreakpointsModel(this, this, q);
       
   422             switch (command.type()) {
       
   423             case QScriptDebuggerCommand::SetBreakpoint: {
       
   424                 int breakpointId = response.resultAsInt();
       
   425                 QScriptBreakpointData data = command.breakpointData();
       
   426                 breakpointsModel->addBreakpoint(breakpointId, data);
       
   427             }   break;
       
   428             case QScriptDebuggerCommand::SetBreakpointData: {
       
   429                 int breakpointId = command.breakpointId();
       
   430                 QScriptBreakpointData data = command.breakpointData();
       
   431                 breakpointsModel->modifyBreakpoint(breakpointId, data);
       
   432             }   break;
       
   433             case QScriptDebuggerCommand::DeleteBreakpoint: {
       
   434                 int breakpointId = command.breakpointId();
       
   435                 breakpointsModel->removeBreakpoint(breakpointId);
       
   436             }   break;
       
   437             default:
       
   438                 Q_ASSERT(false);
       
   439             }
       
   440         }
       
   441     } else if (response.async()) {
       
   442         interactive = false;
       
   443         // disable/invalidate/enable stuff
       
   444         if (continueAction)
       
   445             continueAction->setEnabled(false);
       
   446         if (stepIntoAction)
       
   447             stepIntoAction->setEnabled(false);
       
   448         if (stepOverAction)
       
   449             stepOverAction->setEnabled(false);
       
   450         if (stepOutAction)
       
   451             stepOutAction->setEnabled(false);
       
   452         if (runToCursorAction)
       
   453             runToCursorAction->setEnabled(false);
       
   454         if (runToNewScriptAction)
       
   455             runToNewScriptAction->setEnabled(false);
       
   456         if (interruptAction)
       
   457             interruptAction->setEnabled(true);
       
   458 
       
   459         // the timer is to avoid flicker when stepping
       
   460         if (stackWidget) {
       
   461             stackWidget->setUpdatesEnabled(false);
       
   462             stackWidget->setEnabled(false);
       
   463             if (updatesEnabledTimerId == -1)
       
   464                 updatesEnabledTimerId = q->startTimer(75);
       
   465         }
       
   466         if (localsWidget) {
       
   467             localsWidget->setUpdatesEnabled(false);
       
   468             localsWidget->setEnabled(false);
       
   469             if (updatesEnabledTimerId == -1)
       
   470                 updatesEnabledTimerId = q->startTimer(75);
       
   471         }
       
   472         if (codeWidget)
       
   473             codeWidget->invalidateExecutionLineNumbers();
       
   474 
       
   475         emit q->started();
       
   476     }
       
   477 
       
   478     QScriptDebuggerResponseHandlerInterface *realHandler = responseHandlers.take(commandId);
       
   479     if (realHandler)
       
   480         realHandler->handleResponse(response, commandId);
       
   481 }
       
   482 
       
   483 /*!
       
   484   \reimp
       
   485 
       
   486   Handles a debugger event from the frontend.
       
   487 */
       
   488 bool QScriptDebuggerPrivate::debuggerEvent(const QScriptDebuggerEvent &event)
       
   489 {
       
   490     Q_Q(QScriptDebugger);
       
   491     switch (event.type()) {
       
   492     case QScriptDebuggerEvent::None:
       
   493     case QScriptDebuggerEvent::UserEvent:
       
   494     case QScriptDebuggerEvent::MaxUserEvent:
       
   495         Q_ASSERT(false);
       
   496         break;
       
   497 
       
   498     case QScriptDebuggerEvent::Trace:
       
   499         if (!debugOutputWidget && widgetFactory)
       
   500             q->setDebugOutputWidget(widgetFactory->createDebugOutputWidget());
       
   501         if (debugOutputWidget)
       
   502             debugOutputWidget->message(QtDebugMsg, event.message());
       
   503         return true; // trace doesn't stall execution
       
   504 
       
   505     case QScriptDebuggerEvent::SteppingFinished: {
       
   506         if (!consoleWidget && widgetFactory)
       
   507             q->setConsoleWidget(widgetFactory->createConsoleWidget());
       
   508         if (consoleWidget) {
       
   509             QString msg = event.message();
       
   510             if (!msg.isEmpty())
       
   511                 consoleWidget->message(QtDebugMsg, msg);
       
   512         }
       
   513     }   break;
       
   514 
       
   515     case QScriptDebuggerEvent::Interrupted:
       
   516     case QScriptDebuggerEvent::LocationReached:
       
   517         break;
       
   518 
       
   519     case QScriptDebuggerEvent::Breakpoint: {
       
   520         int bpId = event.breakpointId();
       
   521         if (!consoleWidget && widgetFactory)
       
   522             q->setConsoleWidget(widgetFactory->createConsoleWidget());
       
   523         if (consoleWidget) {
       
   524             consoleWidget->message(QtDebugMsg,
       
   525                                    QString::fromLatin1("Breakpoint %0 at %1, line %2.")
       
   526                                    .arg(bpId).arg(event.fileName())
       
   527                                    .arg(event.lineNumber()));
       
   528         }
       
   529         if (breakpointsModel->breakpointData(bpId).isSingleShot())
       
   530             breakpointsModel->removeBreakpoint(bpId);
       
   531     }   break;
       
   532 
       
   533     case QScriptDebuggerEvent::Exception: {
       
   534         if (event.hasExceptionHandler()) {
       
   535             // Let the exception be handled like normal.
       
   536             // We may want to add a "Break on all exceptions" option
       
   537             // to be able to customize this behavior.
       
   538             return true;
       
   539         }
       
   540         if (!consoleWidget && widgetFactory)
       
   541             q->setConsoleWidget(widgetFactory->createConsoleWidget());
       
   542         if (!errorLogWidget && widgetFactory)
       
   543             q->setErrorLogWidget(widgetFactory->createErrorLogWidget());
       
   544         if (consoleWidget || errorLogWidget) {
       
   545             QString fn = event.fileName();
       
   546             if (fn.isEmpty()) {
       
   547                 if (event.scriptId() != -1)
       
   548                     fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId());
       
   549                 else
       
   550                     fn = QString::fromLatin1("<native>");
       
   551             }
       
   552             QString msg = QString::fromLatin1("Uncaught exception at %0:%1: %2").arg(fn)
       
   553                           .arg(event.lineNumber()).arg(event.message());
       
   554             if (consoleWidget)
       
   555                 consoleWidget->message(QtCriticalMsg, msg);
       
   556             if (errorLogWidget)
       
   557                 errorLogWidget->message(QtCriticalMsg, msg);
       
   558         }
       
   559     }   break;
       
   560 
       
   561     case QScriptDebuggerEvent::InlineEvalFinished: {
       
   562         QScriptDebuggerValue result = event.scriptValue();
       
   563         Q_ASSERT(console != 0);
       
   564         int action = console->evaluateAction();
       
   565         console->setEvaluateAction(0);
       
   566         switch (action) {
       
   567         case 0: { // eval command
       
   568             if (activeJob) {
       
   569                 if (activeJobHibernating) {
       
   570                     activeJobHibernating = false;
       
   571                     activeJob->evaluateFinished(result);
       
   572                 }
       
   573             } else if (consoleWidget) {
       
   574                 // ### if the result is an object, need to do a tostring job on it
       
   575 //          messageHandler->message(QtDebugMsg, result.toString());
       
   576                 if (result.type() != QScriptDebuggerValue::UndefinedValue)
       
   577                     consoleWidget->message(QtDebugMsg, event.message());
       
   578             }
       
   579         }   break;
       
   580         case 1: { // return command
       
   581             QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
       
   582             frontend.scheduleForceReturn(console->currentFrameIndex(), result);
       
   583         }   return false;
       
   584         }
       
   585         if (!event.isNestedEvaluate()) {
       
   586             // in the case when evaluate() was called while the
       
   587             // engine was not running, we don't want to enter interactive mode
       
   588             return true;
       
   589         }
       
   590     }   break;
       
   591 
       
   592     case QScriptDebuggerEvent::DebuggerInvocationRequest: {
       
   593         if (!consoleWidget && widgetFactory)
       
   594             q->setConsoleWidget(widgetFactory->createConsoleWidget());
       
   595         if (consoleWidget) {
       
   596             QString fn = event.fileName();
       
   597             if (fn.isEmpty())
       
   598                 fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId());
       
   599             consoleWidget->message(QtDebugMsg,
       
   600                                    QString::fromLatin1("Debugger invoked from %1, line %2.")
       
   601                                    .arg(fn).arg(event.lineNumber()));
       
   602         }
       
   603     }   break;
       
   604 
       
   605     case QScriptDebuggerEvent::ForcedReturn: {
       
   606     }   break;
       
   607 
       
   608     }
       
   609 
       
   610     if (widgetInPaintEvent) {
       
   611         QString msg = QString::fromLatin1("Suspending evaluation in paintEvent() is not supported; resuming.");
       
   612         if (!consoleWidget && widgetFactory)
       
   613             q->setConsoleWidget(widgetFactory->createConsoleWidget());
       
   614         if (!errorLogWidget && widgetFactory)
       
   615             q->setErrorLogWidget(widgetFactory->createErrorLogWidget());
       
   616         if (consoleWidget)
       
   617             consoleWidget->message(QtWarningMsg, msg);
       
   618         if (errorLogWidget)
       
   619             errorLogWidget->message(QtCriticalMsg, msg);
       
   620         return true;
       
   621     }
       
   622 
       
   623     if (activeJobHibernating) {
       
   624         // evaluate() did not finish normally (e.g. due to a breakpoint),
       
   625         // so cancel the job that's waiting for it
       
   626         delete activeJob;
       
   627         activeJob = 0;
       
   628         activeJobHibernating = false;
       
   629     }
       
   630 
       
   631     startInteraction(event.type(), event.scriptId(), event.lineNumber());
       
   632     return !interactive;
       
   633 }
       
   634 
       
   635 class QScriptToolTipJob : public QScriptDebuggerCommandSchedulerJob
       
   636 {
       
   637 public:
       
   638     QScriptToolTipJob(const QPoint &pos, int frameIndex,
       
   639                       int lineNumber, const QStringList &path,
       
   640                       QScriptDebuggerCommandSchedulerInterface *scheduler)
       
   641         : QScriptDebuggerCommandSchedulerJob(scheduler), m_pos(pos),
       
   642           m_frameIndex(frameIndex), m_lineNumber(lineNumber), m_path(path)
       
   643         {}
       
   644 
       
   645     void start()
       
   646     {
       
   647         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   648         frontend.scheduleGetPropertyExpressionValue(m_frameIndex, m_lineNumber, m_path);
       
   649     }
       
   650     void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
       
   651     {
       
   652         QString tip = response.result().toString();
       
   653         if (tip.indexOf(QLatin1Char('\n')) != -1) {
       
   654             QStringList lines = tip.split(QLatin1Char('\n'));
       
   655             int lineCount = lines.size();
       
   656             if (lineCount > 5) {
       
   657                 lines = lines.mid(0, 5);
       
   658                 lines.append(QString::fromLatin1("(... %0 more lines ...)").arg(lineCount - 5));
       
   659             }
       
   660             tip = lines.join(QLatin1String("\n"));
       
   661         }
       
   662         QToolTip::showText(m_pos, tip);
       
   663         finish();
       
   664     }
       
   665 
       
   666 private:
       
   667     QPoint m_pos;
       
   668     int m_frameIndex;
       
   669     int m_lineNumber;
       
   670     QStringList m_path;
       
   671 };
       
   672 
       
   673 /*!
       
   674   \reimp
       
   675 */
       
   676 void QScriptDebuggerPrivate::showToolTip(const QPoint &pos, int frameIndex,
       
   677                                          int lineNumber, const QStringList &path)
       
   678 {
       
   679     if (frameIndex == -1) {
       
   680         if (stackWidget)
       
   681             frameIndex = stackWidget->currentFrameIndex();
       
   682         else
       
   683             frameIndex = console->currentFrameIndex();
       
   684     }
       
   685     QScriptDebuggerJob *job = new QScriptToolTipJob(pos, frameIndex, lineNumber, path, this);
       
   686     scheduleJob(job);
       
   687 }
       
   688 
       
   689 /*!
       
   690   \reimp
       
   691 */
       
   692 QScriptCompletionTaskInterface *QScriptDebuggerPrivate::createCompletionTask(
       
   693     const QString &contents, int cursorPosition, int frameIndex, int options)
       
   694 {
       
   695     return new QScriptCompletionTask(
       
   696         contents, cursorPosition, frameIndex, this, this,
       
   697         (options & QScriptCompletionProviderInterface::ConsoleCommandCompletion) ? console : 0);
       
   698 }
       
   699 
       
   700 /*!
       
   701   Slot called when a line has been entered in the console widget.
       
   702 */
       
   703 void QScriptDebuggerPrivate::_q_onLineEntered(const QString &contents)
       
   704 {
       
   705     QScriptDebuggerConsoleCommandJob *commandJob;
       
   706     commandJob = console->consumeInput(contents, consoleWidget, this);
       
   707     if (commandJob != 0) {
       
   708         scheduleJob(commandJob);
       
   709         consoleWidget->setLineContinuationMode(false);
       
   710     } else if (console->hasIncompleteInput()) {
       
   711         consoleWidget->setLineContinuationMode(true);
       
   712     }
       
   713 }
       
   714 
       
   715 /*!
       
   716   Slot called when the current index has changed in the stack widget.
       
   717 */
       
   718 void QScriptDebuggerPrivate::_q_onCurrentFrameChanged(int frameIndex)
       
   719 {
       
   720     loadLocals(frameIndex);
       
   721     selectScriptForFrame(frameIndex);
       
   722 }
       
   723 
       
   724 /*!
       
   725   Slot called when the current script has changed in the scripts widget.
       
   726 */
       
   727 void QScriptDebuggerPrivate::_q_onCurrentScriptChanged(qint64 scriptId)
       
   728 {
       
   729     if (codeWidget && (codeWidget->currentScriptId() != scriptId)) {
       
   730         codeWidget->setCurrentScript(scriptId);
       
   731         QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
       
   732         if (view)
       
   733             view->setExecutionLineNumber(-1, /*error=*/false);
       
   734     }
       
   735 }
       
   736 
       
   737 void QScriptDebuggerPrivate::_q_onScriptLocationSelected(int lineNumber)
       
   738 {
       
   739     QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
       
   740     if (!view)
       
   741         return;
       
   742     view->gotoLine(lineNumber);
       
   743 }
       
   744 
       
   745 void QScriptDebuggerPrivate::_q_interrupt()
       
   746 {
       
   747     executeConsoleCommand(QString::fromLatin1("interrupt"));
       
   748 }
       
   749 
       
   750 void QScriptDebuggerPrivate::_q_continue()
       
   751 {
       
   752     executeConsoleCommand(QString::fromLatin1("continue"));
       
   753 }
       
   754 
       
   755 void QScriptDebuggerPrivate::_q_stepInto()
       
   756 {
       
   757     executeConsoleCommand(QString::fromLatin1("step"));
       
   758 }
       
   759 
       
   760 void QScriptDebuggerPrivate::_q_stepOver()
       
   761 {
       
   762     executeConsoleCommand(QString::fromLatin1("next"));
       
   763 }
       
   764 
       
   765 void QScriptDebuggerPrivate::_q_stepOut()
       
   766 {
       
   767     executeConsoleCommand(QString::fromLatin1("finish"));
       
   768 }
       
   769 
       
   770 void QScriptDebuggerPrivate::_q_runToCursor()
       
   771 {
       
   772     qint64 scriptId = codeWidget->currentScriptId();
       
   773     int lineNumber = codeWidget->currentView()->cursorLineNumber();
       
   774     QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
       
   775     frontend.scheduleRunToLocation(scriptId, lineNumber);
       
   776 }
       
   777 
       
   778 void QScriptDebuggerPrivate::_q_runToNewScript()
       
   779 {
       
   780     QScriptDebuggerCommandSchedulerFrontend frontend(this, this);
       
   781     frontend.scheduleRunToLocation(QString(), -1);
       
   782 }
       
   783 
       
   784 void QScriptDebuggerPrivate::_q_toggleBreakpoint()
       
   785 {
       
   786     Q_ASSERT(codeWidget != 0);
       
   787     QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
       
   788     if (!view)
       
   789         return;
       
   790     qint64 scriptId = codeWidget->currentScriptId();
       
   791     int lineNumber = view->cursorLineNumber();
       
   792     Q_ASSERT(breakpointsModel != 0);
       
   793     int bpId = breakpointsModel->resolveBreakpoint(scriptId, lineNumber);
       
   794     if (bpId != -1) {
       
   795         breakpointsModel->deleteBreakpoint(bpId);
       
   796     } else {
       
   797         QScriptBreakpointData data(scriptId, lineNumber);
       
   798         if (scriptsModel)
       
   799             data.setFileName(scriptsModel->scriptData(scriptId).fileName());
       
   800         breakpointsModel->setBreakpoint(data);
       
   801     }
       
   802 }
       
   803 
       
   804 void QScriptDebuggerPrivate::_q_clearDebugOutput()
       
   805 {
       
   806     if (debugOutputWidget)
       
   807         debugOutputWidget->clear();
       
   808 }
       
   809 
       
   810 void QScriptDebuggerPrivate::_q_clearErrorLog()
       
   811 {
       
   812     if (errorLogWidget)
       
   813         errorLogWidget->clear();
       
   814 }
       
   815 
       
   816 void QScriptDebuggerPrivate::_q_clearConsole()
       
   817 {
       
   818     if (consoleWidget)
       
   819         consoleWidget->clear();
       
   820 }
       
   821 
       
   822 void QScriptDebuggerPrivate::executeConsoleCommand(const QString &command)
       
   823 {
       
   824     QString tmp = console->incompleteInput();
       
   825     console->setIncompleteInput(QString());
       
   826     QScriptDebuggerJob *job = console->consumeInput(console->commandPrefix() + command, debugOutputWidget, this);
       
   827     console->setIncompleteInput(tmp);
       
   828     if (job != 0) {
       
   829         scheduleJob(job);
       
   830         // once to send the command...
       
   831         QCoreApplication::processEvents();
       
   832         // ... and once to receive the response
       
   833         QCoreApplication::processEvents();
       
   834     }
       
   835 }
       
   836 
       
   837 void QScriptDebuggerPrivate::_q_findInScript()
       
   838 {
       
   839     if (!codeFinderWidget && widgetFactory)
       
   840         q_func()->setCodeFinderWidget(widgetFactory->createCodeFinderWidget());
       
   841     if (codeFinderWidget) {
       
   842         codeFinderWidget->show();
       
   843         codeFinderWidget->setFocus(Qt::OtherFocusReason);
       
   844     }
       
   845 }
       
   846 
       
   847 void QScriptDebuggerPrivate::_q_findNextInScript()
       
   848 {
       
   849     findCode(codeFinderWidget->text(), codeFinderWidget->findOptions());
       
   850 }
       
   851 
       
   852 void QScriptDebuggerPrivate::_q_findPreviousInScript()
       
   853 {
       
   854     int options = codeFinderWidget->findOptions();
       
   855     options |= QTextDocument::FindBackward;
       
   856     findCode(codeFinderWidget->text(), options);
       
   857 }
       
   858 
       
   859 void QScriptDebuggerPrivate::_q_onFindCodeRequest(
       
   860     const QString &exp, int options)
       
   861 {
       
   862     findCode(exp, options);
       
   863     if (findNextInScriptAction)
       
   864         findNextInScriptAction->setEnabled(!exp.isEmpty());
       
   865     if (findPreviousInScriptAction)
       
   866         findPreviousInScriptAction->setEnabled(!exp.isEmpty());
       
   867 }
       
   868 
       
   869 void QScriptDebuggerPrivate::findCode(const QString &exp, int options)
       
   870 {
       
   871     QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
       
   872     if (!view)
       
   873         return;
       
   874     int result = view->find(exp, options);
       
   875     codeFinderWidget->setOK(((result & 0x1) != 0) || exp.isEmpty());
       
   876     codeFinderWidget->setWrapped((result & 0x2) != 0);
       
   877 }
       
   878 
       
   879 void QScriptDebuggerPrivate::_q_goToLine()
       
   880 {
       
   881     QScriptDebuggerCodeViewInterface *view = codeWidget->currentView();
       
   882     if (!view)
       
   883         return;
       
   884     bool ok = false;
       
   885     int lineNumber = QInputDialog::getInteger(0, QScriptDebugger::tr("Go to Line"),
       
   886                                               QScriptDebugger::tr("Line:"),
       
   887                                               view->cursorLineNumber(),
       
   888                                               1, INT_MAX, 1, &ok);
       
   889     if (ok)
       
   890         view->gotoLine(lineNumber);
       
   891 }
       
   892 
       
   893 class QScriptDebuggerShowLineJob : public QScriptDebuggerCommandSchedulerJob
       
   894 {
       
   895 public:
       
   896     QScriptDebuggerShowLineJob(qint64 scriptId, int lineNumber,
       
   897                                QScriptMessageHandlerInterface *messageHandler,
       
   898                                QScriptDebuggerCommandSchedulerInterface *scheduler)
       
   899         : QScriptDebuggerCommandSchedulerJob(scheduler),
       
   900           m_scriptId(scriptId), m_lineNumber(lineNumber),
       
   901         m_messageHandler(messageHandler) {}
       
   902 
       
   903     void start()
       
   904     {
       
   905         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   906         frontend.scheduleGetScriptData(m_scriptId);
       
   907     }
       
   908     void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
       
   909     {
       
   910         QScriptScriptData data = response.resultAsScriptData();
       
   911         QString line = data.lines(m_lineNumber, 1).value(0);
       
   912         m_messageHandler->message(QtDebugMsg, QString::fromLatin1("%0\t%1")
       
   913                                   .arg(m_lineNumber).arg(line));
       
   914         finish();
       
   915     }
       
   916 
       
   917 private:
       
   918     qint64 m_scriptId;
       
   919     int m_lineNumber;
       
   920     QScriptMessageHandlerInterface *m_messageHandler;
       
   921 };
       
   922 
       
   923 namespace {
       
   924 
       
   925 class SyncStackJob : public QScriptDebuggerCommandSchedulerJob
       
   926 {
       
   927 public:
       
   928     SyncStackJob(QScriptDebuggerPrivate *debugger)
       
   929         : QScriptDebuggerCommandSchedulerJob(debugger),
       
   930           m_debugger(debugger), m_index(0) {}
       
   931     void start()
       
   932     {
       
   933         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   934         frontend.scheduleGetContextInfo(m_index); // ### getContextInfos()
       
   935     }
       
   936     void handleResponse(const QScriptDebuggerResponse &response,
       
   937                         int)
       
   938     {
       
   939         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   940         if (response.error() != QScriptDebuggerResponse::InvalidContextIndex) {
       
   941             m_infos.append(response.resultAsContextInfo());
       
   942             frontend.scheduleGetContextInfo(++m_index);
       
   943         } else {
       
   944             m_debugger->stackModel->setContextInfos(m_infos);
       
   945             if (m_debugger->stackWidget->currentFrameIndex() == -1)
       
   946                 m_debugger->stackWidget->setCurrentFrameIndex(0);
       
   947             m_debugger->stackWidget->setUpdatesEnabled(true);
       
   948             m_debugger->stackWidget->setEnabled(true);
       
   949             finish();
       
   950         }
       
   951     }
       
   952 
       
   953 private:
       
   954     QScriptDebuggerPrivate *m_debugger;
       
   955     int m_index;
       
   956     QList<QScriptContextInfo> m_infos;
       
   957 };
       
   958 
       
   959 class SyncScriptsJob : public QScriptDebuggerCommandSchedulerJob
       
   960 {
       
   961 public:
       
   962     SyncScriptsJob(QScriptDebuggerPrivate *debugger)
       
   963         : QScriptDebuggerCommandSchedulerJob(debugger),
       
   964           m_debugger(debugger), m_index(-1) {}
       
   965 
       
   966     void start()
       
   967     {
       
   968         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   969         frontend.scheduleScriptsCheckpoint();
       
   970     }
       
   971     void handleResponse(const QScriptDebuggerResponse &response,
       
   972                         int)
       
   973     {
       
   974         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
   975         if (m_index == -1) {
       
   976             QScriptScriptsDelta delta;
       
   977             delta = qvariant_cast<QScriptScriptsDelta>(response.result());
       
   978 
       
   979             const QList<qint64> &removed = delta.second;
       
   980             for (int i = 0; i < removed.size(); ++i)
       
   981                 m_debugger->scriptsModel->removeScript(removed.at(i));
       
   982 
       
   983             m_added = delta.first;
       
   984             if (!m_added.isEmpty()) {
       
   985                 frontend.scheduleGetScriptData(m_added.at(++m_index));
       
   986             } else {
       
   987                 m_debugger->scriptsModel->commit();
       
   988                 finish();
       
   989             }
       
   990         } else {
       
   991             QScriptScriptData data = response.resultAsScriptData();
       
   992             qint64 scriptId = m_added.at(m_index);
       
   993             m_debugger->scriptsModel->addScript(scriptId, data);
       
   994 
       
   995             // ### could be slow, might want to do this in a separate thread
       
   996 //            Q_ASSERT_X(false, Q_FUNC_INFO, "implement me");
       
   997             QString xml; // = qt_scriptToXml(data.contents(), data.baseLineNumber());
       
   998             QScriptXmlParser::Result extraInfo = QScriptXmlParser::parse(xml);
       
   999             m_debugger->scriptsModel->addExtraScriptInfo(
       
  1000                 scriptId, extraInfo.functionsInfo, extraInfo.executableLineNumbers);
       
  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 
       
  1011 private:
       
  1012     QScriptDebuggerPrivate *m_debugger;
       
  1013     int m_index;
       
  1014     QList<qint64> m_added;
       
  1015 };
       
  1016 
       
  1017 class SyncBreakpointsJob : public QScriptDebuggerCommandSchedulerJob
       
  1018 {
       
  1019 public:
       
  1020     SyncBreakpointsJob(QScriptDebuggerPrivate *debugger)
       
  1021         : QScriptDebuggerCommandSchedulerJob(debugger),
       
  1022           m_debugger(debugger), m_index(-1) {}
       
  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 
       
  1043 private:
       
  1044     QScriptDebuggerPrivate *m_debugger;
       
  1045     int m_index;
       
  1046     QList<QScriptContextInfo> m_infos;
       
  1047 };
       
  1048 
       
  1049 class SyncLocalsJob : public QScriptDebuggerCommandSchedulerJob
       
  1050 {
       
  1051 public:
       
  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 
       
  1072 private:
       
  1073     QScriptDebuggerPrivate *m_debugger;
       
  1074 };
       
  1075 
       
  1076 class LoadLocalsJob : public QScriptDebuggerCommandSchedulerJob
       
  1077 {
       
  1078 public:
       
  1079     LoadLocalsJob(QScriptDebuggerPrivate *debugger, int frameIndex)
       
  1080         : QScriptDebuggerCommandSchedulerJob(debugger),
       
  1081           m_debugger(debugger), m_frameIndex(frameIndex) {}
       
  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 
       
  1110 private:
       
  1111     QScriptDebuggerPrivate *m_debugger;
       
  1112     int m_frameIndex;
       
  1113 };
       
  1114 
       
  1115 class EmitStoppedSignalJob : public QScriptDebuggerJob
       
  1116 {
       
  1117 public:
       
  1118     EmitStoppedSignalJob(QScriptDebuggerPrivate *debugger)
       
  1119         : m_debugger(debugger) {}
       
  1120 
       
  1121     void start()
       
  1122     {
       
  1123         m_debugger->emitStoppedSignal();
       
  1124         finish();
       
  1125     }
       
  1126 
       
  1127 private:
       
  1128     QScriptDebuggerPrivate *m_debugger;
       
  1129 };
       
  1130 
       
  1131 } // namespace
       
  1132 
       
  1133 void QScriptDebuggerPrivate::startInteraction(QScriptDebuggerEvent::Type type,
       
  1134                                               qint64 scriptId, int lineNumber)
       
  1135 {
       
  1136     Q_Q(QScriptDebugger);
       
  1137     if (type != QScriptDebuggerEvent::InlineEvalFinished) {
       
  1138         if (stackWidget)
       
  1139             stackWidget->setCurrentFrameIndex(0);
       
  1140         console->setCurrentFrameIndex(0);
       
  1141         console->setCurrentScriptId(scriptId);
       
  1142         console->setCurrentLineNumber(lineNumber);
       
  1143     }
       
  1144 
       
  1145     if ((scriptId != -1) && consoleWidget) {
       
  1146         QScriptDebuggerJob *job = new QScriptDebuggerShowLineJob(scriptId, lineNumber, consoleWidget, this);
       
  1147         scheduleJob(job);
       
  1148     }
       
  1149 
       
  1150     sync();
       
  1151 
       
  1152     if (!interactive) {
       
  1153         interactive = true;
       
  1154         if (updatesEnabledTimerId != -1) {
       
  1155             q->killTimer(updatesEnabledTimerId);
       
  1156             updatesEnabledTimerId = -1;
       
  1157         }
       
  1158         console->bumpSessionId();
       
  1159         scheduleJob(new EmitStoppedSignalJob(this));
       
  1160     }
       
  1161 
       
  1162     if (consoleWidget)
       
  1163         consoleWidget->activateWindow();
       
  1164     else if (codeWidget)
       
  1165         codeWidget->activateWindow();
       
  1166 
       
  1167     if (continueAction)
       
  1168         continueAction->setEnabled(true);
       
  1169     if (stepIntoAction)
       
  1170         stepIntoAction->setEnabled(true);
       
  1171     if (stepOverAction)
       
  1172         stepOverAction->setEnabled(true);
       
  1173     if (stepOutAction)
       
  1174         stepOutAction->setEnabled(true);
       
  1175     if (runToCursorAction)
       
  1176         runToCursorAction->setEnabled(true);
       
  1177     if (runToNewScriptAction)
       
  1178         runToNewScriptAction->setEnabled(true);
       
  1179     if (interruptAction)
       
  1180         interruptAction->setEnabled(false);
       
  1181 
       
  1182     bool hasScript = (codeWidget != 0);
       
  1183     if (findInScriptAction)
       
  1184         findInScriptAction->setEnabled(hasScript);
       
  1185     if (toggleBreakpointAction)
       
  1186         toggleBreakpointAction->setEnabled(hasScript);
       
  1187     if (goToLineAction)
       
  1188         goToLineAction->setEnabled(hasScript);
       
  1189 }
       
  1190 
       
  1191 void QScriptDebuggerPrivate::sync()
       
  1192 {
       
  1193     if (localsWidget) {
       
  1194         QScriptDebuggerJob *job = new SyncLocalsJob(this);
       
  1195         scheduleJob(job);
       
  1196     }
       
  1197     if (scriptsModel) {
       
  1198         QScriptDebuggerJob *job = new SyncScriptsJob(this);
       
  1199         scheduleJob(job);
       
  1200     }
       
  1201     if (stackModel) {
       
  1202         QScriptDebuggerJob *job = new SyncStackJob(this);
       
  1203         scheduleJob(job);
       
  1204     }
       
  1205     if (breakpointsModel) {
       
  1206         // need to sync because the ignore-count could have changed
       
  1207         QScriptDebuggerJob *job = new SyncBreakpointsJob(this);
       
  1208         scheduleJob(job);
       
  1209     }
       
  1210 
       
  1211     if (stackWidget && (stackWidget->currentFrameIndex() != -1)) {
       
  1212         int index = stackWidget->currentFrameIndex();
       
  1213         loadLocals(index);
       
  1214         selectScriptForFrame(index);
       
  1215     } else if (codeWidget && (console->currentFrameIndex() != -1)) {
       
  1216         selectScriptForFrame(console->currentFrameIndex());
       
  1217     }
       
  1218 }
       
  1219 
       
  1220 void QScriptDebuggerPrivate::loadLocals(int frameIndex)
       
  1221 {
       
  1222     LoadLocalsJob *job = new LoadLocalsJob(this, frameIndex);
       
  1223     scheduleJob(job);
       
  1224 }
       
  1225 
       
  1226 QScriptDebuggerLocalsModel *QScriptDebuggerPrivate::createLocalsModel()
       
  1227 {
       
  1228     return new QScriptDebuggerLocalsModel(this, this, q_func());
       
  1229 }
       
  1230 
       
  1231 namespace {
       
  1232 
       
  1233 class ShowFrameCodeJob : public QScriptDebuggerCommandSchedulerJob
       
  1234 {
       
  1235 public:
       
  1236     ShowFrameCodeJob(QScriptDebuggerPrivate *debugger, int frameIndex)
       
  1237         : QScriptDebuggerCommandSchedulerJob(debugger),
       
  1238           m_debugger(debugger), m_frameIndex(frameIndex) {}
       
  1239 
       
  1240     void start()
       
  1241     {
       
  1242         QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
  1243         frontend.scheduleGetContextInfo(m_frameIndex);
       
  1244     }
       
  1245     void handleResponse(const QScriptDebuggerResponse &response,
       
  1246                         int)
       
  1247     {
       
  1248         if (m_info.isNull()) {
       
  1249             m_info = response.resultAsContextInfo();
       
  1250             QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
       
  1251             frontend.scheduleGetContextState(m_frameIndex);
       
  1252         } else {
       
  1253             int contextState = response.resultAsInt();
       
  1254             bool error = (contextState == QScriptContext::ExceptionState);
       
  1255             if (m_debugger->scriptsWidget) {
       
  1256                 m_debugger->scriptsWidget->setCurrentScript(m_info.scriptId());
       
  1257             }
       
  1258             if (m_debugger->codeWidget) {
       
  1259                 m_debugger->codeWidget->setCurrentScript(m_info.scriptId());
       
  1260                 QScriptDebuggerCodeViewInterface *view = m_debugger->codeWidget->currentView();
       
  1261                 if (view)
       
  1262                     view->setExecutionLineNumber(m_info.lineNumber(), error);
       
  1263             }
       
  1264             finish();
       
  1265         }
       
  1266     }
       
  1267 
       
  1268 private:
       
  1269     QScriptDebuggerPrivate *m_debugger;
       
  1270     int m_frameIndex;
       
  1271     QScriptContextInfo m_info;
       
  1272 };
       
  1273 
       
  1274 } // namespace
       
  1275 
       
  1276 void QScriptDebuggerPrivate::selectScriptForFrame(int frameIndex)
       
  1277 {
       
  1278     QScriptDebuggerJob *job = new ShowFrameCodeJob(this, frameIndex);
       
  1279     scheduleJob(job);
       
  1280 }
       
  1281 
       
  1282 void QScriptDebuggerPrivate::emitStoppedSignal()
       
  1283 {
       
  1284     emit q_func()->stopped();
       
  1285 }
       
  1286 
       
  1287 /*!
       
  1288   Constructs a new QScriptDebugger object.
       
  1289 */
       
  1290 QScriptDebugger::QScriptDebugger(QObject *parent)
       
  1291     : QObject(*new QScriptDebuggerPrivate, parent)
       
  1292 {
       
  1293     ++scriptDebuggerCount;
       
  1294 }
       
  1295 
       
  1296 /*!
       
  1297   Destroys this QScriptDebugger.
       
  1298 */
       
  1299 QScriptDebugger::~QScriptDebugger()
       
  1300 {
       
  1301     --scriptDebuggerCount;
       
  1302     if ((scriptDebuggerCount == 0) && eventCallbackRegistered) {
       
  1303         eventCallbackRegistered = false;
       
  1304         QInternal::unregisterCallback(QInternal::EventNotifyCallback,
       
  1305                                       scriptDebuggerEventCallback);
       
  1306     }
       
  1307 }
       
  1308 
       
  1309 /*!
       
  1310   \internal
       
  1311 */
       
  1312 QScriptDebugger::QScriptDebugger(QScriptDebuggerPrivate &dd, QObject *parent)
       
  1313     : QObject(dd, parent)
       
  1314 {
       
  1315 }
       
  1316 
       
  1317 QScriptDebuggerFrontend *QScriptDebugger::frontend() const
       
  1318 {
       
  1319     Q_D(const QScriptDebugger);
       
  1320     return d->frontend;
       
  1321 }
       
  1322 
       
  1323 void QScriptDebugger::setFrontend(QScriptDebuggerFrontend *frontend)
       
  1324 {
       
  1325     Q_D(QScriptDebugger);
       
  1326     if (d->frontend)
       
  1327         d->frontend->setEventHandler(0);
       
  1328     d->frontend = frontend;
       
  1329     if (frontend) {
       
  1330         frontend->setEventHandler(d);
       
  1331         if (!eventCallbackRegistered) {
       
  1332             eventCallbackRegistered = true;
       
  1333             QInternal::registerCallback(QInternal::EventNotifyCallback,
       
  1334                                         scriptDebuggerEventCallback);
       
  1335         }
       
  1336     }
       
  1337 }
       
  1338 
       
  1339 QAction *QScriptDebugger::action(DebuggerAction action, QObject *parent)
       
  1340 {
       
  1341     switch (action) {
       
  1342     case InterruptAction:
       
  1343         return interruptAction(parent);
       
  1344     case ContinueAction:
       
  1345         return continueAction(parent);
       
  1346     case StepIntoAction:
       
  1347         return stepIntoAction(parent);
       
  1348     case StepOverAction:
       
  1349         return stepOverAction(parent);
       
  1350     case StepOutAction:
       
  1351         return stepOutAction(parent);
       
  1352     case RunToCursorAction:
       
  1353         return runToCursorAction(parent);
       
  1354     case RunToNewScriptAction:
       
  1355         return runToNewScriptAction(parent);
       
  1356     case ToggleBreakpointAction:
       
  1357         return toggleBreakpointAction(parent);
       
  1358     case ClearDebugOutputAction:
       
  1359         return clearDebugOutputAction(parent);
       
  1360     case ClearErrorLogAction:
       
  1361         return clearErrorLogAction(parent);
       
  1362     case ClearConsoleAction:
       
  1363         return clearConsoleAction(parent);
       
  1364     case FindInScriptAction:
       
  1365         return findInScriptAction(parent);
       
  1366     case FindNextInScriptAction:
       
  1367         return findNextInScriptAction(parent);
       
  1368     case FindPreviousInScriptAction:
       
  1369         return findPreviousInScriptAction(parent);
       
  1370     case GoToLineAction:
       
  1371         return goToLineAction(parent);
       
  1372     }
       
  1373     return 0;
       
  1374 }
       
  1375 
       
  1376 QWidget *QScriptDebugger::widget(DebuggerWidget widget)
       
  1377 {
       
  1378     switch (widget) {
       
  1379     case ConsoleWidget: {
       
  1380         QScriptDebuggerConsoleWidgetInterface *w = consoleWidget();
       
  1381         if (!w && widgetFactory()) {
       
  1382             w = widgetFactory()->createConsoleWidget();
       
  1383             setConsoleWidget(w);
       
  1384         }
       
  1385         return w;
       
  1386     }
       
  1387     case StackWidget: {
       
  1388         QScriptDebuggerStackWidgetInterface *w = stackWidget();
       
  1389         if (!w && widgetFactory()) {
       
  1390             w = widgetFactory()->createStackWidget();
       
  1391             setStackWidget(w);
       
  1392         }
       
  1393         return w;
       
  1394     }
       
  1395     case ScriptsWidget: {
       
  1396         QScriptDebuggerScriptsWidgetInterface *w = scriptsWidget();
       
  1397         if (!w && widgetFactory()) {
       
  1398             w = widgetFactory()->createScriptsWidget();
       
  1399             setScriptsWidget(w);
       
  1400         }
       
  1401         return w;
       
  1402     }
       
  1403     case LocalsWidget: {
       
  1404         QScriptDebuggerLocalsWidgetInterface *w = localsWidget();
       
  1405         if (!w && widgetFactory()) {
       
  1406             w = widgetFactory()->createLocalsWidget();
       
  1407             setLocalsWidget(w);
       
  1408         }
       
  1409         return w;
       
  1410     }
       
  1411     case CodeWidget: {
       
  1412         QScriptDebuggerCodeWidgetInterface *w = codeWidget();
       
  1413         if (!w && widgetFactory()) {
       
  1414             w = widgetFactory()->createCodeWidget();
       
  1415             setCodeWidget(w);
       
  1416         }
       
  1417         return w;
       
  1418     }
       
  1419     case CodeFinderWidget: {
       
  1420         QScriptDebuggerCodeFinderWidgetInterface *w = codeFinderWidget();
       
  1421         if (!w && widgetFactory()) {
       
  1422             w = widgetFactory()->createCodeFinderWidget();
       
  1423             setCodeFinderWidget(w);
       
  1424         }
       
  1425         return w;
       
  1426     }
       
  1427     case BreakpointsWidget: {
       
  1428         QScriptBreakpointsWidgetInterface *w = breakpointsWidget();
       
  1429         if (!w && widgetFactory()) {
       
  1430             w = widgetFactory()->createBreakpointsWidget();
       
  1431             setBreakpointsWidget(w);
       
  1432         }
       
  1433         return w;
       
  1434     }
       
  1435     case DebugOutputWidget: {
       
  1436         QScriptDebugOutputWidgetInterface *w = debugOutputWidget();
       
  1437         if (!w && widgetFactory()) {
       
  1438             w = widgetFactory()->createDebugOutputWidget();
       
  1439             setDebugOutputWidget(w);
       
  1440         }
       
  1441         return w;
       
  1442     }
       
  1443     case ErrorLogWidget: {
       
  1444         QScriptErrorLogWidgetInterface *w = errorLogWidget();
       
  1445         if (!w && widgetFactory()) {
       
  1446             w = widgetFactory()->createErrorLogWidget();
       
  1447             setErrorLogWidget(w);
       
  1448         }
       
  1449         return w;
       
  1450     }
       
  1451     }
       
  1452     return 0;
       
  1453 }
       
  1454 
       
  1455 QScriptDebuggerConsoleWidgetInterface *QScriptDebugger::consoleWidget() const
       
  1456 {
       
  1457     Q_D(const QScriptDebugger);
       
  1458     return d->consoleWidget;
       
  1459 }
       
  1460 
       
  1461 void QScriptDebugger::setConsoleWidget(QScriptDebuggerConsoleWidgetInterface *consoleWidget)
       
  1462 {
       
  1463     Q_D(QScriptDebugger);
       
  1464     if (d->consoleWidget) {
       
  1465         QObject::disconnect(d->consoleWidget, 0, this, 0);
       
  1466     }
       
  1467     d->consoleWidget = consoleWidget;
       
  1468     if (consoleWidget) {
       
  1469         consoleWidget->setCommandHistorian(d->console);
       
  1470         consoleWidget->setCompletionProvider(d);
       
  1471         QObject::connect(consoleWidget, SIGNAL(lineEntered(QString)),
       
  1472                          this, SLOT(_q_onLineEntered(QString)));
       
  1473 
       
  1474         d->console->showDebuggerInfoMessage(consoleWidget);
       
  1475     }
       
  1476 }
       
  1477 
       
  1478 QScriptDebuggerStackWidgetInterface *QScriptDebugger::stackWidget() const
       
  1479 {
       
  1480     Q_D(const QScriptDebugger);
       
  1481     return d->stackWidget;
       
  1482 }
       
  1483 
       
  1484 void QScriptDebugger::setStackWidget(QScriptDebuggerStackWidgetInterface *stackWidget)
       
  1485 {
       
  1486     Q_D(QScriptDebugger);
       
  1487     if (d->stackWidget) {
       
  1488         QObject::disconnect(d->stackWidget, 0, this, 0);
       
  1489     }
       
  1490     d->stackWidget = stackWidget;
       
  1491     if (stackWidget) {
       
  1492         if (!d->stackModel) {
       
  1493             d->stackModel = new QScriptDebuggerStackModel(this);
       
  1494             if (d->interactive)
       
  1495                 d->scheduleJob(new SyncStackJob(d));
       
  1496         }
       
  1497         stackWidget->setStackModel(d->stackModel);
       
  1498         QObject::connect(stackWidget, SIGNAL(currentFrameChanged(int)),
       
  1499                          this, SLOT(_q_onCurrentFrameChanged(int)));
       
  1500     }
       
  1501 }
       
  1502 
       
  1503 QScriptDebuggerScriptsWidgetInterface *QScriptDebugger::scriptsWidget() const
       
  1504 {
       
  1505     Q_D(const QScriptDebugger);
       
  1506     return d->scriptsWidget;
       
  1507 }
       
  1508 
       
  1509 void QScriptDebugger::setScriptsWidget(QScriptDebuggerScriptsWidgetInterface *scriptsWidget)
       
  1510 {
       
  1511     Q_D(QScriptDebugger);
       
  1512     if (d->scriptsWidget) {
       
  1513         QObject::disconnect(d->scriptsWidget, 0, this, 0);
       
  1514     }
       
  1515     d->scriptsWidget = scriptsWidget;
       
  1516     if (scriptsWidget) {
       
  1517         if (!d->scriptsModel) {
       
  1518             d->scriptsModel = new QScriptDebuggerScriptsModel(this);
       
  1519             if (d->interactive)
       
  1520                 d->scheduleJob(new SyncScriptsJob(d));
       
  1521         }
       
  1522         scriptsWidget->setScriptsModel(d->scriptsModel);
       
  1523         QObject::connect(scriptsWidget, SIGNAL(currentScriptChanged(qint64)),
       
  1524                          this, SLOT(_q_onCurrentScriptChanged(qint64)));
       
  1525         QObject::connect(d->scriptsWidget, SIGNAL(scriptLocationSelected(int)),
       
  1526                          this, SLOT(_q_onScriptLocationSelected(int)));
       
  1527     }
       
  1528 }
       
  1529 
       
  1530 QScriptDebuggerLocalsWidgetInterface *QScriptDebugger::localsWidget() const
       
  1531 {
       
  1532     Q_D(const QScriptDebugger);
       
  1533     return d->localsWidget;
       
  1534 }
       
  1535 
       
  1536 void QScriptDebugger::setLocalsWidget(QScriptDebuggerLocalsWidgetInterface *localsWidget)
       
  1537 {
       
  1538     Q_D(QScriptDebugger);
       
  1539     if (d->localsWidget) {
       
  1540         // ### d->localsWidget->setLocalsModel(0);
       
  1541     }
       
  1542     localsWidget->setCompletionProvider(d);
       
  1543     d->localsWidget = localsWidget;
       
  1544 }
       
  1545 
       
  1546 QScriptDebuggerCodeWidgetInterface *QScriptDebugger::codeWidget() const
       
  1547 {
       
  1548     Q_D(const QScriptDebugger);
       
  1549     return d->codeWidget;
       
  1550 }
       
  1551 
       
  1552 void QScriptDebugger::setCodeWidget(QScriptDebuggerCodeWidgetInterface *codeWidget)
       
  1553 {
       
  1554     Q_D(QScriptDebugger);
       
  1555     if (d->codeWidget) {
       
  1556         d->codeWidget->removeEventFilter(this);
       
  1557     }
       
  1558     d->codeWidget = codeWidget;
       
  1559     if (codeWidget) {
       
  1560         if (!d->scriptsModel) {
       
  1561             d->scriptsModel = new QScriptDebuggerScriptsModel(this);
       
  1562             if (d->interactive)
       
  1563                 d->scheduleJob(new SyncScriptsJob(d));
       
  1564         }
       
  1565         codeWidget->setScriptsModel(d->scriptsModel);
       
  1566         if (!d->breakpointsModel) {
       
  1567             d->breakpointsModel = new QScriptBreakpointsModel(d, d, this);
       
  1568             if (d->interactive)
       
  1569                 d->scheduleJob(new SyncBreakpointsJob(d));
       
  1570         }
       
  1571         codeWidget->setBreakpointsModel(d->breakpointsModel);
       
  1572         codeWidget->setToolTipProvider(d);
       
  1573         codeWidget->installEventFilter(this);
       
  1574     }
       
  1575     bool hasScript = (codeWidget != 0) && (codeWidget->currentView() != 0);
       
  1576     if (d->findInScriptAction)
       
  1577         d->findInScriptAction->setEnabled(hasScript && (d->codeFinderWidget != 0));
       
  1578     if (d->goToLineAction)
       
  1579         d->goToLineAction->setEnabled(hasScript);
       
  1580     if (d->toggleBreakpointAction)
       
  1581         d->toggleBreakpointAction->setEnabled(hasScript);
       
  1582 }
       
  1583 
       
  1584 QScriptDebuggerCodeFinderWidgetInterface *QScriptDebugger::codeFinderWidget() const
       
  1585 {
       
  1586     Q_D(const QScriptDebugger);
       
  1587     return d->codeFinderWidget;
       
  1588 }
       
  1589 
       
  1590 void QScriptDebugger::setCodeFinderWidget(QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget)
       
  1591 {
       
  1592     Q_D(QScriptDebugger);
       
  1593     if (d->codeFinderWidget) {
       
  1594         QObject::disconnect(d->codeFinderWidget, 0, this, 0);
       
  1595     }
       
  1596     d->codeFinderWidget = codeFinderWidget;
       
  1597     if (codeFinderWidget) {
       
  1598         QObject::connect(codeFinderWidget, SIGNAL(findRequest(QString,int)),
       
  1599                          this, SLOT(_q_onFindCodeRequest(QString,int)));
       
  1600     }
       
  1601     if (d->findInScriptAction) {
       
  1602         d->findInScriptAction->setEnabled(
       
  1603             (codeFinderWidget != 0)
       
  1604             && (d->codeWidget != 0)
       
  1605             && (d->codeWidget->currentView() != 0));
       
  1606     }
       
  1607 }
       
  1608 
       
  1609 QScriptDebugOutputWidgetInterface *QScriptDebugger::debugOutputWidget() const
       
  1610 {
       
  1611     Q_D(const QScriptDebugger);
       
  1612     return d->debugOutputWidget;
       
  1613 }
       
  1614 
       
  1615 void QScriptDebugger::setDebugOutputWidget(QScriptDebugOutputWidgetInterface *debugOutputWidget)
       
  1616 {
       
  1617     Q_D(QScriptDebugger);
       
  1618     d->debugOutputWidget = debugOutputWidget;
       
  1619 }
       
  1620 
       
  1621 QScriptBreakpointsWidgetInterface *QScriptDebugger::breakpointsWidget() const
       
  1622 {
       
  1623     Q_D(const QScriptDebugger);
       
  1624     return d->breakpointsWidget;
       
  1625 }
       
  1626 
       
  1627 void QScriptDebugger::setBreakpointsWidget(QScriptBreakpointsWidgetInterface *breakpointsWidget)
       
  1628 {
       
  1629     Q_D(QScriptDebugger);
       
  1630     if (d->breakpointsWidget) {
       
  1631         // ### invalidate
       
  1632     }
       
  1633     d->breakpointsWidget = breakpointsWidget;
       
  1634     if (breakpointsWidget) {
       
  1635         if (!d->breakpointsModel) {
       
  1636             d->breakpointsModel = new QScriptBreakpointsModel(d, d, this);
       
  1637             if (d->interactive)
       
  1638                 d->scheduleJob(new SyncBreakpointsJob(d));
       
  1639         }
       
  1640         d->breakpointsWidget->setBreakpointsModel(d->breakpointsModel);
       
  1641         d->breakpointsWidget->setScriptsModel(d->scriptsModel);
       
  1642     }
       
  1643 }
       
  1644 
       
  1645 QScriptErrorLogWidgetInterface *QScriptDebugger::errorLogWidget() const
       
  1646 {
       
  1647     Q_D(const QScriptDebugger);
       
  1648     return d->errorLogWidget;
       
  1649 }
       
  1650 
       
  1651 void QScriptDebugger::setErrorLogWidget(QScriptErrorLogWidgetInterface *errorLogWidget)
       
  1652 {
       
  1653     Q_D(QScriptDebugger);
       
  1654     d->errorLogWidget = errorLogWidget;
       
  1655 }
       
  1656 
       
  1657 QScriptDebuggerWidgetFactoryInterface *QScriptDebugger::widgetFactory() const
       
  1658 {
       
  1659     Q_D(const QScriptDebugger);
       
  1660     return d->widgetFactory;
       
  1661 }
       
  1662 
       
  1663 void QScriptDebugger::setWidgetFactory(QScriptDebuggerWidgetFactoryInterface *factory)
       
  1664 {
       
  1665     Q_D(QScriptDebugger);
       
  1666     d->widgetFactory = factory;
       
  1667 }
       
  1668 
       
  1669 QAction *QScriptDebugger::interruptAction(QObject *parent) const
       
  1670 {
       
  1671     Q_D(const QScriptDebugger);
       
  1672     if (!d->interruptAction) {
       
  1673         QIcon interruptIcon;
       
  1674         interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("interrupt.png")), QIcon::Normal);
       
  1675         interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_interrupt.png")), QIcon::Disabled);
       
  1676         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1677         that->d_func()->interruptAction = new QAction(interruptIcon, QScriptDebugger::tr("Interrupt"), parent);
       
  1678         d->interruptAction->setEnabled(!d->interactive);
       
  1679         d->interruptAction->setShortcut(QScriptDebugger::tr("Shift+F5"));
       
  1680         QObject::connect(d->interruptAction, SIGNAL(triggered()),
       
  1681                          that, SLOT(_q_interrupt()));
       
  1682     }
       
  1683     return d->interruptAction;
       
  1684 }
       
  1685 
       
  1686 QAction *QScriptDebugger::continueAction(QObject *parent) const
       
  1687 {
       
  1688     Q_D(const QScriptDebugger);
       
  1689     if (!d->continueAction) {
       
  1690         QIcon continueIcon;
       
  1691         continueIcon.addPixmap(d->pixmap(QString::fromLatin1("play.png")), QIcon::Normal);
       
  1692         continueIcon.addPixmap(d->pixmap(QString::fromLatin1("d_play.png")), QIcon::Disabled);
       
  1693         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1694         that->d_func()->continueAction = new QAction(continueIcon, QScriptDebugger::tr("Continue"), parent);
       
  1695         d->continueAction->setEnabled(d->interactive);
       
  1696         d->continueAction->setShortcut(QScriptDebugger::tr("F5"));
       
  1697         QObject::connect(d->continueAction, SIGNAL(triggered()),
       
  1698                          that, SLOT(_q_continue()));
       
  1699     }
       
  1700     return d->continueAction;
       
  1701 }
       
  1702 
       
  1703 QAction *QScriptDebugger::stepIntoAction(QObject *parent) const
       
  1704 {
       
  1705     Q_D(const QScriptDebugger);
       
  1706     if (!d->stepIntoAction) {
       
  1707         QIcon stepIntoIcon;
       
  1708         stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("stepinto.png")), QIcon::Normal);
       
  1709         stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepinto.png")), QIcon::Disabled);
       
  1710         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1711         that->d_func()->stepIntoAction = new QAction(stepIntoIcon, QScriptDebugger::tr("Step Into"), parent);
       
  1712         d->stepIntoAction->setEnabled(d->interactive);
       
  1713         d->stepIntoAction->setShortcut(QScriptDebugger::tr("F11"));
       
  1714         QObject::connect(d->stepIntoAction, SIGNAL(triggered()),
       
  1715                          that, SLOT(_q_stepInto()));
       
  1716     }
       
  1717     return d->stepIntoAction;
       
  1718 }
       
  1719 
       
  1720 QAction *QScriptDebugger::stepOverAction(QObject *parent) const
       
  1721 {
       
  1722     Q_D(const QScriptDebugger);
       
  1723     if (!d->stepOverAction) {
       
  1724         QIcon stepOverIcon;
       
  1725         stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("stepover.png")), QIcon::Normal);
       
  1726         stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepover.png")), QIcon::Disabled);
       
  1727         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1728         that->d_func()->stepOverAction = new QAction(stepOverIcon, QScriptDebugger::tr("Step Over"), parent);
       
  1729         d->stepOverAction->setEnabled(d->interactive);
       
  1730         d->stepOverAction->setShortcut(QScriptDebugger::tr("F10"));
       
  1731         QObject::connect(d->stepOverAction, SIGNAL(triggered()),
       
  1732                          that, SLOT(_q_stepOver()));
       
  1733     }
       
  1734     return d->stepOverAction;
       
  1735 }
       
  1736 
       
  1737 QAction *QScriptDebugger::stepOutAction(QObject *parent) const
       
  1738 {
       
  1739     Q_D(const QScriptDebugger);
       
  1740     if (!d->stepOutAction) {
       
  1741         QIcon stepOutIcon;
       
  1742         stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("stepout.png")), QIcon::Normal);
       
  1743         stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepout.png")), QIcon::Disabled);
       
  1744         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1745         that->d_func()->stepOutAction = new QAction(stepOutIcon, QScriptDebugger::tr("Step Out"), parent);
       
  1746         d->stepOutAction->setEnabled(d->interactive);
       
  1747         d->stepOutAction->setShortcut(QScriptDebugger::tr("Shift+F11"));
       
  1748         QObject::connect(d->stepOutAction, SIGNAL(triggered()),
       
  1749                          that, SLOT(_q_stepOut()));
       
  1750     }
       
  1751     return d->stepOutAction;
       
  1752 }
       
  1753 
       
  1754 QAction *QScriptDebugger::runToCursorAction(QObject *parent) const
       
  1755 {
       
  1756     Q_D(const QScriptDebugger);
       
  1757     if (!d->runToCursorAction) {
       
  1758         QIcon runToCursorIcon;
       
  1759         runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("runtocursor.png")), QIcon::Normal);
       
  1760         runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("d_runtocursor.png")), QIcon::Disabled);
       
  1761         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1762         that->d_func()->runToCursorAction = new QAction(runToCursorIcon, QScriptDebugger::tr("Run to Cursor"), parent);
       
  1763         d->runToCursorAction->setEnabled(d->interactive);
       
  1764         d->runToCursorAction->setShortcut(QScriptDebugger::tr("Ctrl+F10"));
       
  1765         QObject::connect(d->runToCursorAction, SIGNAL(triggered()),
       
  1766                          that, SLOT(_q_runToCursor()));
       
  1767     }
       
  1768     return d->runToCursorAction;
       
  1769 }
       
  1770 
       
  1771 QAction *QScriptDebugger::runToNewScriptAction(QObject *parent) const
       
  1772 {
       
  1773     Q_D(const QScriptDebugger);
       
  1774     if (!d->runToNewScriptAction) {
       
  1775         QIcon runToNewScriptIcon;
       
  1776         runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("runtonewscript.png")), QIcon::Normal);
       
  1777         runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_breakonscriptload.png")), QIcon::Disabled);
       
  1778         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1779         that->d_func()->runToNewScriptAction = new QAction(runToNewScriptIcon,
       
  1780                                                            QScriptDebugger::tr("Run to New Script"), parent);
       
  1781         d->runToNewScriptAction->setEnabled(d->interactive);
       
  1782         QObject::connect(d->runToNewScriptAction, SIGNAL(triggered()),
       
  1783                          that, SLOT(_q_runToNewScript()));
       
  1784     }
       
  1785     return d->runToNewScriptAction;
       
  1786 }
       
  1787 
       
  1788 QAction *QScriptDebugger::toggleBreakpointAction(QObject *parent) const
       
  1789 {
       
  1790     Q_D(const QScriptDebugger);
       
  1791     if (!d->toggleBreakpointAction) {
       
  1792         QIcon toggleBreakpointIcon;
       
  1793         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1794         that->d_func()->toggleBreakpointAction = new QAction(toggleBreakpointIcon,
       
  1795                                                              QScriptDebugger::tr("Toggle Breakpoint"), parent);
       
  1796         d->toggleBreakpointAction->setShortcut(QScriptDebugger::tr("F9"));
       
  1797         d->toggleBreakpointAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0));
       
  1798         QObject::connect(d->toggleBreakpointAction, SIGNAL(triggered()),
       
  1799                          that, SLOT(_q_toggleBreakpoint()));
       
  1800     }
       
  1801     return d->toggleBreakpointAction;
       
  1802 }
       
  1803 
       
  1804 QAction *QScriptDebugger::clearDebugOutputAction(QObject *parent) const
       
  1805 {
       
  1806     Q_D(const QScriptDebugger);
       
  1807     if (!d->clearDebugOutputAction) {
       
  1808         QIcon clearDebugOutputIcon;
       
  1809         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1810         that->d_func()->clearDebugOutputAction = new QAction(clearDebugOutputIcon, QScriptDebugger::tr("Clear Debug Output"), parent);
       
  1811         QObject::connect(d->clearDebugOutputAction, SIGNAL(triggered()),
       
  1812                          that, SLOT(_q_clearDebugOutput()));
       
  1813     }
       
  1814     return d->clearDebugOutputAction;
       
  1815 }
       
  1816 
       
  1817 QAction *QScriptDebugger::clearErrorLogAction(QObject *parent) const
       
  1818 {
       
  1819     Q_D(const QScriptDebugger);
       
  1820     if (!d->clearErrorLogAction) {
       
  1821         QIcon clearErrorLogIcon;
       
  1822         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1823         that->d_func()->clearErrorLogAction = new QAction(clearErrorLogIcon, QScriptDebugger::tr("Clear Error Log"), parent);
       
  1824         QObject::connect(d->clearErrorLogAction, SIGNAL(triggered()),
       
  1825                          that, SLOT(_q_clearErrorLog()));
       
  1826     }
       
  1827     return d->clearErrorLogAction;
       
  1828 }
       
  1829 
       
  1830 QAction *QScriptDebugger::clearConsoleAction(QObject *parent) const
       
  1831 {
       
  1832     Q_D(const QScriptDebugger);
       
  1833     if (!d->clearConsoleAction) {
       
  1834         QIcon clearConsoleIcon;
       
  1835         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1836         that->d_func()->clearConsoleAction = new QAction(clearConsoleIcon, QScriptDebugger::tr("Clear Console"), parent);
       
  1837         QObject::connect(d->clearConsoleAction, SIGNAL(triggered()),
       
  1838                          that, SLOT(_q_clearConsole()));
       
  1839     }
       
  1840     return d->clearConsoleAction;
       
  1841 }
       
  1842 
       
  1843 QAction *QScriptDebugger::findInScriptAction(QObject *parent) const
       
  1844 {
       
  1845     Q_D(const QScriptDebugger);
       
  1846     if (!d->findInScriptAction) {
       
  1847         QIcon findInScriptIcon;
       
  1848         findInScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("find.png")), QIcon::Normal);
       
  1849         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1850         that->d_func()->findInScriptAction = new QAction(findInScriptIcon, QScriptDebugger::tr("&Find in Script..."), parent);
       
  1851         d->findInScriptAction->setShortcut(QScriptDebugger::tr("Ctrl+F"));
       
  1852         d->findInScriptAction->setEnabled(
       
  1853             (d->codeFinderWidget != 0)
       
  1854             && (d->codeWidget != 0)
       
  1855             && (d->codeWidget->currentView() != 0));
       
  1856         QObject::connect(d->findInScriptAction, SIGNAL(triggered()),
       
  1857                          that, SLOT(_q_findInScript()));
       
  1858     }
       
  1859     return d->findInScriptAction;
       
  1860 }
       
  1861 
       
  1862 QAction *QScriptDebugger::findNextInScriptAction(QObject *parent) const
       
  1863 {
       
  1864     Q_D(const QScriptDebugger);
       
  1865     if (!d->findNextInScriptAction) {
       
  1866         QIcon findNextInScriptIcon;
       
  1867         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1868         that->d_func()->findNextInScriptAction = new QAction(findNextInScriptIcon, QScriptDebugger::tr("Find &Next"), parent);
       
  1869         d->findNextInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty());
       
  1870         d->findNextInScriptAction->setShortcut(QScriptDebugger::tr("F3"));
       
  1871         QObject::connect(d->findNextInScriptAction, SIGNAL(triggered()),
       
  1872                          that, SLOT(_q_findNextInScript()));
       
  1873     }
       
  1874     return d->findNextInScriptAction;
       
  1875 }
       
  1876 
       
  1877 QAction *QScriptDebugger::findPreviousInScriptAction(QObject *parent) const
       
  1878 {
       
  1879     Q_D(const QScriptDebugger);
       
  1880     if (!d->findPreviousInScriptAction) {
       
  1881         QIcon findPreviousInScriptIcon;
       
  1882         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1883         that->d_func()->findPreviousInScriptAction = new QAction(findPreviousInScriptIcon, QScriptDebugger::tr("Find &Previous"), parent);
       
  1884         d->findPreviousInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty());
       
  1885         d->findPreviousInScriptAction->setShortcut(QScriptDebugger::tr("Shift+F3"));
       
  1886         QObject::connect(d->findPreviousInScriptAction, SIGNAL(triggered()),
       
  1887                          that, SLOT(_q_findPreviousInScript()));
       
  1888     }
       
  1889     return d->findPreviousInScriptAction;
       
  1890 }
       
  1891 
       
  1892 QAction *QScriptDebugger::goToLineAction(QObject *parent) const
       
  1893 {
       
  1894     Q_D(const QScriptDebugger);
       
  1895     if (!d->goToLineAction) {
       
  1896         QIcon goToLineIcon;
       
  1897         QScriptDebugger *that = const_cast<QScriptDebugger*>(this);
       
  1898         that->d_func()->goToLineAction = new QAction(goToLineIcon, QScriptDebugger::tr("Go to Line"), parent);
       
  1899         d->goToLineAction->setShortcut(QScriptDebugger::tr("Ctrl+G"));
       
  1900         d->goToLineAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0));
       
  1901         QObject::connect(d->goToLineAction, SIGNAL(triggered()),
       
  1902                          that, SLOT(_q_goToLine()));
       
  1903     }
       
  1904     return d->goToLineAction;
       
  1905 }
       
  1906 
       
  1907 QMenu *QScriptDebugger::createStandardMenu(QWidget *widgetParent, QObject *actionParent)
       
  1908 {
       
  1909     QMenu *menu = new QMenu(widgetParent);
       
  1910     menu->setTitle(QScriptDebugger::tr("Debug"));
       
  1911     menu->addAction(action(ContinueAction, actionParent));
       
  1912     menu->addAction(action(InterruptAction, actionParent));
       
  1913     menu->addAction(action(StepIntoAction, actionParent));
       
  1914     menu->addAction(action(StepOverAction, actionParent));
       
  1915     menu->addAction(action(StepOutAction, actionParent));
       
  1916     menu->addAction(action(RunToCursorAction, actionParent));
       
  1917     menu->addAction(action(RunToNewScriptAction, actionParent));
       
  1918 
       
  1919     menu->addSeparator();
       
  1920     menu->addAction(action(ToggleBreakpointAction, actionParent));
       
  1921 
       
  1922     menu->addSeparator();
       
  1923     menu->addAction(action(ClearDebugOutputAction, actionParent));
       
  1924     menu->addAction(action(ClearErrorLogAction, actionParent));
       
  1925     menu->addAction(action(ClearConsoleAction, actionParent));
       
  1926 
       
  1927     return menu;
       
  1928 }
       
  1929 
       
  1930 #ifndef QT_NO_TOOLBAR
       
  1931 QToolBar *QScriptDebugger::createStandardToolBar(QWidget *widgetParent, QObject *actionParent)
       
  1932 {
       
  1933     QToolBar *tb = new QToolBar(widgetParent);
       
  1934     tb->setObjectName(QLatin1String("qtscriptdebugger_standardToolBar"));
       
  1935     tb->addAction(action(ContinueAction, actionParent));
       
  1936     tb->addAction(action(InterruptAction, actionParent));
       
  1937     tb->addAction(action(StepIntoAction, actionParent));
       
  1938     tb->addAction(action(StepOverAction, actionParent));
       
  1939     tb->addAction(action(StepOutAction, actionParent));
       
  1940     tb->addAction(action(RunToCursorAction, actionParent));
       
  1941     tb->addAction(action(RunToNewScriptAction, actionParent));
       
  1942     tb->addSeparator();
       
  1943     tb->addAction(action(FindInScriptAction, actionParent));
       
  1944     return tb;
       
  1945 }
       
  1946 #endif
       
  1947 
       
  1948 bool QScriptDebugger::isInteractive() const
       
  1949 {
       
  1950     Q_D(const QScriptDebugger);
       
  1951     return d->interactive;
       
  1952 }
       
  1953 
       
  1954 /*!
       
  1955   \reimp
       
  1956 */
       
  1957 bool QScriptDebugger::eventFilter(QObject *watched, QEvent *e)
       
  1958 {
       
  1959     Q_D(QScriptDebugger);
       
  1960     if (watched == d->codeWidget) {
       
  1961         if (e->type() == QEvent::KeyPress) {
       
  1962             d->_q_findInScript();
       
  1963             d->codeFinderWidget->setText(static_cast<QKeyEvent*>(e)->text());
       
  1964             return true;
       
  1965         }
       
  1966     }
       
  1967     return false;
       
  1968 }
       
  1969 
       
  1970 /*!
       
  1971   \reimp
       
  1972 */
       
  1973 void QScriptDebugger::timerEvent(QTimerEvent *e)
       
  1974 {
       
  1975     Q_D(QScriptDebugger);
       
  1976     if (e->timerId() == d->updatesEnabledTimerId) {
       
  1977         killTimer(d->updatesEnabledTimerId);
       
  1978         d->updatesEnabledTimerId = -1;
       
  1979         if (d->stackWidget)
       
  1980             d->stackWidget->setUpdatesEnabled(true);
       
  1981         if (d->localsWidget)
       
  1982             d->localsWidget->setUpdatesEnabled(true);
       
  1983     } else {
       
  1984         QObject::timerEvent(e);
       
  1985     }
       
  1986 }
       
  1987 
       
  1988 QT_END_NAMESPACE
       
  1989 
       
  1990 #include "moc_qscriptdebugger_p.cpp"