File indexing completed on 2024-04-28 15:23:09

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_