File indexing completed on 2023-10-03 03:17:40
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2000-2001 Harri Porten (porten@kde.org) 0004 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com) 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0019 */ 0020 0021 #ifndef _KJS_DEBUGGER_H_ 0022 #define _KJS_DEBUGGER_H_ 0023 0024 #ifdef KJS_DEBUGGER 0025 0026 #include <qwidget.h> 0027 #include <q3multilineedit.h> 0028 #include <qpixmap.h> 0029 #include <q3ptrlist.h> 0030 #include <QStack> 0031 #include <qcheckbox.h> 0032 #include <kdialog.h> 0033 #include <kcomponentdata.h> 0034 #include <kmainwindow.h> 0035 #include <q3scrollview.h> 0036 0037 #include <kjs/debugger.h> 0038 #include <kjs/completion.h> 0039 #include <kjs/interpreter.h> 0040 #include <kjs/value.h> 0041 #include "kjs_binding.h" 0042 0043 #include "dom/dom_misc.h" 0044 0045 class QListWidget; 0046 class QComboBox; 0047 class QAction; 0048 0049 namespace KJS 0050 { 0051 class List; 0052 class KJSDebugWin; 0053 0054 class SourceFile : public DOM::DomShared 0055 { 0056 public: 0057 SourceFile(QString u, QString c, Interpreter *interp) 0058 : url(u), code(c), interpreter(interp) {} 0059 QString getCode(); 0060 QString url; 0061 QString code; 0062 Interpreter *interpreter; 0063 }; 0064 0065 /** 0066 * @internal 0067 * 0068 * When kjs parses some code, it generates a source code fragment (or just "source"). 0069 * This is referenced by its source id in future calls to functions such as atLine() 0070 * and callEvent(). We keep a record of all source fragments parsed in order to display 0071 * then to the user. 0072 * 0073 * For .js files, the source fragment will be the entire file. For js code included 0074 * in html files, however, there may be multiple source fragments within the one file 0075 * (e.g. multiple SCRIPT tags or onclick="..." attributes) 0076 * 0077 * In the case where a single file has multiple source fragments, the source objects 0078 * for these fragments will all point to the same SourceFile for their code. 0079 */ 0080 class SourceFragment 0081 { 0082 public: 0083 SourceFragment(int sid, int bl, int el, SourceFile *sf); 0084 ~SourceFragment(); 0085 0086 int sourceId; 0087 int baseLine; 0088 int errorLine; 0089 SourceFile *sourceFile; 0090 private: 0091 SourceFragment(const SourceFragment &other); 0092 SourceFragment &operator = (const SourceFragment &other); 0093 }; 0094 0095 class KJSErrorDialog : public KDialog 0096 { 0097 Q_OBJECT 0098 public: 0099 KJSErrorDialog(QWidget *parent, const QString &errorMessage, bool showDebug); 0100 virtual ~KJSErrorDialog(); 0101 0102 bool debugSelected() const 0103 { 0104 return m_debugSelected; 0105 } 0106 bool dontShowAgain() const 0107 { 0108 return m_dontShowAgainCb->isChecked(); 0109 } 0110 0111 protected Q_SLOTS: 0112 virtual void slotUser1(); 0113 0114 private: 0115 QCheckBox *m_dontShowAgainCb; 0116 bool m_debugSelected; 0117 }; 0118 0119 class EvalMultiLineEdit : public Q3MultiLineEdit 0120 { 0121 Q_OBJECT 0122 public: 0123 EvalMultiLineEdit(QWidget *parent); 0124 const QString &code() const 0125 { 0126 return m_code; 0127 } 0128 protected: 0129 void keyPressEvent(QKeyEvent *e); 0130 private: 0131 QString m_code; 0132 }; 0133 0134 class SourceDisplay : public Q3ScrollView 0135 { 0136 Q_OBJECT 0137 public: 0138 SourceDisplay(KJSDebugWin *debugWin, QWidget *parent, const char *name = 0); 0139 ~SourceDisplay(); 0140 0141 void setSource(SourceFile *sourceFile); 0142 void setCurrentLine(int lineno, bool doCenter = true); 0143 0144 Q_SIGNALS: 0145 void lineDoubleClicked(int lineno); 0146 0147 protected: 0148 virtual void contentsMousePressEvent(QMouseEvent *e); 0149 virtual void showEvent(QShowEvent *); 0150 virtual void drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph); 0151 0152 QString m_source; 0153 int m_currentLine; 0154 SourceFile *m_sourceFile; 0155 QStringList m_lines; 0156 0157 KJSDebugWin *m_debugWin; 0158 QFont m_font; 0159 QPixmap m_breakpointIcon; 0160 }; 0161 0162 /** 0163 * @internal 0164 * 0165 * KJSDebugWin represents the debugger window that is visible to the user. It contains 0166 * a stack frame list, a code viewer and a source fragment selector, plus buttons 0167 * to control execution including next, step and continue. 0168 * 0169 * There is only one debug window per program. This can be obtained by calling #instance 0170 */ 0171 class KJSDebugWin : public KMainWindow, public Debugger, public KComponentData 0172 { 0173 Q_OBJECT 0174 friend class SourceDisplay; 0175 public: 0176 KJSDebugWin(QWidget *parent = 0, const char *name = 0); 0177 virtual ~KJSDebugWin(); 0178 0179 static KJSDebugWin *createInstance(); 0180 static void destroyInstance(); 0181 static KJSDebugWin *debugWindow() 0182 { 0183 return kjs_html_debugger; 0184 } 0185 0186 enum Mode { Disabled = 0, // No break on any statements 0187 Next = 1, // Will break on next statement in current context 0188 Step = 2, // Will break on next statement in current or deeper context 0189 Continue = 3, // Will continue until next breakpoint 0190 Stop = 4 // The script will stop execution completely, 0191 // as soon as possible 0192 }; 0193 0194 void setSourceLine(int sourceId, int lineno); 0195 void setNextSourceInfo(QString url, int baseLine); 0196 void sourceChanged(Interpreter *interpreter, QString url); 0197 bool inSession() const 0198 { 0199 return !m_execStates.isEmpty(); 0200 } 0201 void setMode(Mode m) 0202 { 0203 m_mode = m; 0204 } 0205 void clearInterpreter(Interpreter *interpreter); 0206 ExecState *getExecState() const 0207 { 0208 return m_execStates.top(); 0209 } 0210 0211 // functions overridden from KJS:Debugger 0212 bool sourceParsed(ExecState *exec, int sourceId, 0213 const UString &source, int errorLine); 0214 bool sourceUnused(ExecState *exec, int sourceId); 0215 bool exception(ExecState *exec, JSValue *value, bool inTryCatch); 0216 bool atStatement(ExecState *exec); 0217 bool enterContext(ExecState *exec); 0218 bool exitContext(ExecState *exec, const Completion &completion); 0219 0220 public Q_SLOTS: 0221 void slotNext(); 0222 void slotStep(); 0223 void slotContinue(); 0224 void slotStop(); 0225 void slotBreakNext(); 0226 void slotToggleBreakpoint(int lineno); 0227 void slotShowFrame(int frameno); 0228 void slotSourceSelected(int sourceSelIndex); 0229 void slotEval(); 0230 0231 protected: 0232 0233 void closeEvent(QCloseEvent *e); 0234 bool eventFilter(QObject *obj, QEvent *evt); 0235 void disableOtherWindows(); 0236 void enableOtherWindows(); 0237 0238 private: 0239 0240 SourceFile *getSourceFile(Interpreter *interpreter, QString url); 0241 void setSourceFile(Interpreter *interpreter, QString url, SourceFile *sourceFile); 0242 void removeSourceFile(Interpreter *interpreter, QString url); 0243 0244 void checkBreak(ExecState *exec); 0245 void enterSession(ExecState *exec); 0246 void leaveSession(); 0247 void displaySourceFile(SourceFile *sourceFile, bool forceRefresh); 0248 void updateContextList(); 0249 0250 QString contextStr(const Context &ctx); 0251 0252 struct Breakpoint { 0253 int sourceId; 0254 int lineno; 0255 }; 0256 Breakpoint *m_breakpoints; 0257 int m_breakpointCount; 0258 bool setBreakpoint(int sourceId, int lineno); 0259 bool deleteBreakpoint(int sourceId, int lineno); 0260 bool haveBreakpoint(SourceFile *sourceFile, int line0, int line1); 0261 bool haveBreakpoint(int sourceId, int line0, int line1) const 0262 { 0263 for (int i = 0; i < m_breakpointCount; i++) { 0264 if (m_breakpoints[i].sourceId == sourceId && 0265 m_breakpoints[i].lineno >= line0 && 0266 m_breakpoints[i].lineno <= line1) { 0267 return true; 0268 } 0269 } 0270 return false; 0271 } 0272 0273 SourceFile *m_curSourceFile; 0274 Mode m_mode; 0275 QString m_nextSourceUrl; 0276 int m_nextSourceBaseLine; 0277 QStack<ExecState *> m_execStates; 0278 ExecState **m_execs; 0279 int m_execsCount; 0280 int m_execsAlloc; 0281 int m_steppingDepth; 0282 0283 QMap<QString, SourceFile *> m_sourceFiles; /* maps url->SourceFile */ 0284 QMap<int, SourceFragment *> m_sourceFragments; /* maps SourceId->SourceFragment */ 0285 Q3PtrList<SourceFile> m_sourceSelFiles; /* maps combobox index->SourceFile */ 0286 0287 QPixmap m_stopIcon; 0288 QPixmap m_emptyIcon; 0289 SourceDisplay *m_sourceDisplay; 0290 QListWidget *m_contextList; 0291 0292 QAction *m_stepAction; 0293 QAction *m_nextAction; 0294 QAction *m_continueAction; 0295 QAction *m_stopAction; 0296 QAction *m_breakAction; 0297 0298 QComboBox *m_sourceSel; 0299 EvalMultiLineEdit *m_evalEdit; 0300 int m_evalDepth; 0301 0302 static KJSDebugWin *kjs_html_debugger; 0303 }; 0304 0305 } // namespace 0306 0307 #endif // KJS_DEBUGGER 0308 0309 #endif // _KJS_DEBUGGER_H_