File indexing completed on 2024-12-01 12:33:25
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2006 Matt Broadstone (mbroadst@gmail.com) 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public 0016 * License along with this library; if not, write to the Free Software 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 */ 0019 0020 #ifndef DEBUGWINDOW_H 0021 #define DEBUGWINDOW_H 0022 0023 #include <kcomponentdata.h> 0024 #include <kxmlguiwindow.h> 0025 0026 #include <kjs/debugger.h> 0027 #include <kjs/completion.h> 0028 #include <kjs/interpreter.h> 0029 #include <kjs/value.h> 0030 #include <kjs_binding.h> 0031 0032 #include <ktexteditor/document.h> 0033 #include <ktexteditor/view.h> 0034 #include <ktexteditor/editor.h> 0035 #include <ktexteditor/markinterface.h> 0036 0037 #include "khtml_pagecache.h" 0038 #include "khtml_part.h" 0039 #include "dom/dom_misc.h" 0040 #include "misc/shared.h" 0041 0042 #include <QStack> 0043 #include <QVector> 0044 0045 #include "interpreter_ctx.h" 0046 #include "debugdocument.h" 0047 0048 class QAction; 0049 class KToggleAction; 0050 class QTabWidget; 0051 class QFrame; 0052 class QEventLoop; 0053 0054 namespace KJSDebugger 0055 { 0056 0057 class CallStackDock; 0058 class WatchesDock; 0059 class LocalVariablesDock; 0060 class ScriptsDock; 0061 class BreakpointsDock; 0062 class ConsoleDock; 0063 0064 /** 0065 * DebuggerWindow 0066 * 0067 * KJSDebugWin represents the debugger window that is visible to the user. It contains 0068 * a stack frame list, a code viewer and a source fragment selector, plus buttons 0069 * to control execution including next, step and continue. 0070 * 0071 * There is only one debug window per program. This can be obtained by calling #instance 0072 */ 0073 class DebugWindow : public KXmlGuiWindow, public KJS::Debugger, public KComponentData, 0074 public khtml::Shared<DebugWindow> 0075 { 0076 Q_OBJECT 0077 0078 public: 0079 DebugWindow(QWidget *parent = 0); 0080 virtual ~DebugWindow(); 0081 0082 static DebugWindow *window(); 0083 0084 // Returns true if the debugger is active, and has blocked the execution 0085 // for some reason. 0086 // ### seems like some of what we (mis-)use inSession() for should use this 0087 static bool isBlocked(); 0088 0089 // Returns if we blocked execution; KHTML will attempt to use it 0090 // to prevent some kinds of accidental recursion. Should go 0091 // if proper modal dialog manager shows up 0092 bool inSession() const 0093 { 0094 return !m_activeSessionCtxs.isEmpty(); 0095 } 0096 0097 public: 0098 0099 // All of the below are overridden from KJS::Debugger 0100 bool sourceParsed(KJS::ExecState *exec, int sourceId, const KJS::UString &sourceURL, 0101 const KJS::UString &source, int startingLineNumber, int errorLine, const KJS::UString &errorMsg); 0102 bool exception(KJS::ExecState *exec, int sourceId, int lineno, KJS::JSValue *exceptionObj); 0103 bool atStatement(KJS::ExecState *exec, int sourceId, int firstLine, int lastLine); 0104 bool enterContext(KJS::ExecState *exec, int sourceId, int lineno, KJS::JSObject *function, const KJS::List &args); 0105 bool exitContext(KJS::ExecState *exec, int sourceId, int lineno, KJS::JSObject *function); 0106 void attach(KJS::Interpreter *interp); 0107 void detach(KJS::Interpreter *interp); 0108 0109 bool shouldReindentSources() const; 0110 0111 // Called by KJSProxy when we navigate away from a page 0112 void clearInterpreter(KJS::Interpreter *interp); 0113 0114 // Hook for activating the debugger from gdb or such 0115 static void forceStopAtNext(); 0116 0117 public Q_SLOTS: 0118 void stopAtNext(); 0119 void continueExecution(); 0120 void stepInto(); 0121 void stepOut(); 0122 void stepOver(); 0123 0124 void markSet(KTextEditor::Document *document, KTextEditor::Mark mark, 0125 KTextEditor::MarkInterface::MarkChangeAction action); 0126 0127 protected: 0128 virtual void closeEvent(QCloseEvent *event); 0129 0130 bool eventFilter(QObject *object, QEvent *event); 0131 void disableOtherWindows(); 0132 void enableOtherWindows(); 0133 0134 private Q_SLOTS: 0135 void settingsChanged(); 0136 0137 void displayScript(KJSDebugger::DebugDocument *document); 0138 void displayScript(KJSDebugger::DebugDocument *document, int line); // -1 denotes not focusing on the line 0139 void updateVarView(); 0140 void closeTab(); 0141 void documentDestroyed(KJSDebugger::DebugDocument *doc); 0142 0143 void doEval(const QString &code); 0144 private: 0145 void createActions(); 0146 void createMenus(); 0147 void createToolBars(); 0148 void createStatusBar(); 0149 void createTabWidget(); 0150 0151 void enterDebugSession(KJS::ExecState *exec, DebugDocument *document, int line); 0152 void leaveDebugSession(); 0153 0154 void enterModality(); 0155 void leaveModality(); 0156 0157 void enterLoop(); 0158 void exitLoop(); 0159 0160 enum RunMode { Running, Stopped }; 0161 0162 void setUIMode(RunMode mode); 0163 void updateStoppedMark(RunMode mode); 0164 private: 0165 void cleanupDocument(DebugDocument::Ptr document); 0166 0167 // Checks to see whether we should stop at the given location, based on the current 0168 // mode and breakpoints. Returns false if we should abort 0169 bool checkSourceLocation(KJS::ExecState *exec, int sourceId, int firstLine, int lastLine); 0170 0171 // Standard actions 0172 QAction *m_exitAct; 0173 0174 // Flow control actions 0175 QAction *m_continueAct; 0176 QAction *m_stopAct; 0177 QAction *m_stepIntoAct; 0178 QAction *m_stepOutAct; 0179 QAction *m_stepOverAct; 0180 0181 KToggleAction *m_catchExceptionsAction; 0182 KToggleAction *m_reindentAction; 0183 0184 // WatchesDock *m_watches; 0185 LocalVariablesDock *m_localVariables; 0186 ScriptsDock *m_scripts; 0187 CallStackDock *m_callStack; 0188 BreakpointsDock *m_breakpoints; 0189 ConsoleDock *m_console; 0190 0191 QTabWidget *m_tabWidget; 0192 0193 // e.g. not aborted 0194 bool shouldContinue(InterpreterContext *ic); 0195 0196 // This keeps track of modal dialogs we've put up 0197 // that may disable the CPU guard. 0198 int m_modalLevel; 0199 0200 // This is all the nested event loops that are active 0201 QStack<QEventLoop *> m_activeEventLoops; 0202 0203 void resetTimeoutsIfNeeded(); 0204 0205 bool m_reindentSources; 0206 bool m_catchExceptions; 0207 void syncFromConfig(); 0208 void syncToConfig(); 0209 0210 // The handling of debugger modes is a bit funny. 0211 // essentially, we want normal step/stepOver/stepOut 0212 // to work per (dynamic) interpreter, but "break at next" 0213 // should work globally. 0214 bool m_breakAtNext; 0215 0216 InterpreterContext *ctx() 0217 { 0218 return m_activeSessionCtxs.isEmpty() ? 0 : m_activeSessionCtxs.top(); 0219 } 0220 0221 QHash<int, DebugDocument::Ptr> m_docForSid; 0222 0223 // For each interpreter, we keep track of what documents belong to it 0224 // so we can discard them when needed, as well as flush for reload 0225 QHash<KJS::Interpreter *, QList<DebugDocument::Ptr> > m_docsForIntrp; 0226 0227 // Some of the state we want to keep track of while debugging, such as backtraces, 0228 // is per-interpreter, and this lets us look uit up. 0229 QHash<KJS::Interpreter *, InterpreterContext *> m_contexts; 0230 0231 // This keeps track of the contexts for the various debuggers 0232 // we may be in session for. It's needed because the same window is 0233 // used for all, so we may occassionally be a few levels of recursion in, 0234 // so we need to know exactly how to unwind, etc. 0235 QStack<InterpreterContext *> m_activeSessionCtxs; 0236 0237 // This denotes the session we were in once we entered the running UI 0238 // mode. May be null 0239 InterpreterContext *m_runningSessionCtx; 0240 0241 // The documents that are currently open for viewing. 0242 // The index matches that of the tab widget; 0243 QList<DebugDocument *> m_openDocuments; 0244 0245 static DebugWindow *s_debugger; 0246 }; 0247 0248 } // namespace 0249 0250 #endif // DEBUGWINDOW_H