| /**************************************************************************** |
| ** |
| ** Copyright (C) 2018 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtSCriptTools module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qscriptdebugger_p.h" |
| #include "qscriptdebuggerconsole_p.h" |
| #include "qscriptdebuggerconsolecommandmanager_p.h" |
| #include "qscriptdebuggerconsolecommandjob_p.h" |
| #include "qscriptstdmessagehandler_p.h" |
| #include "qscriptdebuggerfrontend_p.h" |
| #include "qscriptdebuggereventhandlerinterface_p.h" |
| #include "qscriptdebuggerresponsehandlerinterface_p.h" |
| #include "qscriptdebuggerjobschedulerinterface_p.h" |
| #include "qscriptdebuggerconsolewidgetinterface_p.h" |
| #include "qscriptcompletionproviderinterface_p.h" |
| #include "qscriptcompletiontask_p.h" |
| #include "qscripttooltipproviderinterface_p.h" |
| #include "qscriptdebuggerstackwidgetinterface_p.h" |
| #include "qscriptdebuggerstackmodel_p.h" |
| #include "qscriptdebuggerscriptswidgetinterface_p.h" |
| #include "qscriptdebuggerscriptsmodel_p.h" |
| #include "qscriptdebuggerlocalswidgetinterface_p.h" |
| #include "qscriptdebuggerlocalsmodel_p.h" |
| #include "qscriptdebuggercodewidgetinterface_p.h" |
| #include "qscriptdebuggercodeviewinterface_p.h" |
| #include "qscriptdebuggercodefinderwidgetinterface_p.h" |
| #include "qscriptbreakpointswidgetinterface_p.h" |
| #include "qscriptbreakpointsmodel_p.h" |
| #include "qscriptdebugoutputwidgetinterface_p.h" |
| #include "qscripterrorlogwidgetinterface_p.h" |
| #include "qscriptdebuggerwidgetfactoryinterface_p.h" |
| #include "qscriptdebuggerevent_p.h" |
| #include "qscriptdebuggervalue_p.h" |
| #include "qscriptdebuggerresponse_p.h" |
| #include "qscriptdebuggercommand_p.h" |
| #include "qscriptdebuggercommandschedulerfrontend_p.h" |
| #include "qscriptdebuggercommandschedulerjob_p.h" |
| #include "qscriptdebuggerjob_p_p.h" |
| #include "qscriptxmlparser_p.h" |
| |
| #include "private/qobject_p.h" |
| |
| #include <QtScript/qscriptcontext.h> |
| #include <QtScript/qscriptcontextinfo.h> |
| |
| #include <QtCore/qcoreapplication.h> |
| #include <QtCore/qdir.h> |
| #include <QtCore/qfileinfo.h> |
| #include <QtCore/qstringlist.h> |
| #include <QtCore/qdebug.h> |
| |
| #include <QtWidgets/qaction.h> |
| #include <QtGui/qevent.h> |
| #include <QtGui/qicon.h> |
| #include <QtWidgets/qinputdialog.h> |
| #include <QtWidgets/qmenu.h> |
| #include <QtWidgets/qtoolbar.h> |
| #include <QtWidgets/qtooltip.h> |
| |
| QT_BEGIN_NAMESPACE |
| typedef QPair<QList<qint64>, QList<qint64> > QScriptScriptsDelta; |
| typedef QPair<QList<qint64>, QList<qint64> > QScriptContextsDelta; |
| QT_END_NAMESPACE |
| |
| Q_DECLARE_METATYPE(QScriptScriptsDelta) |
| |
| QT_BEGIN_NAMESPACE |
| |
| Q_SCRIPT_EXPORT QString qt_scriptToXml(const QString &program, int lineNumber = 1); |
| |
| namespace { |
| |
| static int scriptDebuggerCount = 0; |
| static bool eventCallbackRegistered = false; |
| static bool widgetInPaintEvent = false; |
| |
| static bool scriptDebuggerEventCallback(void **data) |
| { |
| QEvent *event = reinterpret_cast<QEvent*>(data[1]); |
| if (event->type() == QEvent::Paint) { |
| QObject *receiver = reinterpret_cast<QObject*>(data[0]); |
| bool was = widgetInPaintEvent; |
| widgetInPaintEvent = true; |
| QCoreApplication::instance()->notify(receiver, event); |
| widgetInPaintEvent = was; |
| bool *result = reinterpret_cast<bool*>(data[2]); |
| *result = true; |
| return true; |
| } |
| return false; |
| } |
| |
| } |
| |
| /*! |
| \since 4.5 |
| \class QScriptDebugger |
| \internal |
| |
| \brief The QScriptDebugger class provides a Qt Script debugger. |
| |
| \ingroup script |
| */ |
| |
| class QScriptDebuggerPrivate |
| : public QObjectPrivate, |
| public QScriptDebuggerCommandSchedulerInterface, |
| public QScriptDebuggerJobSchedulerInterface, |
| public QScriptDebuggerEventHandlerInterface, |
| public QScriptDebuggerResponseHandlerInterface, |
| public QScriptCompletionProviderInterface, |
| public QScriptToolTipProviderInterface |
| { |
| Q_DECLARE_PUBLIC(QScriptDebugger) |
| public: |
| QScriptDebuggerPrivate(); |
| ~QScriptDebuggerPrivate(); |
| |
| int scheduleJob(QScriptDebuggerJob *job); |
| void finishJob(QScriptDebuggerJob *job); |
| void hibernateUntilEvaluateFinished(QScriptDebuggerJob *job); |
| |
| void maybeStartNewJob(); |
| |
| int scheduleCommand(const QScriptDebuggerCommand &command, |
| QScriptDebuggerResponseHandlerInterface *responseHandler); |
| |
| void handleResponse( |
| const QScriptDebuggerResponse &response, int commandId); |
| bool debuggerEvent(const QScriptDebuggerEvent &event); |
| |
| QScriptCompletionTaskInterface *createCompletionTask( |
| const QString &contents, int cursorPosition, int frameIndex, int options); |
| |
| void showToolTip(const QPoint &pos, int frameIndex, |
| int lineNumber, const QStringList &path); |
| |
| static QPixmap pixmap(const QString &path); |
| |
| void startInteraction(QScriptDebuggerEvent::Type type, |
| qint64 scriptId, int lineNumber); |
| void sync(); |
| void loadLocals(int frameIndex); |
| QScriptDebuggerLocalsModel *createLocalsModel(); |
| void selectScriptForFrame(int frameIndex); |
| void emitStoppedSignal(); |
| |
| void maybeDelete(QWidget *widget); |
| |
| // private slots |
| void _q_onLineEntered(const QString &contents); |
| void _q_onCurrentFrameChanged(int frameIndex); |
| void _q_onCurrentScriptChanged(qint64 scriptId); |
| void _q_onScriptLocationSelected(int lineNumber); |
| void _q_interrupt(); |
| void _q_continue(); |
| void _q_stepInto(); |
| void _q_stepOver(); |
| void _q_stepOut(); |
| void _q_runToCursor(); |
| void _q_runToNewScript(); |
| void _q_toggleBreakpoint(); |
| void _q_clearDebugOutput(); |
| void _q_clearErrorLog(); |
| void _q_clearConsole(); |
| void _q_findInScript(); |
| void _q_findNextInScript(); |
| void _q_findPreviousInScript(); |
| void _q_onFindCodeRequest(const QString &, int); |
| void _q_goToLine(); |
| |
| void executeConsoleCommand(const QString &command); |
| void findCode(const QString &exp, int options); |
| |
| QScriptDebuggerFrontend *frontend; |
| |
| bool interactive; |
| QScriptDebuggerConsole *console; |
| |
| int nextJobId; |
| QList<QScriptDebuggerJob*> pendingJobs; |
| QList<int> pendingJobIds; |
| QScriptDebuggerJob *activeJob; |
| bool activeJobHibernating; |
| QHash<int, QScriptDebuggerCommand> watchedCommands; |
| QHash<int, QScriptDebuggerResponseHandlerInterface*> responseHandlers; |
| |
| QScriptDebuggerConsoleWidgetInterface *consoleWidget; |
| QScriptDebuggerStackWidgetInterface *stackWidget; |
| QScriptDebuggerStackModel *stackModel; |
| QScriptDebuggerScriptsWidgetInterface *scriptsWidget; |
| QScriptDebuggerScriptsModel *scriptsModel; |
| QScriptDebuggerLocalsWidgetInterface *localsWidget; |
| QHash<int, QScriptDebuggerLocalsModel*> localsModels; |
| QScriptDebuggerCodeWidgetInterface *codeWidget; |
| QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget; |
| QScriptBreakpointsWidgetInterface *breakpointsWidget; |
| QScriptBreakpointsModel *breakpointsModel; |
| QScriptDebugOutputWidgetInterface *debugOutputWidget; |
| QScriptErrorLogWidgetInterface *errorLogWidget; |
| QScriptDebuggerWidgetFactoryInterface *widgetFactory; |
| |
| QAction *interruptAction; |
| QAction *continueAction; |
| QAction *stepIntoAction; |
| QAction *stepOverAction; |
| QAction *stepOutAction; |
| QAction *runToCursorAction; |
| QAction *runToNewScriptAction; |
| |
| QAction *toggleBreakpointAction; |
| |
| QAction *clearDebugOutputAction; |
| QAction *clearErrorLogAction; |
| QAction *clearConsoleAction; |
| |
| QAction *findInScriptAction; |
| QAction *findNextInScriptAction; |
| QAction *findPreviousInScriptAction; |
| QAction *goToLineAction; |
| |
| int updatesEnabledTimerId; |
| }; |
| |
| QScriptDebuggerPrivate::QScriptDebuggerPrivate() |
| { |
| frontend = 0; |
| activeJob = 0; |
| activeJobHibernating = false; |
| nextJobId = 0; |
| interactive = false; |
| |
| console = new QScriptDebuggerConsole(); |
| QString scriptsPath = QLatin1String(":/qt/scripttools/debugging/scripts/commands"); |
| QScriptStdMessageHandler tmp; |
| console->loadScriptedCommands(scriptsPath, &tmp); |
| |
| consoleWidget = 0; |
| stackWidget = 0; |
| stackModel = 0; |
| scriptsWidget = 0; |
| scriptsModel = 0; |
| localsWidget = 0; |
| codeWidget = 0; |
| codeFinderWidget = 0; |
| breakpointsWidget = 0; |
| breakpointsModel = 0; |
| debugOutputWidget = 0; |
| errorLogWidget = 0; |
| widgetFactory = 0; |
| |
| interruptAction = 0; |
| continueAction = 0; |
| stepIntoAction = 0; |
| stepOverAction = 0; |
| stepOutAction = 0; |
| runToCursorAction = 0; |
| runToNewScriptAction = 0; |
| |
| toggleBreakpointAction = 0; |
| |
| clearErrorLogAction = 0; |
| clearDebugOutputAction = 0; |
| clearConsoleAction = 0; |
| |
| findInScriptAction = 0; |
| findNextInScriptAction = 0; |
| findPreviousInScriptAction = 0; |
| goToLineAction = 0; |
| |
| updatesEnabledTimerId = -1; |
| } |
| |
| QScriptDebuggerPrivate::~QScriptDebuggerPrivate() |
| { |
| delete console; |
| qDeleteAll(pendingJobs); |
| delete activeJob; |
| maybeDelete(consoleWidget); |
| maybeDelete(stackWidget); |
| maybeDelete(scriptsWidget); |
| maybeDelete(localsWidget); |
| maybeDelete(codeWidget); |
| maybeDelete(codeFinderWidget); |
| maybeDelete(breakpointsWidget); |
| maybeDelete(debugOutputWidget); |
| maybeDelete(errorLogWidget); |
| } |
| |
| void QScriptDebuggerPrivate::maybeDelete(QWidget *widget) |
| { |
| if (widget && !widget->parent()) |
| delete widget; |
| } |
| |
| QPixmap QScriptDebuggerPrivate::pixmap(const QString &path) |
| { |
| static QString prefix = QString::fromLatin1(":/qt/scripttools/debugging/images/"); |
| return QPixmap(prefix + path); |
| } |
| |
| /* |
| \reimp |
| */ |
| int QScriptDebuggerPrivate::scheduleJob(QScriptDebuggerJob *job) |
| { |
| QScriptDebuggerJobPrivate *priv = QScriptDebuggerJobPrivate::get(job); |
| Q_ASSERT(priv->jobScheduler == 0); |
| priv->jobScheduler = this; |
| int id = nextJobId; |
| pendingJobs.append(job); |
| pendingJobIds.append(id); |
| maybeStartNewJob(); |
| return id; |
| } |
| |
| /* |
| \reimp |
| */ |
| void QScriptDebuggerPrivate::finishJob(QScriptDebuggerJob *job) |
| { |
| Q_UNUSED(job); |
| Q_ASSERT(activeJob == job); |
| delete activeJob; |
| activeJob = 0; |
| activeJobHibernating = false; |
| maybeStartNewJob(); |
| } |
| |
| /* |
| \reimp |
| */ |
| void QScriptDebuggerPrivate::hibernateUntilEvaluateFinished(QScriptDebuggerJob *job) |
| { |
| Q_UNUSED(job); |
| Q_ASSERT(activeJob == job); |
| activeJobHibernating = true; |
| } |
| |
| /* |
| Starts a new job if appropriate. |
| */ |
| void QScriptDebuggerPrivate::maybeStartNewJob() |
| { |
| if (activeJob || pendingJobs.isEmpty()) |
| return; |
| activeJob = pendingJobs.takeFirst(); |
| activeJob->start(); |
| } |
| |
| /* |
| \reimp |
| */ |
| int QScriptDebuggerPrivate::scheduleCommand( |
| const QScriptDebuggerCommand &command, |
| QScriptDebuggerResponseHandlerInterface *responseHandler) |
| { |
| if (!frontend) |
| return -1; |
| int id = frontend->scheduleCommand(command, this); |
| if (responseHandler && (responseHandler != this)) |
| responseHandlers.insert(id, responseHandler); |
| if ((command.type() == QScriptDebuggerCommand::SetBreakpoint) |
| || (command.type() == QScriptDebuggerCommand::SetBreakpointData) |
| || (command.type() == QScriptDebuggerCommand::DeleteBreakpoint)) { |
| // need to watch this command and update the breakpoints model afterwards |
| watchedCommands.insert(id, command); |
| } |
| return id; |
| } |
| |
| /* |
| \reimp |
| */ |
| void QScriptDebuggerPrivate::handleResponse( |
| const QScriptDebuggerResponse &response, int commandId) |
| { |
| Q_Q(QScriptDebugger); |
| if (watchedCommands.contains(commandId)) { |
| QScriptDebuggerCommand command = watchedCommands.take(commandId); |
| if (response.error() == QScriptDebuggerResponse::NoError) { |
| if (!breakpointsModel) |
| breakpointsModel = new QScriptBreakpointsModel(this, this, q); |
| switch (command.type()) { |
| case QScriptDebuggerCommand::SetBreakpoint: { |
| int breakpointId = response.resultAsInt(); |
| QScriptBreakpointData data = command.breakpointData(); |
| breakpointsModel->addBreakpoint(breakpointId, data); |
| } break; |
| case QScriptDebuggerCommand::SetBreakpointData: { |
| int breakpointId = command.breakpointId(); |
| QScriptBreakpointData data = command.breakpointData(); |
| breakpointsModel->modifyBreakpoint(breakpointId, data); |
| } break; |
| case QScriptDebuggerCommand::DeleteBreakpoint: { |
| int breakpointId = command.breakpointId(); |
| breakpointsModel->removeBreakpoint(breakpointId); |
| } break; |
| default: |
| Q_ASSERT(false); |
| } |
| } |
| } else if (response.async()) { |
| interactive = false; |
| // disable/invalidate/enable stuff |
| if (continueAction) |
| continueAction->setEnabled(false); |
| if (stepIntoAction) |
| stepIntoAction->setEnabled(false); |
| if (stepOverAction) |
| stepOverAction->setEnabled(false); |
| if (stepOutAction) |
| stepOutAction->setEnabled(false); |
| if (runToCursorAction) |
| runToCursorAction->setEnabled(false); |
| if (runToNewScriptAction) |
| runToNewScriptAction->setEnabled(false); |
| if (interruptAction) |
| interruptAction->setEnabled(true); |
| |
| // the timer is to avoid flicker when stepping |
| if (stackWidget) { |
| stackWidget->setUpdatesEnabled(false); |
| stackWidget->setEnabled(false); |
| if (updatesEnabledTimerId == -1) |
| updatesEnabledTimerId = q->startTimer(75); |
| } |
| if (localsWidget) { |
| localsWidget->setUpdatesEnabled(false); |
| localsWidget->setEnabled(false); |
| if (updatesEnabledTimerId == -1) |
| updatesEnabledTimerId = q->startTimer(75); |
| } |
| if (codeWidget) |
| codeWidget->invalidateExecutionLineNumbers(); |
| |
| emit q->started(); |
| } |
| |
| QScriptDebuggerResponseHandlerInterface *realHandler = responseHandlers.take(commandId); |
| if (realHandler) |
| realHandler->handleResponse(response, commandId); |
| } |
| |
| /* |
| \reimp |
| |
| Handles a debugger event from the frontend. |
| */ |
| bool QScriptDebuggerPrivate::debuggerEvent(const QScriptDebuggerEvent &event) |
| { |
| Q_Q(QScriptDebugger); |
| switch (event.type()) { |
| case QScriptDebuggerEvent::None: |
| case QScriptDebuggerEvent::UserEvent: |
| case QScriptDebuggerEvent::MaxUserEvent: |
| Q_ASSERT(false); |
| break; |
| |
| case QScriptDebuggerEvent::Trace: |
| if (!debugOutputWidget && widgetFactory) |
| q->setDebugOutputWidget(widgetFactory->createDebugOutputWidget()); |
| if (debugOutputWidget) |
| debugOutputWidget->message(QtDebugMsg, event.message()); |
| return true; // trace doesn't stall execution |
| |
| case QScriptDebuggerEvent::SteppingFinished: { |
| if (!consoleWidget && widgetFactory) |
| q->setConsoleWidget(widgetFactory->createConsoleWidget()); |
| if (consoleWidget) { |
| QString msg = event.message(); |
| if (!msg.isEmpty()) |
| consoleWidget->message(QtDebugMsg, msg); |
| } |
| } break; |
| |
| case QScriptDebuggerEvent::Interrupted: |
| case QScriptDebuggerEvent::LocationReached: |
| break; |
| |
| case QScriptDebuggerEvent::Breakpoint: { |
| int bpId = event.breakpointId(); |
| if (!consoleWidget && widgetFactory) |
| q->setConsoleWidget(widgetFactory->createConsoleWidget()); |
| if (consoleWidget) { |
| consoleWidget->message(QtDebugMsg, |
| QString::fromLatin1("Breakpoint %0 at %1, line %2.") |
| .arg(bpId).arg(event.fileName()) |
| .arg(event.lineNumber())); |
| } |
| if (breakpointsModel->breakpointData(bpId).isSingleShot()) |
| breakpointsModel->removeBreakpoint(bpId); |
| } break; |
| |
| case QScriptDebuggerEvent::Exception: { |
| if (event.hasExceptionHandler()) { |
| // Let the exception be handled like normal. |
| // We may want to add a "Break on all exceptions" option |
| // to be able to customize this behavior. |
| return true; |
| } |
| if (!consoleWidget && widgetFactory) |
| q->setConsoleWidget(widgetFactory->createConsoleWidget()); |
| if (!errorLogWidget && widgetFactory) |
| q->setErrorLogWidget(widgetFactory->createErrorLogWidget()); |
| if (consoleWidget || errorLogWidget) { |
| QString fn = event.fileName(); |
| if (fn.isEmpty()) { |
| if (event.scriptId() != -1) |
| fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId()); |
| else |
| fn = QString::fromLatin1("<native>"); |
| } |
| QString msg = QString::fromLatin1("Uncaught exception at %0:%1: %2").arg(fn) |
| .arg(event.lineNumber()).arg(event.message()); |
| if (consoleWidget) |
| consoleWidget->message(QtCriticalMsg, msg); |
| if (errorLogWidget) |
| errorLogWidget->message(QtCriticalMsg, msg); |
| } |
| } break; |
| |
| case QScriptDebuggerEvent::InlineEvalFinished: { |
| QScriptDebuggerValue result = event.scriptValue(); |
| Q_ASSERT(console != 0); |
| int action = console->evaluateAction(); |
| console->setEvaluateAction(0); |
| switch (action) { |
| case 0: { // eval command |
| if (activeJob) { |
| if (activeJobHibernating) { |
| activeJobHibernating = false; |
| activeJob->evaluateFinished(result); |
| } |
| } else if (consoleWidget) { |
| // ### if the result is an object, need to do a tostring job on it |
| // messageHandler->message(QtDebugMsg, result.toString()); |
| if (result.type() != QScriptDebuggerValue::UndefinedValue) |
| consoleWidget->message(QtDebugMsg, event.message()); |
| } |
| } break; |
| case 1: { // return command |
| QScriptDebuggerCommandSchedulerFrontend frontend(this, this); |
| frontend.scheduleForceReturn(console->currentFrameIndex(), result); |
| } return false; |
| } |
| if (!event.isNestedEvaluate()) { |
| // in the case when evaluate() was called while the |
| // engine was not running, we don't want to enter interactive mode |
| return true; |
| } |
| } break; |
| |
| case QScriptDebuggerEvent::DebuggerInvocationRequest: { |
| if (!consoleWidget && widgetFactory) |
| q->setConsoleWidget(widgetFactory->createConsoleWidget()); |
| if (consoleWidget) { |
| QString fn = event.fileName(); |
| if (fn.isEmpty()) |
| fn = QString::fromLatin1("<anonymous script, id=%0>").arg(event.scriptId()); |
| consoleWidget->message(QtDebugMsg, |
| QString::fromLatin1("Debugger invoked from %1, line %2.") |
| .arg(fn).arg(event.lineNumber())); |
| } |
| } break; |
| |
| case QScriptDebuggerEvent::ForcedReturn: { |
| } break; |
| |
| } |
| |
| if (widgetInPaintEvent) { |
| QString msg = QString::fromLatin1("Suspending evaluation in paintEvent() is not supported; resuming."); |
| if (!consoleWidget && widgetFactory) |
| q->setConsoleWidget(widgetFactory->createConsoleWidget()); |
| if (!errorLogWidget && widgetFactory) |
| q->setErrorLogWidget(widgetFactory->createErrorLogWidget()); |
| if (consoleWidget) |
| consoleWidget->message(QtWarningMsg, msg); |
| if (errorLogWidget) |
| errorLogWidget->message(QtCriticalMsg, msg); |
| return true; |
| } |
| |
| if (activeJobHibernating) { |
| // evaluate() did not finish normally (e.g. due to a breakpoint), |
| // so cancel the job that's waiting for it |
| delete activeJob; |
| activeJob = 0; |
| activeJobHibernating = false; |
| } |
| |
| startInteraction(event.type(), event.scriptId(), event.lineNumber()); |
| return !interactive; |
| } |
| |
| class QScriptToolTipJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| QScriptToolTipJob(const QPoint &pos, int frameIndex, |
| int lineNumber, const QStringList &path, |
| QScriptDebuggerCommandSchedulerInterface *scheduler) |
| : QScriptDebuggerCommandSchedulerJob(scheduler), m_pos(pos), |
| m_frameIndex(frameIndex), m_lineNumber(lineNumber), m_path(path) |
| {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetPropertyExpressionValue(m_frameIndex, m_lineNumber, m_path); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/) |
| { |
| QString tip = response.result().toString(); |
| if (tip.indexOf(QLatin1Char('\n')) != -1) { |
| QStringList lines = tip.split(QLatin1Char('\n')); |
| int lineCount = lines.size(); |
| if (lineCount > 5) { |
| lines = lines.mid(0, 5); |
| lines.append(QString::fromLatin1("(... %0 more lines ...)").arg(lineCount - 5)); |
| } |
| tip = lines.join(QLatin1String("\n")); |
| } |
| #if QT_CONFIG(tooltip) |
| QToolTip::showText(m_pos, tip); |
| #endif |
| finish(); |
| } |
| |
| private: |
| QPoint m_pos; |
| int m_frameIndex; |
| int m_lineNumber; |
| QStringList m_path; |
| }; |
| |
| /* |
| \reimp |
| */ |
| void QScriptDebuggerPrivate::showToolTip(const QPoint &pos, int frameIndex, |
| int lineNumber, const QStringList &path) |
| { |
| if (frameIndex == -1) { |
| if (stackWidget) |
| frameIndex = stackWidget->currentFrameIndex(); |
| else |
| frameIndex = console->currentFrameIndex(); |
| } |
| QScriptDebuggerJob *job = new QScriptToolTipJob(pos, frameIndex, lineNumber, path, this); |
| scheduleJob(job); |
| } |
| |
| /* |
| \reimp |
| */ |
| QScriptCompletionTaskInterface *QScriptDebuggerPrivate::createCompletionTask( |
| const QString &contents, int cursorPosition, int frameIndex, int options) |
| { |
| return new QScriptCompletionTask( |
| contents, cursorPosition, frameIndex, this, this, |
| (options & QScriptCompletionProviderInterface::ConsoleCommandCompletion) ? console : 0); |
| } |
| |
| /* |
| Slot called when a line has been entered in the console widget. |
| */ |
| void QScriptDebuggerPrivate::_q_onLineEntered(const QString &contents) |
| { |
| QScriptDebuggerConsoleCommandJob *commandJob; |
| commandJob = console->consumeInput(contents, consoleWidget, this); |
| if (commandJob != 0) { |
| scheduleJob(commandJob); |
| consoleWidget->setLineContinuationMode(false); |
| } else if (console->hasIncompleteInput()) { |
| consoleWidget->setLineContinuationMode(true); |
| } |
| } |
| |
| /* |
| Slot called when the current index has changed in the stack widget. |
| */ |
| void QScriptDebuggerPrivate::_q_onCurrentFrameChanged(int frameIndex) |
| { |
| loadLocals(frameIndex); |
| selectScriptForFrame(frameIndex); |
| } |
| |
| /* |
| Slot called when the current script has changed in the scripts widget. |
| */ |
| void QScriptDebuggerPrivate::_q_onCurrentScriptChanged(qint64 scriptId) |
| { |
| if (codeWidget && (codeWidget->currentScriptId() != scriptId)) { |
| codeWidget->setCurrentScript(scriptId); |
| QScriptDebuggerCodeViewInterface *view = codeWidget->currentView(); |
| if (view) |
| view->setExecutionLineNumber(-1, /*error=*/false); |
| } |
| } |
| |
| void QScriptDebuggerPrivate::_q_onScriptLocationSelected(int lineNumber) |
| { |
| QScriptDebuggerCodeViewInterface *view = codeWidget->currentView(); |
| if (!view) |
| return; |
| view->gotoLine(lineNumber); |
| } |
| |
| void QScriptDebuggerPrivate::_q_interrupt() |
| { |
| executeConsoleCommand(QString::fromLatin1("interrupt")); |
| } |
| |
| void QScriptDebuggerPrivate::_q_continue() |
| { |
| executeConsoleCommand(QString::fromLatin1("continue")); |
| } |
| |
| void QScriptDebuggerPrivate::_q_stepInto() |
| { |
| executeConsoleCommand(QString::fromLatin1("step")); |
| } |
| |
| void QScriptDebuggerPrivate::_q_stepOver() |
| { |
| executeConsoleCommand(QString::fromLatin1("next")); |
| } |
| |
| void QScriptDebuggerPrivate::_q_stepOut() |
| { |
| executeConsoleCommand(QString::fromLatin1("finish")); |
| } |
| |
| void QScriptDebuggerPrivate::_q_runToCursor() |
| { |
| qint64 scriptId = codeWidget->currentScriptId(); |
| int lineNumber = codeWidget->currentView()->cursorLineNumber(); |
| QScriptDebuggerCommandSchedulerFrontend frontend(this, this); |
| frontend.scheduleRunToLocation(scriptId, lineNumber); |
| } |
| |
| void QScriptDebuggerPrivate::_q_runToNewScript() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(this, this); |
| frontend.scheduleRunToLocation(QString(), -1); |
| } |
| |
| void QScriptDebuggerPrivate::_q_toggleBreakpoint() |
| { |
| Q_ASSERT(codeWidget != 0); |
| QScriptDebuggerCodeViewInterface *view = codeWidget->currentView(); |
| if (!view) |
| return; |
| qint64 scriptId = codeWidget->currentScriptId(); |
| int lineNumber = view->cursorLineNumber(); |
| Q_ASSERT(breakpointsModel != 0); |
| int bpId = breakpointsModel->resolveBreakpoint(scriptId, lineNumber); |
| if (bpId != -1) { |
| breakpointsModel->deleteBreakpoint(bpId); |
| } else { |
| QScriptBreakpointData data(scriptId, lineNumber); |
| if (scriptsModel) |
| data.setFileName(scriptsModel->scriptData(scriptId).fileName()); |
| breakpointsModel->setBreakpoint(data); |
| } |
| } |
| |
| void QScriptDebuggerPrivate::_q_clearDebugOutput() |
| { |
| if (debugOutputWidget) |
| debugOutputWidget->clear(); |
| } |
| |
| void QScriptDebuggerPrivate::_q_clearErrorLog() |
| { |
| if (errorLogWidget) |
| errorLogWidget->clear(); |
| } |
| |
| void QScriptDebuggerPrivate::_q_clearConsole() |
| { |
| if (consoleWidget) |
| consoleWidget->clear(); |
| } |
| |
| void QScriptDebuggerPrivate::executeConsoleCommand(const QString &command) |
| { |
| QString tmp = console->incompleteInput(); |
| console->setIncompleteInput(QString()); |
| QScriptDebuggerJob *job = console->consumeInput(console->commandPrefix() + command, debugOutputWidget, this); |
| console->setIncompleteInput(tmp); |
| if (job != 0) { |
| scheduleJob(job); |
| // once to send the command... |
| QCoreApplication::processEvents(); |
| // ... and once to receive the response |
| QCoreApplication::processEvents(); |
| } |
| } |
| |
| void QScriptDebuggerPrivate::_q_findInScript() |
| { |
| if (!codeFinderWidget && widgetFactory) |
| q_func()->setCodeFinderWidget(widgetFactory->createCodeFinderWidget()); |
| if (codeFinderWidget) { |
| codeFinderWidget->show(); |
| codeFinderWidget->setFocus(Qt::OtherFocusReason); |
| } |
| } |
| |
| void QScriptDebuggerPrivate::_q_findNextInScript() |
| { |
| findCode(codeFinderWidget->text(), codeFinderWidget->findOptions()); |
| } |
| |
| void QScriptDebuggerPrivate::_q_findPreviousInScript() |
| { |
| int options = codeFinderWidget->findOptions(); |
| options |= QTextDocument::FindBackward; |
| findCode(codeFinderWidget->text(), options); |
| } |
| |
| void QScriptDebuggerPrivate::_q_onFindCodeRequest( |
| const QString &exp, int options) |
| { |
| findCode(exp, options); |
| if (findNextInScriptAction) |
| findNextInScriptAction->setEnabled(!exp.isEmpty()); |
| if (findPreviousInScriptAction) |
| findPreviousInScriptAction->setEnabled(!exp.isEmpty()); |
| } |
| |
| void QScriptDebuggerPrivate::findCode(const QString &exp, int options) |
| { |
| QScriptDebuggerCodeViewInterface *view = codeWidget->currentView(); |
| if (!view) |
| return; |
| int result = view->find(exp, options); |
| codeFinderWidget->setOK(((result & 0x1) != 0) || exp.isEmpty()); |
| codeFinderWidget->setWrapped((result & 0x2) != 0); |
| } |
| |
| void QScriptDebuggerPrivate::_q_goToLine() |
| { |
| QScriptDebuggerCodeViewInterface *view = codeWidget->currentView(); |
| if (!view) |
| return; |
| #ifndef QT_NO_INPUTDIALOG |
| bool ok = false; |
| int lineNumber = QInputDialog::getInt(0, QScriptDebugger::tr("Go to Line"), |
| QScriptDebugger::tr("Line:"), |
| view->cursorLineNumber(), |
| 1, INT_MAX, 1, &ok); |
| if (ok) |
| view->gotoLine(lineNumber); |
| #endif |
| } |
| |
| class QScriptDebuggerShowLineJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| QScriptDebuggerShowLineJob(qint64 scriptId, int lineNumber, |
| QScriptMessageHandlerInterface *messageHandler, |
| QScriptDebuggerCommandSchedulerInterface *scheduler) |
| : QScriptDebuggerCommandSchedulerJob(scheduler), |
| m_scriptId(scriptId), m_lineNumber(lineNumber), |
| m_messageHandler(messageHandler) {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetScriptData(m_scriptId); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/) |
| { |
| QScriptScriptData data = response.resultAsScriptData(); |
| QString line = data.lines(m_lineNumber, 1).value(0); |
| m_messageHandler->message(QtDebugMsg, QString::fromLatin1("%0\t%1") |
| .arg(m_lineNumber).arg(line)); |
| finish(); |
| } |
| |
| private: |
| qint64 m_scriptId; |
| int m_lineNumber; |
| QScriptMessageHandlerInterface *m_messageHandler; |
| }; |
| |
| namespace { |
| |
| class SyncStackJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| SyncStackJob(QScriptDebuggerPrivate *debugger) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger), m_index(0) {} |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetContextInfo(m_index); // ### getContextInfos() |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| if (response.error() != QScriptDebuggerResponse::InvalidContextIndex) { |
| m_infos.append(response.resultAsContextInfo()); |
| frontend.scheduleGetContextInfo(++m_index); |
| } else { |
| m_debugger->stackModel->setContextInfos(m_infos); |
| if (m_debugger->stackWidget->currentFrameIndex() == -1) |
| m_debugger->stackWidget->setCurrentFrameIndex(0); |
| m_debugger->stackWidget->setUpdatesEnabled(true); |
| m_debugger->stackWidget->setEnabled(true); |
| finish(); |
| } |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| int m_index; |
| QList<QScriptContextInfo> m_infos; |
| }; |
| |
| class SyncScriptsJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| SyncScriptsJob(QScriptDebuggerPrivate *debugger) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger), m_index(-1) {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleScriptsCheckpoint(); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| if (m_index == -1) { |
| QScriptScriptsDelta delta; |
| delta = qvariant_cast<QScriptScriptsDelta>(response.result()); |
| |
| const QList<qint64> &removed = delta.second; |
| for (int i = 0; i < removed.size(); ++i) |
| m_debugger->scriptsModel->removeScript(removed.at(i)); |
| |
| m_added = delta.first; |
| if (!m_added.isEmpty()) { |
| frontend.scheduleGetScriptData(m_added.at(++m_index)); |
| } else { |
| m_debugger->scriptsModel->commit(); |
| finish(); |
| } |
| } else { |
| QScriptScriptData data = response.resultAsScriptData(); |
| qint64 scriptId = m_added.at(m_index); |
| m_debugger->scriptsModel->addScript(scriptId, data); |
| |
| // ### could be slow, might want to do this in a separate thread |
| // Q_ASSERT_X(false, Q_FUNC_INFO, "implement me"); |
| QString xml; // = qt_scriptToXml(data.contents(), data.baseLineNumber()); |
| QScriptXmlParser::Result extraInfo = QScriptXmlParser::parse(xml); |
| m_debugger->scriptsModel->addExtraScriptInfo( |
| scriptId, extraInfo.functionsInfo, extraInfo.executableLineNumbers); |
| |
| if (++m_index < m_added.size()) |
| frontend.scheduleGetScriptData(m_added.at(m_index)); |
| else { |
| m_debugger->scriptsModel->commit(); |
| finish(); |
| } |
| } |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| int m_index; |
| QList<qint64> m_added; |
| }; |
| |
| class SyncBreakpointsJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| SyncBreakpointsJob(QScriptDebuggerPrivate *debugger) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger) {} |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetBreakpoints(); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| QScriptBreakpointMap breakpoints = response.resultAsBreakpoints(); |
| QScriptBreakpointMap::const_iterator it; |
| for (it = breakpoints.constBegin(); it != breakpoints.constEnd(); ++it) { |
| int id = it.key(); |
| QScriptBreakpointData newData = it.value(); |
| QScriptBreakpointData existingData = m_debugger->breakpointsModel->breakpointData(id); |
| if (existingData.isValid() && (existingData != newData)) |
| m_debugger->breakpointsModel->modifyBreakpoint(id, newData); |
| } |
| finish(); |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| QList<QScriptContextInfo> m_infos; |
| }; |
| |
| class SyncLocalsJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| SyncLocalsJob(QScriptDebuggerPrivate *debugger) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger) {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleContextsCheckpoint(); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| QScriptContextsDelta delta = qvariant_cast<QScriptContextsDelta>(response.result()); |
| for (int i = 0; i < delta.first.size(); ++i) { |
| QScriptDebuggerLocalsModel *model = m_debugger->localsModels.take(delta.first.at(i)); |
| delete model; |
| } |
| finish(); |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| }; |
| |
| class LoadLocalsJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| LoadLocalsJob(QScriptDebuggerPrivate *debugger, int frameIndex) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger), m_frameIndex(frameIndex) {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetContextId(m_frameIndex); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| qint64 contextId = response.resultAsLongLong(); |
| QScriptDebuggerLocalsModel *model = m_debugger->localsModels.value(contextId); |
| if (model) { |
| model->sync(m_frameIndex); |
| } else { |
| model = m_debugger->createLocalsModel(); |
| m_debugger->localsModels.insert(contextId, model); |
| model->init(m_frameIndex); |
| } |
| if (m_debugger->localsWidget) { |
| if (m_debugger->localsWidget->localsModel() != model) // ### bug in qtreeview |
| m_debugger->localsWidget->setLocalsModel(model); |
| m_debugger->localsWidget->setUpdatesEnabled(true); |
| m_debugger->localsWidget->setEnabled(true); |
| } |
| finish(); |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| int m_frameIndex; |
| }; |
| |
| class EmitStoppedSignalJob : public QScriptDebuggerJob |
| { |
| public: |
| EmitStoppedSignalJob(QScriptDebuggerPrivate *debugger) |
| : m_debugger(debugger) {} |
| |
| void start() |
| { |
| m_debugger->emitStoppedSignal(); |
| finish(); |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| }; |
| |
| } // namespace |
| |
| void QScriptDebuggerPrivate::startInteraction(QScriptDebuggerEvent::Type type, |
| qint64 scriptId, int lineNumber) |
| { |
| Q_Q(QScriptDebugger); |
| if (type != QScriptDebuggerEvent::InlineEvalFinished) { |
| if (stackWidget) |
| stackWidget->setCurrentFrameIndex(0); |
| console->setCurrentFrameIndex(0); |
| console->setCurrentScriptId(scriptId); |
| console->setCurrentLineNumber(lineNumber); |
| } |
| |
| if ((scriptId != -1) && consoleWidget) { |
| QScriptDebuggerJob *job = new QScriptDebuggerShowLineJob(scriptId, lineNumber, consoleWidget, this); |
| scheduleJob(job); |
| } |
| |
| sync(); |
| |
| if (!interactive) { |
| interactive = true; |
| if (updatesEnabledTimerId != -1) { |
| q->killTimer(updatesEnabledTimerId); |
| updatesEnabledTimerId = -1; |
| } |
| console->bumpSessionId(); |
| scheduleJob(new EmitStoppedSignalJob(this)); |
| } |
| |
| if (consoleWidget) |
| consoleWidget->activateWindow(); |
| else if (codeWidget) |
| codeWidget->activateWindow(); |
| |
| if (continueAction) |
| continueAction->setEnabled(true); |
| if (stepIntoAction) |
| stepIntoAction->setEnabled(true); |
| if (stepOverAction) |
| stepOverAction->setEnabled(true); |
| if (stepOutAction) |
| stepOutAction->setEnabled(true); |
| if (runToCursorAction) |
| runToCursorAction->setEnabled(true); |
| if (runToNewScriptAction) |
| runToNewScriptAction->setEnabled(true); |
| if (interruptAction) |
| interruptAction->setEnabled(false); |
| |
| bool hasScript = (codeWidget != 0); |
| if (findInScriptAction) |
| findInScriptAction->setEnabled(hasScript); |
| if (toggleBreakpointAction) |
| toggleBreakpointAction->setEnabled(hasScript); |
| if (goToLineAction) |
| goToLineAction->setEnabled(hasScript); |
| } |
| |
| void QScriptDebuggerPrivate::sync() |
| { |
| if (localsWidget) { |
| QScriptDebuggerJob *job = new SyncLocalsJob(this); |
| scheduleJob(job); |
| } |
| if (scriptsModel) { |
| QScriptDebuggerJob *job = new SyncScriptsJob(this); |
| scheduleJob(job); |
| } |
| if (stackModel) { |
| QScriptDebuggerJob *job = new SyncStackJob(this); |
| scheduleJob(job); |
| } |
| if (breakpointsModel) { |
| // need to sync because the ignore-count could have changed |
| QScriptDebuggerJob *job = new SyncBreakpointsJob(this); |
| scheduleJob(job); |
| } |
| |
| if (stackWidget && (stackWidget->currentFrameIndex() != -1)) { |
| int index = stackWidget->currentFrameIndex(); |
| loadLocals(index); |
| selectScriptForFrame(index); |
| } else if (codeWidget && (console->currentFrameIndex() != -1)) { |
| selectScriptForFrame(console->currentFrameIndex()); |
| } |
| } |
| |
| void QScriptDebuggerPrivate::loadLocals(int frameIndex) |
| { |
| LoadLocalsJob *job = new LoadLocalsJob(this, frameIndex); |
| scheduleJob(job); |
| } |
| |
| QScriptDebuggerLocalsModel *QScriptDebuggerPrivate::createLocalsModel() |
| { |
| return new QScriptDebuggerLocalsModel(this, this, q_func()); |
| } |
| |
| namespace { |
| |
| class ShowFrameCodeJob : public QScriptDebuggerCommandSchedulerJob |
| { |
| public: |
| ShowFrameCodeJob(QScriptDebuggerPrivate *debugger, int frameIndex) |
| : QScriptDebuggerCommandSchedulerJob(debugger), |
| m_debugger(debugger), m_frameIndex(frameIndex) {} |
| |
| void start() |
| { |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetContextInfo(m_frameIndex); |
| } |
| void handleResponse(const QScriptDebuggerResponse &response, |
| int) |
| { |
| if (m_info.isNull()) { |
| m_info = response.resultAsContextInfo(); |
| QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this); |
| frontend.scheduleGetContextState(m_frameIndex); |
| } else { |
| int contextState = response.resultAsInt(); |
| bool error = (contextState == QScriptContext::ExceptionState); |
| if (m_debugger->scriptsWidget) { |
| m_debugger->scriptsWidget->setCurrentScript(m_info.scriptId()); |
| } |
| if (m_debugger->codeWidget) { |
| m_debugger->codeWidget->setCurrentScript(m_info.scriptId()); |
| QScriptDebuggerCodeViewInterface *view = m_debugger->codeWidget->currentView(); |
| if (view) |
| view->setExecutionLineNumber(m_info.lineNumber(), error); |
| } |
| finish(); |
| } |
| } |
| |
| private: |
| QScriptDebuggerPrivate *m_debugger; |
| int m_frameIndex; |
| QScriptContextInfo m_info; |
| }; |
| |
| } // namespace |
| |
| void QScriptDebuggerPrivate::selectScriptForFrame(int frameIndex) |
| { |
| QScriptDebuggerJob *job = new ShowFrameCodeJob(this, frameIndex); |
| scheduleJob(job); |
| } |
| |
| void QScriptDebuggerPrivate::emitStoppedSignal() |
| { |
| emit q_func()->stopped(); |
| } |
| |
| /*! |
| Constructs a new QScriptDebugger object. |
| */ |
| QScriptDebugger::QScriptDebugger(QObject *parent) |
| : QObject(*new QScriptDebuggerPrivate, parent) |
| { |
| ++scriptDebuggerCount; |
| } |
| |
| /*! |
| Destroys this QScriptDebugger. |
| */ |
| QScriptDebugger::~QScriptDebugger() |
| { |
| --scriptDebuggerCount; |
| if ((scriptDebuggerCount == 0) && eventCallbackRegistered) { |
| eventCallbackRegistered = false; |
| QInternal::unregisterCallback(QInternal::EventNotifyCallback, |
| scriptDebuggerEventCallback); |
| } |
| } |
| |
| /*! |
| \internal |
| */ |
| QScriptDebugger::QScriptDebugger(QScriptDebuggerPrivate &dd, QObject *parent) |
| : QObject(dd, parent) |
| { |
| } |
| |
| QScriptDebuggerFrontend *QScriptDebugger::frontend() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->frontend; |
| } |
| |
| void QScriptDebugger::setFrontend(QScriptDebuggerFrontend *frontend) |
| { |
| Q_D(QScriptDebugger); |
| if (d->frontend) |
| d->frontend->setEventHandler(0); |
| d->frontend = frontend; |
| if (frontend) { |
| frontend->setEventHandler(d); |
| if (!eventCallbackRegistered) { |
| eventCallbackRegistered = true; |
| QInternal::registerCallback(QInternal::EventNotifyCallback, |
| scriptDebuggerEventCallback); |
| } |
| } |
| } |
| |
| QAction *QScriptDebugger::action(DebuggerAction action, QObject *parent) |
| { |
| switch (action) { |
| case InterruptAction: |
| return interruptAction(parent); |
| case ContinueAction: |
| return continueAction(parent); |
| case StepIntoAction: |
| return stepIntoAction(parent); |
| case StepOverAction: |
| return stepOverAction(parent); |
| case StepOutAction: |
| return stepOutAction(parent); |
| case RunToCursorAction: |
| return runToCursorAction(parent); |
| case RunToNewScriptAction: |
| return runToNewScriptAction(parent); |
| case ToggleBreakpointAction: |
| return toggleBreakpointAction(parent); |
| case ClearDebugOutputAction: |
| return clearDebugOutputAction(parent); |
| case ClearErrorLogAction: |
| return clearErrorLogAction(parent); |
| case ClearConsoleAction: |
| return clearConsoleAction(parent); |
| case FindInScriptAction: |
| return findInScriptAction(parent); |
| case FindNextInScriptAction: |
| return findNextInScriptAction(parent); |
| case FindPreviousInScriptAction: |
| return findPreviousInScriptAction(parent); |
| case GoToLineAction: |
| return goToLineAction(parent); |
| } |
| return 0; |
| } |
| |
| QWidget *QScriptDebugger::widget(DebuggerWidget widget) |
| { |
| switch (widget) { |
| case ConsoleWidget: { |
| QScriptDebuggerConsoleWidgetInterface *w = consoleWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createConsoleWidget(); |
| setConsoleWidget(w); |
| } |
| return w; |
| } |
| case StackWidget: { |
| QScriptDebuggerStackWidgetInterface *w = stackWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createStackWidget(); |
| setStackWidget(w); |
| } |
| return w; |
| } |
| case ScriptsWidget: { |
| QScriptDebuggerScriptsWidgetInterface *w = scriptsWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createScriptsWidget(); |
| setScriptsWidget(w); |
| } |
| return w; |
| } |
| case LocalsWidget: { |
| QScriptDebuggerLocalsWidgetInterface *w = localsWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createLocalsWidget(); |
| setLocalsWidget(w); |
| } |
| return w; |
| } |
| case CodeWidget: { |
| QScriptDebuggerCodeWidgetInterface *w = codeWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createCodeWidget(); |
| setCodeWidget(w); |
| } |
| return w; |
| } |
| case CodeFinderWidget: { |
| QScriptDebuggerCodeFinderWidgetInterface *w = codeFinderWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createCodeFinderWidget(); |
| setCodeFinderWidget(w); |
| } |
| return w; |
| } |
| case BreakpointsWidget: { |
| QScriptBreakpointsWidgetInterface *w = breakpointsWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createBreakpointsWidget(); |
| setBreakpointsWidget(w); |
| } |
| return w; |
| } |
| case DebugOutputWidget: { |
| QScriptDebugOutputWidgetInterface *w = debugOutputWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createDebugOutputWidget(); |
| setDebugOutputWidget(w); |
| } |
| return w; |
| } |
| case ErrorLogWidget: { |
| QScriptErrorLogWidgetInterface *w = errorLogWidget(); |
| if (!w && widgetFactory()) { |
| w = widgetFactory()->createErrorLogWidget(); |
| setErrorLogWidget(w); |
| } |
| return w; |
| } |
| } |
| return 0; |
| } |
| |
| QScriptDebuggerConsoleWidgetInterface *QScriptDebugger::consoleWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->consoleWidget; |
| } |
| |
| void QScriptDebugger::setConsoleWidget(QScriptDebuggerConsoleWidgetInterface *consoleWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->consoleWidget) { |
| QObject::disconnect(d->consoleWidget, 0, this, 0); |
| } |
| d->consoleWidget = consoleWidget; |
| if (consoleWidget) { |
| consoleWidget->setCommandHistorian(d->console); |
| consoleWidget->setCompletionProvider(d); |
| QObject::connect(consoleWidget, SIGNAL(lineEntered(QString)), |
| this, SLOT(_q_onLineEntered(QString))); |
| |
| d->console->showDebuggerInfoMessage(consoleWidget); |
| } |
| } |
| |
| QScriptDebuggerStackWidgetInterface *QScriptDebugger::stackWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->stackWidget; |
| } |
| |
| void QScriptDebugger::setStackWidget(QScriptDebuggerStackWidgetInterface *stackWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->stackWidget) { |
| QObject::disconnect(d->stackWidget, 0, this, 0); |
| } |
| d->stackWidget = stackWidget; |
| if (stackWidget) { |
| if (!d->stackModel) { |
| d->stackModel = new QScriptDebuggerStackModel(this); |
| if (d->interactive) |
| d->scheduleJob(new SyncStackJob(d)); |
| } |
| stackWidget->setStackModel(d->stackModel); |
| QObject::connect(stackWidget, SIGNAL(currentFrameChanged(int)), |
| this, SLOT(_q_onCurrentFrameChanged(int))); |
| } |
| } |
| |
| QScriptDebuggerScriptsWidgetInterface *QScriptDebugger::scriptsWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->scriptsWidget; |
| } |
| |
| void QScriptDebugger::setScriptsWidget(QScriptDebuggerScriptsWidgetInterface *scriptsWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->scriptsWidget) { |
| QObject::disconnect(d->scriptsWidget, 0, this, 0); |
| } |
| d->scriptsWidget = scriptsWidget; |
| if (scriptsWidget) { |
| if (!d->scriptsModel) { |
| d->scriptsModel = new QScriptDebuggerScriptsModel(this); |
| if (d->interactive) |
| d->scheduleJob(new SyncScriptsJob(d)); |
| } |
| scriptsWidget->setScriptsModel(d->scriptsModel); |
| QObject::connect(scriptsWidget, SIGNAL(currentScriptChanged(qint64)), |
| this, SLOT(_q_onCurrentScriptChanged(qint64))); |
| QObject::connect(d->scriptsWidget, SIGNAL(scriptLocationSelected(int)), |
| this, SLOT(_q_onScriptLocationSelected(int))); |
| } |
| } |
| |
| QScriptDebuggerLocalsWidgetInterface *QScriptDebugger::localsWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->localsWidget; |
| } |
| |
| void QScriptDebugger::setLocalsWidget(QScriptDebuggerLocalsWidgetInterface *localsWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->localsWidget) { |
| // ### d->localsWidget->setLocalsModel(0); |
| } |
| localsWidget->setCompletionProvider(d); |
| d->localsWidget = localsWidget; |
| } |
| |
| QScriptDebuggerCodeWidgetInterface *QScriptDebugger::codeWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->codeWidget; |
| } |
| |
| void QScriptDebugger::setCodeWidget(QScriptDebuggerCodeWidgetInterface *codeWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->codeWidget) { |
| d->codeWidget->removeEventFilter(this); |
| } |
| d->codeWidget = codeWidget; |
| if (codeWidget) { |
| if (!d->scriptsModel) { |
| d->scriptsModel = new QScriptDebuggerScriptsModel(this); |
| if (d->interactive) |
| d->scheduleJob(new SyncScriptsJob(d)); |
| } |
| codeWidget->setScriptsModel(d->scriptsModel); |
| if (!d->breakpointsModel) { |
| d->breakpointsModel = new QScriptBreakpointsModel(d, d, this); |
| if (d->interactive) |
| d->scheduleJob(new SyncBreakpointsJob(d)); |
| } |
| codeWidget->setBreakpointsModel(d->breakpointsModel); |
| codeWidget->setToolTipProvider(d); |
| codeWidget->installEventFilter(this); |
| } |
| bool hasScript = (codeWidget != 0) && (codeWidget->currentView() != 0); |
| if (d->findInScriptAction) |
| d->findInScriptAction->setEnabled(hasScript && (d->codeFinderWidget != 0)); |
| if (d->goToLineAction) |
| d->goToLineAction->setEnabled(hasScript); |
| if (d->toggleBreakpointAction) |
| d->toggleBreakpointAction->setEnabled(hasScript); |
| } |
| |
| QScriptDebuggerCodeFinderWidgetInterface *QScriptDebugger::codeFinderWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->codeFinderWidget; |
| } |
| |
| void QScriptDebugger::setCodeFinderWidget(QScriptDebuggerCodeFinderWidgetInterface *codeFinderWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->codeFinderWidget) { |
| QObject::disconnect(d->codeFinderWidget, 0, this, 0); |
| } |
| d->codeFinderWidget = codeFinderWidget; |
| if (codeFinderWidget) { |
| QObject::connect(codeFinderWidget, SIGNAL(findRequest(QString,int)), |
| this, SLOT(_q_onFindCodeRequest(QString,int))); |
| } |
| if (d->findInScriptAction) { |
| d->findInScriptAction->setEnabled( |
| (codeFinderWidget != 0) |
| && (d->codeWidget != 0) |
| && (d->codeWidget->currentView() != 0)); |
| } |
| } |
| |
| QScriptDebugOutputWidgetInterface *QScriptDebugger::debugOutputWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->debugOutputWidget; |
| } |
| |
| void QScriptDebugger::setDebugOutputWidget(QScriptDebugOutputWidgetInterface *debugOutputWidget) |
| { |
| Q_D(QScriptDebugger); |
| d->debugOutputWidget = debugOutputWidget; |
| } |
| |
| QScriptBreakpointsWidgetInterface *QScriptDebugger::breakpointsWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->breakpointsWidget; |
| } |
| |
| void QScriptDebugger::setBreakpointsWidget(QScriptBreakpointsWidgetInterface *breakpointsWidget) |
| { |
| Q_D(QScriptDebugger); |
| if (d->breakpointsWidget) { |
| // ### invalidate |
| } |
| d->breakpointsWidget = breakpointsWidget; |
| if (breakpointsWidget) { |
| if (!d->breakpointsModel) { |
| d->breakpointsModel = new QScriptBreakpointsModel(d, d, this); |
| if (d->interactive) |
| d->scheduleJob(new SyncBreakpointsJob(d)); |
| } |
| d->breakpointsWidget->setBreakpointsModel(d->breakpointsModel); |
| d->breakpointsWidget->setScriptsModel(d->scriptsModel); |
| } |
| } |
| |
| QScriptErrorLogWidgetInterface *QScriptDebugger::errorLogWidget() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->errorLogWidget; |
| } |
| |
| void QScriptDebugger::setErrorLogWidget(QScriptErrorLogWidgetInterface *errorLogWidget) |
| { |
| Q_D(QScriptDebugger); |
| d->errorLogWidget = errorLogWidget; |
| } |
| |
| QScriptDebuggerWidgetFactoryInterface *QScriptDebugger::widgetFactory() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->widgetFactory; |
| } |
| |
| void QScriptDebugger::setWidgetFactory(QScriptDebuggerWidgetFactoryInterface *factory) |
| { |
| Q_D(QScriptDebugger); |
| d->widgetFactory = factory; |
| } |
| |
| QAction *QScriptDebugger::interruptAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->interruptAction) { |
| QIcon interruptIcon; |
| interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("interrupt.png")), QIcon::Normal); |
| interruptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_interrupt.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->interruptAction = new QAction(interruptIcon, QScriptDebugger::tr("Interrupt"), parent); |
| d->interruptAction->setEnabled(!d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->interruptAction->setShortcut(QScriptDebugger::tr("Shift+F5")); |
| #endif |
| QObject::connect(d->interruptAction, SIGNAL(triggered()), |
| that, SLOT(_q_interrupt())); |
| } |
| return d->interruptAction; |
| } |
| |
| QAction *QScriptDebugger::continueAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->continueAction) { |
| QIcon continueIcon; |
| continueIcon.addPixmap(d->pixmap(QString::fromLatin1("play.png")), QIcon::Normal); |
| continueIcon.addPixmap(d->pixmap(QString::fromLatin1("d_play.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->continueAction = new QAction(continueIcon, QScriptDebugger::tr("Continue"), parent); |
| d->continueAction->setEnabled(d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->continueAction->setShortcut(QScriptDebugger::tr("F5")); |
| #endif |
| QObject::connect(d->continueAction, SIGNAL(triggered()), |
| that, SLOT(_q_continue())); |
| } |
| return d->continueAction; |
| } |
| |
| QAction *QScriptDebugger::stepIntoAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->stepIntoAction) { |
| QIcon stepIntoIcon; |
| stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("stepinto.png")), QIcon::Normal); |
| stepIntoIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepinto.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->stepIntoAction = new QAction(stepIntoIcon, QScriptDebugger::tr("Step Into"), parent); |
| d->stepIntoAction->setEnabled(d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->stepIntoAction->setShortcut(QScriptDebugger::tr("F11")); |
| #endif |
| QObject::connect(d->stepIntoAction, SIGNAL(triggered()), |
| that, SLOT(_q_stepInto())); |
| } |
| return d->stepIntoAction; |
| } |
| |
| QAction *QScriptDebugger::stepOverAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->stepOverAction) { |
| QIcon stepOverIcon; |
| stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("stepover.png")), QIcon::Normal); |
| stepOverIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepover.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->stepOverAction = new QAction(stepOverIcon, QScriptDebugger::tr("Step Over"), parent); |
| d->stepOverAction->setEnabled(d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->stepOverAction->setShortcut(QScriptDebugger::tr("F10")); |
| #endif |
| QObject::connect(d->stepOverAction, SIGNAL(triggered()), |
| that, SLOT(_q_stepOver())); |
| } |
| return d->stepOverAction; |
| } |
| |
| QAction *QScriptDebugger::stepOutAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->stepOutAction) { |
| QIcon stepOutIcon; |
| stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("stepout.png")), QIcon::Normal); |
| stepOutIcon.addPixmap(d->pixmap(QString::fromLatin1("d_stepout.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->stepOutAction = new QAction(stepOutIcon, QScriptDebugger::tr("Step Out"), parent); |
| d->stepOutAction->setEnabled(d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->stepOutAction->setShortcut(QScriptDebugger::tr("Shift+F11")); |
| #endif |
| QObject::connect(d->stepOutAction, SIGNAL(triggered()), |
| that, SLOT(_q_stepOut())); |
| } |
| return d->stepOutAction; |
| } |
| |
| QAction *QScriptDebugger::runToCursorAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->runToCursorAction) { |
| QIcon runToCursorIcon; |
| runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("runtocursor.png")), QIcon::Normal); |
| runToCursorIcon.addPixmap(d->pixmap(QString::fromLatin1("d_runtocursor.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->runToCursorAction = new QAction(runToCursorIcon, QScriptDebugger::tr("Run to Cursor"), parent); |
| d->runToCursorAction->setEnabled(d->interactive); |
| #ifndef QT_NO_SHORTCUT |
| d->runToCursorAction->setShortcut(QScriptDebugger::tr("Ctrl+F10")); |
| #endif |
| QObject::connect(d->runToCursorAction, SIGNAL(triggered()), |
| that, SLOT(_q_runToCursor())); |
| } |
| return d->runToCursorAction; |
| } |
| |
| QAction *QScriptDebugger::runToNewScriptAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->runToNewScriptAction) { |
| QIcon runToNewScriptIcon; |
| runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("runtonewscript.png")), QIcon::Normal); |
| runToNewScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("d_breakonscriptload.png")), QIcon::Disabled); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->runToNewScriptAction = new QAction(runToNewScriptIcon, |
| QScriptDebugger::tr("Run to New Script"), parent); |
| d->runToNewScriptAction->setEnabled(d->interactive); |
| QObject::connect(d->runToNewScriptAction, SIGNAL(triggered()), |
| that, SLOT(_q_runToNewScript())); |
| } |
| return d->runToNewScriptAction; |
| } |
| |
| QAction *QScriptDebugger::toggleBreakpointAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->toggleBreakpointAction) { |
| QIcon toggleBreakpointIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->toggleBreakpointAction = new QAction(toggleBreakpointIcon, |
| QScriptDebugger::tr("Toggle Breakpoint"), parent); |
| #ifndef QT_NO_SHORTCUT |
| d->toggleBreakpointAction->setShortcut(QScriptDebugger::tr("F9")); |
| #endif |
| d->toggleBreakpointAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0)); |
| QObject::connect(d->toggleBreakpointAction, SIGNAL(triggered()), |
| that, SLOT(_q_toggleBreakpoint())); |
| } |
| return d->toggleBreakpointAction; |
| } |
| |
| QAction *QScriptDebugger::clearDebugOutputAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->clearDebugOutputAction) { |
| QIcon clearDebugOutputIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->clearDebugOutputAction = new QAction(clearDebugOutputIcon, QScriptDebugger::tr("Clear Debug Output"), parent); |
| QObject::connect(d->clearDebugOutputAction, SIGNAL(triggered()), |
| that, SLOT(_q_clearDebugOutput())); |
| } |
| return d->clearDebugOutputAction; |
| } |
| |
| QAction *QScriptDebugger::clearErrorLogAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->clearErrorLogAction) { |
| QIcon clearErrorLogIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->clearErrorLogAction = new QAction(clearErrorLogIcon, QScriptDebugger::tr("Clear Error Log"), parent); |
| QObject::connect(d->clearErrorLogAction, SIGNAL(triggered()), |
| that, SLOT(_q_clearErrorLog())); |
| } |
| return d->clearErrorLogAction; |
| } |
| |
| QAction *QScriptDebugger::clearConsoleAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->clearConsoleAction) { |
| QIcon clearConsoleIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->clearConsoleAction = new QAction(clearConsoleIcon, QScriptDebugger::tr("Clear Console"), parent); |
| QObject::connect(d->clearConsoleAction, SIGNAL(triggered()), |
| that, SLOT(_q_clearConsole())); |
| } |
| return d->clearConsoleAction; |
| } |
| |
| QAction *QScriptDebugger::findInScriptAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->findInScriptAction) { |
| QIcon findInScriptIcon; |
| findInScriptIcon.addPixmap(d->pixmap(QString::fromLatin1("find.png")), QIcon::Normal); |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->findInScriptAction = new QAction(findInScriptIcon, QScriptDebugger::tr("&Find in Script..."), parent); |
| #ifndef QT_NO_SHORTCUT |
| d->findInScriptAction->setShortcut(QScriptDebugger::tr("Ctrl+F")); |
| #endif |
| d->findInScriptAction->setEnabled( |
| (d->codeFinderWidget != 0) |
| && (d->codeWidget != 0) |
| && (d->codeWidget->currentView() != 0)); |
| QObject::connect(d->findInScriptAction, SIGNAL(triggered()), |
| that, SLOT(_q_findInScript())); |
| } |
| return d->findInScriptAction; |
| } |
| |
| QAction *QScriptDebugger::findNextInScriptAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->findNextInScriptAction) { |
| QIcon findNextInScriptIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->findNextInScriptAction = new QAction(findNextInScriptIcon, QScriptDebugger::tr("Find &Next"), parent); |
| d->findNextInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty()); |
| #ifndef QT_NO_SHORTCUT |
| d->findNextInScriptAction->setShortcut(QScriptDebugger::tr("F3")); |
| #endif |
| QObject::connect(d->findNextInScriptAction, SIGNAL(triggered()), |
| that, SLOT(_q_findNextInScript())); |
| } |
| return d->findNextInScriptAction; |
| } |
| |
| QAction *QScriptDebugger::findPreviousInScriptAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->findPreviousInScriptAction) { |
| QIcon findPreviousInScriptIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->findPreviousInScriptAction = new QAction(findPreviousInScriptIcon, QScriptDebugger::tr("Find &Previous"), parent); |
| d->findPreviousInScriptAction->setEnabled(d->codeFinderWidget && !d->codeFinderWidget->text().isEmpty()); |
| #ifndef QT_NO_SHORTCUT |
| d->findPreviousInScriptAction->setShortcut(QScriptDebugger::tr("Shift+F3")); |
| #endif |
| QObject::connect(d->findPreviousInScriptAction, SIGNAL(triggered()), |
| that, SLOT(_q_findPreviousInScript())); |
| } |
| return d->findPreviousInScriptAction; |
| } |
| |
| QAction *QScriptDebugger::goToLineAction(QObject *parent) const |
| { |
| Q_D(const QScriptDebugger); |
| if (!d->goToLineAction) { |
| QIcon goToLineIcon; |
| QScriptDebugger *that = const_cast<QScriptDebugger*>(this); |
| that->d_func()->goToLineAction = new QAction(goToLineIcon, QScriptDebugger::tr("Go to Line"), parent); |
| #ifndef QT_NO_SHORTCUT |
| d->goToLineAction->setShortcut(QScriptDebugger::tr("Ctrl+G")); |
| #endif |
| d->goToLineAction->setEnabled((d->codeWidget != 0) && (d->codeWidget->currentView() != 0)); |
| QObject::connect(d->goToLineAction, SIGNAL(triggered()), |
| that, SLOT(_q_goToLine())); |
| } |
| return d->goToLineAction; |
| } |
| |
| QMenu *QScriptDebugger::createStandardMenu(QWidget *widgetParent, QObject *actionParent) |
| { |
| QMenu *menu = new QMenu(widgetParent); |
| menu->setTitle(QScriptDebugger::tr("Debug")); |
| menu->addAction(action(ContinueAction, actionParent)); |
| menu->addAction(action(InterruptAction, actionParent)); |
| menu->addAction(action(StepIntoAction, actionParent)); |
| menu->addAction(action(StepOverAction, actionParent)); |
| menu->addAction(action(StepOutAction, actionParent)); |
| menu->addAction(action(RunToCursorAction, actionParent)); |
| menu->addAction(action(RunToNewScriptAction, actionParent)); |
| |
| menu->addSeparator(); |
| menu->addAction(action(ToggleBreakpointAction, actionParent)); |
| |
| menu->addSeparator(); |
| menu->addAction(action(ClearDebugOutputAction, actionParent)); |
| menu->addAction(action(ClearErrorLogAction, actionParent)); |
| menu->addAction(action(ClearConsoleAction, actionParent)); |
| |
| return menu; |
| } |
| |
| #ifndef QT_NO_TOOLBAR |
| QToolBar *QScriptDebugger::createStandardToolBar(QWidget *widgetParent, QObject *actionParent) |
| { |
| QToolBar *tb = new QToolBar(widgetParent); |
| tb->setObjectName(QLatin1String("qtscriptdebugger_standardToolBar")); |
| tb->addAction(action(ContinueAction, actionParent)); |
| tb->addAction(action(InterruptAction, actionParent)); |
| tb->addAction(action(StepIntoAction, actionParent)); |
| tb->addAction(action(StepOverAction, actionParent)); |
| tb->addAction(action(StepOutAction, actionParent)); |
| tb->addAction(action(RunToCursorAction, actionParent)); |
| tb->addAction(action(RunToNewScriptAction, actionParent)); |
| tb->addSeparator(); |
| tb->addAction(action(FindInScriptAction, actionParent)); |
| return tb; |
| } |
| #endif |
| |
| bool QScriptDebugger::isInteractive() const |
| { |
| Q_D(const QScriptDebugger); |
| return d->interactive; |
| } |
| |
| /*! |
| \reimp |
| */ |
| bool QScriptDebugger::eventFilter(QObject *watched, QEvent *e) |
| { |
| Q_D(QScriptDebugger); |
| if (watched == d->codeWidget) { |
| if (e->type() == QEvent::KeyPress) { |
| d->_q_findInScript(); |
| d->codeFinderWidget->setText(static_cast<QKeyEvent*>(e)->text()); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /*! |
| \reimp |
| */ |
| void QScriptDebugger::timerEvent(QTimerEvent *e) |
| { |
| Q_D(QScriptDebugger); |
| if (e->timerId() == d->updatesEnabledTimerId) { |
| killTimer(d->updatesEnabledTimerId); |
| d->updatesEnabledTimerId = -1; |
| if (d->stackWidget) |
| d->stackWidget->setUpdatesEnabled(true); |
| if (d->localsWidget) |
| d->localsWidget->setUpdatesEnabled(true); |
| } else { |
| QObject::timerEvent(e); |
| } |
| } |
| |
| QT_END_NAMESPACE |
| |
| #include "moc_qscriptdebugger_p.cpp" |