khtml Library API Documentation

kjs_debugwin.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (C) 2000-2001 Harri Porten (porten@kde.org)
00004  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Library General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU Library General Public
00017  *  License along with this library; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 #include "kjs_debugwin.h"
00022 
00023 #ifdef KJS_DEBUGGER
00024 
00025 #include <assert.h>
00026 #include <qlayout.h>
00027 #include <qpushbutton.h>
00028 #include <qtextedit.h>
00029 #include <qlistbox.h>
00030 #include <qlineedit.h>
00031 #include <qapplication.h>
00032 #include <qsplitter.h>
00033 #include <qcombobox.h>
00034 #include <qbitmap.h>
00035 #include <qwidgetlist.h>
00036 
00037 #include <klocale.h>
00038 #include <kdebug.h>
00039 #include <kiconloader.h>
00040 #include <kmessagebox.h>
00041 
00042 #include "kjs_dom.h"
00043 #include <kjs/ustring.h>
00044 #include <kjs/object.h>
00045 #include <kjs/function.h>
00046 #include <kjs/interpreter.h>
00047 
00048 using namespace KJS;
00049 
00050 KJSDebugWin * KJSDebugWin::kjs_html_debugger = 0;
00051 
00052 bool FakeModal::eventFilter( QObject *o, QEvent *e )
00053 {
00054     switch (e->type()) {
00055         case QEvent::MouseButtonPress:
00056         case QEvent::MouseButtonRelease:
00057         case QEvent::MouseButtonDblClick:
00058         case QEvent::MouseMove:
00059         case QEvent::KeyPress:
00060         case QEvent::KeyRelease:
00061         case QEvent::Destroy:
00062         case QEvent::Close:
00063         case QEvent::Quit:
00064             while (o->parent())
00065                 o = o->parent();
00066             if (o == modalWidget)
00067                 return QWidget::eventFilter( o, e );
00068             else
00069                 return TRUE;
00070             break;
00071         default:
00072             return QWidget::eventFilter( o, e );
00073     }
00074 }
00075 
00076 
00077 void FakeModal::enable(QWidget *modal)
00078 {
00079     QWidgetList *widgets = QApplication::allWidgets();
00080     QWidgetListIt it(*widgets);
00081     for (; it.current(); ++it)
00082         it.current()->installEventFilter(this);
00083     modalWidget = modal;
00084 }
00085 
00086 void FakeModal::disable()
00087 {
00088     QWidgetList *widgets = QApplication::allWidgets();
00089     QWidgetListIt it(*widgets);
00090     for (; it.current(); ++it)
00091         it.current()->removeEventFilter(this);
00092     modalWidget = 0;
00093 }
00094 
00095 //-------------------------------------------------------------------------
00096 
00097 QString StackFrame::toString()
00098 {
00099   QString str = "";
00100   if (!name.isNull())
00101     str.sprintf("%s() at sourceId %d, line %d",name.ascii(),sourceId,lineno);
00102   else
00103     str.sprintf("??? at sourceId %d, line %d",sourceId,lineno);
00104   return str;
00105 }
00106 
00107 SourceFragment::SourceFragment(int sid, int bl, SourceFile *sf)
00108 {
00109   sourceId = sid;
00110   baseLine = bl;
00111   sourceFile = sf;
00112   sourceFile->ref();
00113 }
00114 
00115 SourceFragment::~SourceFragment()
00116 {
00117   sourceFile->deref();
00118 }
00119 
00120 //-------------------------------------------------------------------------
00121 
00122 KJSDebugWin::KJSDebugWin(QWidget *parent, const char *name)
00123   : QWidget(parent, name),
00124     m_inSession(false),
00125     m_curSourceFile(0)
00126 {
00127   setCaption(i18n("JavaScript Debugger"));
00128   QVBoxLayout *vl = new QVBoxLayout(this, 5);
00129 
00130   // frame list & code
00131   QSplitter *splitter = new QSplitter(this);
00132   QFont font("courier",10);
00133 
00134   m_frameList = new QListBox(splitter);
00135   m_frameList->setFont(font);
00136   m_frameList->setMinimumSize(100,200);
00137   connect(m_frameList,SIGNAL(highlighted(int)),this,SLOT(showFrame(int)));
00138 
00139   // source selection & display
00140   QWidget *sourceSelDisplay = new QWidget(splitter);
00141   QVBoxLayout *ssdvl = new QVBoxLayout(sourceSelDisplay);
00142   
00143   
00144   m_sourceSel = new QComboBox(sourceSelDisplay);
00145   connect(m_sourceSel,SIGNAL(activated(int)),this,SLOT(sourceSelected(int)));
00146   ssdvl->addWidget(m_sourceSel);
00147 
00148   m_sourceDisplay = new QListBox(sourceSelDisplay);
00149   m_sourceDisplay->setFont(font);
00150   ssdvl->addWidget(m_sourceDisplay);
00151 
00152   vl->addWidget(splitter);
00153 
00154   QValueList<int> splitSizes;
00155   splitSizes.insert(splitSizes.end(),200);
00156   splitSizes.insert(splitSizes.end(),400);
00157   splitter->setSizes(splitSizes);
00158 
00159 
00160   // evaluate
00161   QHBoxLayout *hl1 = new QHBoxLayout(vl);
00162   m_evalEdit = new QLineEdit(this);
00163   m_evalButton = new QPushButton(i18n("&Evaluate"),this);
00164   m_evalButton->setEnabled(false);
00165   hl1->addWidget(m_evalEdit);
00166   hl1->addWidget(m_evalButton);
00167   connect(m_evalButton, SIGNAL(clicked()), SLOT(eval()));
00168   connect(m_evalEdit, SIGNAL(returnPressed()), SLOT(eval()));
00169 
00170   // control buttons
00171   QHBoxLayout *hl2 = new QHBoxLayout(vl);
00172   m_nextButton = new QPushButton(i18n("&Next"), this);
00173   m_stepButton = new QPushButton(i18n("&Step"), this);
00174   m_continueButton = new QPushButton(i18n("&Continue"), this);
00175   m_stopButton = new QPushButton(i18n("St&op"), this);
00176   m_breakButton = new QPushButton(i18n("&Break at next Statement"), this);
00177   m_breakpointButton = new QPushButton(i18n("&Toggle Breakpoint"), this);
00178   hl2->addWidget(m_nextButton);
00179   hl2->addWidget(m_stepButton);
00180   hl2->addWidget(m_continueButton);
00181   hl2->addWidget(m_stopButton);
00182   hl2->addWidget(m_breakButton);
00183   hl2->addWidget(m_breakpointButton);
00184   hl2->addStretch();
00185 
00186   connect(m_nextButton, SIGNAL(clicked()), SLOT(next()));
00187   connect(m_stepButton, SIGNAL(clicked()), SLOT(step()));
00188   connect(m_continueButton, SIGNAL(clicked()), SLOT(cont()));
00189   connect(m_stopButton, SIGNAL(clicked()), SLOT(stop()));
00190   connect(m_breakButton, SIGNAL(clicked()), SLOT(breakNext()));
00191   connect(m_breakpointButton, SIGNAL(clicked()), SLOT(toggleBreakpoint()));
00192 
00193   m_nextButton->setEnabled(false);
00194   m_stepButton->setEnabled(false);
00195   m_continueButton->setEnabled(false);
00196   m_stopButton->setEnabled(false);
00197   m_breakButton->setEnabled(true);
00198   m_breakpointButton->setEnabled(false);
00199 
00200   // frame list
00201   m_frames.setAutoDelete(true);
00202   StackFrame *sf = new StackFrame(-1,-1,"Global code",false);
00203   sf->next = true;
00204   m_frames.append(sf);
00205   //  m_frameList->insertItem(sf->toString());
00206 
00207 
00208   setMinimumSize(300,200);
00209   resize(600,450);
00210   m_mode = Continue;
00211   m_sourceBreakpoints = 0;
00212 
00213   KIconLoader loader;
00214   m_stopIcon = loader.loadIcon("stop",KIcon::Small);
00215   
00216   m_emptyIcon = QPixmap(m_stopIcon.width(),m_stopIcon.height());
00217   QBitmap emptyMask(m_stopIcon.width(),m_stopIcon.height(),true);
00218   //  m_emptyIcon.fill(m_sourceDisplay,0,0);
00219   m_emptyIcon.setMask(emptyMask);
00220 
00221   m_nextSourceBaseLine = 0;
00222   m_nextSourceUrl = "";
00223 
00224   updateFrameList();
00225   m_inSession = false;
00226   m_curExecState = 0;
00227 }
00228 
00229 KJSDebugWin::~KJSDebugWin()
00230 {
00231 }
00232 
00233 
00234 KJSDebugWin *KJSDebugWin::createInstance()
00235 {
00236   assert(!kjs_html_debugger);
00237   kjs_html_debugger = new KJSDebugWin();
00238   kjs_html_debugger->show();
00239   return kjs_html_debugger;
00240 }
00241 
00242 void KJSDebugWin::destroyInstance()
00243 {
00244   assert(kjs_html_debugger);
00245   kjs_html_debugger->hide();
00246   delete kjs_html_debugger;
00247 }
00248 
00249 void KJSDebugWin::next()
00250 {
00251   m_mode = Next;
00252   leaveSession();
00253 }
00254 
00255 void KJSDebugWin::step()
00256 {
00257   m_mode = Step;
00258   leaveSession();
00259 }
00260 
00261 void KJSDebugWin::cont()
00262 {
00263   m_mode = Continue;
00264   leaveSession();
00265 }
00266 
00267 void KJSDebugWin::stop()
00268 {
00269   m_mode = Stop;
00270   leaveSession();
00271 }
00272 
00273 void KJSDebugWin::breakNext()
00274 {
00275   m_mode = Step;
00276 }
00277 
00278 void KJSDebugWin::toggleBreakpoint()
00279 {
00280     int line = m_sourceDisplay->currentItem();
00281     if (line >= 0) {
00282         QString text(m_sourceDisplay->item(line)->text()); 
00283         m_sourceDisplay->removeItem(line);
00284         QListBoxPixmap *item;
00285         if (setBreakpoint(m_frames.last()->sourceId, line)) {
00286             item = new QListBoxPixmap(m_stopIcon,text);
00287         } else {
00288             deleteBreakpoint(m_frames.last()->sourceId, line);
00289             item = new QListBoxPixmap(m_emptyIcon,text);
00290         }
00291         m_sourceDisplay->insertItem(item, line);
00292         m_sourceDisplay->setCurrentItem(line);
00293     }
00294 }
00295 
00296 void KJSDebugWin::showFrame(int frameno)
00297 {
00298   StackFrame *frame = m_frames.at(frameno);
00299   if (!frame)
00300     return;
00301   highLight(frame->sourceId,frame->lineno);
00302 }
00303 
00304 void KJSDebugWin::sourceSelected(int sourceSelIndex)
00305 {
00306   // a souce file has been selected from the drop-down list - display the file
00307   // and hilight the line if it's in the current stack frame
00308   if (sourceSelIndex < 0 || sourceSelIndex >= (int)m_sourceSel->count())
00309     return;
00310   SourceFile *sourceFile = m_sourceSelFiles[sourceSelIndex];
00311   bool newsource = m_curSourceFile != sourceFile;
00312   m_curSourceFile = sourceFile;
00313 
00314   SourceFragment *lastFragment = 0;
00315   StackFrame *curFrame = m_frames.at(m_frameList->currentItem() >= 0 ? m_frameList->currentItem() : m_frames.count()-1);
00316   if (curFrame)
00317     lastFragment = m_sourceFragments[curFrame->sourceId];
00318   if (newsource)
00319       setCode(sourceFile->code, curFrame ? curFrame->sourceId : -1);
00320   if (lastFragment && lastFragment->sourceFile == m_curSourceFile) {
00321     m_sourceDisplay->setCurrentItem(lastFragment->baseLine+curFrame->lineno);
00322   } else
00323     m_sourceDisplay->setCurrentItem(-1);
00324 }
00325 
00326 void KJSDebugWin::eval()
00327 {
00328   // evaluate the js code from m_evalEdit
00329 /*
00330   if (!m_inSession)
00331     return;
00332 
00333   // create function
00334   KJS::Constructor constr(KJS::Global::current().get("Function").imp());
00335   KJS::List args;
00336   args.append(KJS::String("event"));
00337   args.append(KJS::String("return "+m_evalEdit->text()+";"));
00338   KJS::KJSO func = constr.construct(args);
00339   // execute
00340   Mode oldMode = m_mode;
00341   m_mode = Continue; // prevents us from stopping during evaluation
00342 
00343   KJSO ret = m_curContext->executeCall(m_curScript,func,func,0);
00344   KMessageBox::information(this, ret.toString().value().qstring(), "JavaScript eval");
00345   m_mode = oldMode;
00346   */
00347 }
00348 
00349 void KJSDebugWin::closeEvent(QCloseEvent *e)
00350 {
00351   if (m_inSession)
00352     leaveSession();
00353   return QWidget::closeEvent(e);
00354 }
00355 
00356 bool KJSDebugWin::sourceParsed(KJS::ExecState * exec, int sourceId,
00357                                const KJS::UString &source, int /*errorLine*/)
00358 {
00359   // the interpreter has parsed some js code - store it in a SourceFragment object
00360   // ### report errors (errorLine >= 0)
00361 
00362   SourceFile *sourceFile = m_sourceFiles[m_nextSourceUrl];
00363   if (!sourceFile) {
00364     sourceFile = new SourceFile("(unknown)",source.qstring(),m_sourceSel->count());
00365     m_sourceSelFiles[sourceFile->index] = sourceFile;
00366     if (m_nextSourceUrl.isNull() || m_nextSourceUrl == "")
00367         m_sourceSel->insertItem("???");
00368     else
00369         m_sourceSel->insertItem(m_nextSourceUrl);
00370   }
00371 
00372   SourceFragment *sf = new SourceFragment(sourceId,m_nextSourceBaseLine,sourceFile);
00373   m_sourceFragments[sourceId] = sf;
00374 
00375 
00376   m_nextSourceBaseLine = 0;
00377   m_nextSourceUrl = "";
00378 
00379   return (m_mode != Stop);
00380 }
00381 
00382 bool KJSDebugWin::sourceUnused(KJS::ExecState * /*exec*/, int sourceId)
00383 {
00384   // the source fragment is no longer in use, so we can free it
00385 
00386   SourceFragment *fragment = m_sourceFragments[sourceId];
00387   if (fragment) {
00388       m_sourceFragments.erase(sourceId);
00389       SourceFile *sourceFile = fragment->sourceFile;
00390       if (sourceFile->hasOneRef()) {
00391           m_sourceSel->removeItem(sourceFile->index);
00392           for (int i = sourceFile->index; i < m_sourceSel->count(); i++) {
00393               m_sourceSelFiles[i+1]->index--;
00394               m_sourceSelFiles[i] = m_sourceSelFiles[i+1];
00395           }
00396           m_sourceSelFiles.erase(m_sourceSel->count());
00397           m_sourceSel->removeItem(m_sourceSel->count()-1);
00398       }
00399       delete fragment;
00400   }
00401   return (m_mode != Stop);
00402 }
00403 
00404 bool KJSDebugWin::exception(KJS::ExecState *exec, int /*sourceId*/, 
00405         int /*lineno*/, KJS::Object &exceptionObj)
00406 {
00407   // ### bring up source & hilight line
00408   KMessageBox::error(this, exceptionObj.toString(exec).qstring(), "JavaScript error");
00409   return (m_mode != Stop);
00410 }
00411 
00412 bool KJSDebugWin::atStatement(KJS::ExecState *exec, int sourceId, 
00413                               int firstLine, int lastLine)
00414 {
00415   KJS::ExecState *oldCurExecState = m_curExecState;
00416   m_curExecState = exec;
00417   
00418   if (haveBreakpoint(sourceId,firstLine, lastLine)) {
00419     m_mode = Next;
00420     m_frames.last()->next = true;
00421   }
00422 
00423   m_frames.last()->sourceId = sourceId;
00424   m_frames.last()->lineno = firstLine;
00425   //  highLight(sourceId,lineno);
00426   if (m_mode == KJSDebugWin::Step || m_mode == KJSDebugWin::Next) {
00427     if (m_frames.last()->next)
00428       enterSession();
00429   }
00430 
00431   m_curExecState = oldCurExecState;
00432   return (m_mode != Stop);
00433 }
00434 
00435 bool KJSDebugWin::callEvent(KJS::ExecState *exec, int sourceId, int lineno,
00436         KJS::Object &function, const KJS::List & /*args*/)
00437 {
00438   //  highLight(sourceId,lineno);
00439   KJS::ExecState *oldCurExecState = m_curExecState;
00440   m_curExecState = exec;
00441   KJS::FunctionImp *fimp = static_cast<KJS::FunctionImp*>(function.imp()); 
00442   QString name = fimp->name().qstring();
00443   StackFrame *sf = new StackFrame(sourceId,lineno,name,m_mode == Step);
00444   m_frames.append(sf);
00445   if (m_mode == Step)
00446     enterSession();
00447   m_curExecState = oldCurExecState;
00448   return (m_mode != Stop);
00449 }
00450 
00451 bool KJSDebugWin::returnEvent(KJS::ExecState *exec, int sourceId, int lineno,
00452         KJS::Object & /*function*/)
00453 {
00454   //  highLight(sourceId,lineno);
00455   KJS::ExecState *oldCurExecState = m_curExecState;
00456   m_curExecState = exec;
00457   m_frames.last()->sourceId = sourceId;
00458   m_frames.last()->lineno = lineno;
00459   if (m_frames.last()->step)
00460     enterSession();
00461   m_frames.removeLast();
00462   //  m_frameList->removeItem(m_frameList->count()-1);
00463   m_curExecState = oldCurExecState;
00464   return (m_mode != Stop);
00465 }
00466 
00467 void KJSDebugWin::setCode(const QString &code, int sourceId)
00468 {
00469   const QChar *chars = code.unicode();
00470   uint len = code.length();
00471   QChar newLine('\n');
00472   QChar cr('\r');
00473   QChar tab('\t');
00474   QString tabstr("        ");
00475   QString line;
00476   m_sourceDisplay->clear();
00477   int numlines = 0;
00478   for (uint i = 0; i < len; i++) {
00479       if (chars[i] == cr)
00480           continue;
00481       else if (chars[i] == newLine) {
00482           m_sourceDisplay->insertItem(new QListBoxPixmap(haveBreakpoint(sourceId, numlines, numlines) ? m_stopIcon : m_emptyIcon,line));
00483           numlines++;
00484           line = "";
00485       } else if (chars[i] == tab) {
00486           line += tabstr;
00487       } else
00488           line += chars[i];
00489   }
00490   if (line.length())
00491       m_sourceDisplay->insertItem(new QListBoxPixmap(haveBreakpoint(sourceId, numlines, numlines) ? m_stopIcon : m_emptyIcon,line));
00492 }
00493 
00494 void KJSDebugWin::highLight(int sourceId, int line)
00495 {
00496   if (!isVisible())
00497     show();
00498 
00499   SourceFragment *source = m_sourceFragments[sourceId];
00500   if (!source)
00501     return;
00502 
00503   SourceFile *sourceFile = source->sourceFile;
00504   if (m_curSourceFile != source->sourceFile) {
00505       m_sourceSel->setCurrentItem(source->sourceFile->index);
00506       setCode(sourceFile->code, sourceId);
00507   }
00508   m_curSourceFile = source->sourceFile;
00509   if (line > 0)
00510     m_sourceDisplay->setCurrentItem(line+source->baseLine-1);
00511   else
00512     m_sourceDisplay->setCurrentItem(-1);
00513 }
00514 
00515 void KJSDebugWin::setNextSourceInfo(QString url, int baseLine)
00516 {
00517   m_nextSourceUrl = url;
00518   m_nextSourceBaseLine = baseLine;
00519 }
00520 
00521 void KJSDebugWin::setSourceFile(QString url, QString code)
00522 {
00523   SourceFile *existing = m_sourceFiles[url];
00524   int newindex = m_sourceSel->count();
00525   if (existing) {
00526       newindex = existing->index;
00527       m_sourceSel->removeItem(existing->index);
00528       existing->deref();
00529   }
00530   SourceFile *newSF = new SourceFile(url,code,newindex);
00531   m_sourceFiles[url] = newSF;
00532   m_sourceSelFiles[newindex] = newSF;
00533   m_sourceSel->insertItem(url,newindex);
00534 }
00535 
00536 void KJSDebugWin::appendSourceFile(QString url, QString code)
00537 {
00538   SourceFile *existing = m_sourceFiles[url];
00539   if (!existing) {
00540     setSourceFile(url,code);
00541     return;
00542   }
00543   existing->code.append(code);
00544 }
00545 
00546 void KJSDebugWin::enterSession()
00547 {
00548   // This "enters" a new debugging session, i.e. enables usage of the debugging window
00549   // It re-enters the qt event loop here, allowing execution of other parts of the
00550   // program to continue while the script is stopped. We have to be a bit careful here,
00551   // i.e. make sure the user can't quite the app, and not executing more js code
00552   assert(!m_inSession);
00553   m_fakeModal.enable(this);
00554   m_inSession = true;
00555   m_mode = Continue;
00556 
00557   m_nextButton->setEnabled(true);
00558   m_stepButton->setEnabled(true);
00559   m_continueButton->setEnabled(true);
00560   m_stopButton->setEnabled(true);
00561   m_evalButton->setEnabled(true);
00562   m_breakButton->setEnabled(false);
00563   m_breakpointButton->setEnabled(true);
00564   updateFrameList();
00565 
00566   qApp->enter_loop(); // won't return until leaveSession() is called
00567   assert(!m_inSession);
00568 }
00569 
00570 void KJSDebugWin::leaveSession()
00571 {
00572   // Disables debugging for this window and returns to execute the rest of the script
00573   // (or aborts execution, if the user pressed stop). When this returns, the program
00574   // will exit the qt event loop, i.e. return to whatever processing was being done
00575   // before the debugger was stopped.
00576   assert(m_inSession);
00577   m_nextButton->setEnabled(false);
00578   m_stepButton->setEnabled(false);
00579   m_continueButton->setEnabled(false);
00580   m_stopButton->setEnabled(false);
00581   m_evalButton->setEnabled(false);
00582   m_breakButton->setEnabled(true);
00583   m_breakpointButton->setEnabled(false);
00584   m_inSession = false;
00585   qApp->exit_loop();
00586   m_fakeModal.disable();
00587 }
00588 
00589 void KJSDebugWin::updateFrameList()
00590 {
00591   uint frameno;
00592   disconnect(m_frameList,SIGNAL(highlighted(int)),this,SLOT(showFrame(int)));
00593   m_frameList->clear();
00594   for (frameno = 0; frameno < m_frames.count(); frameno++) {
00595     m_frameList->insertItem(m_frames.at(frameno)->toString(),frameno);
00596   }
00597   m_frameList->setSelected(m_frameList->count()-1, true);
00598   highLight(m_frames.last()->sourceId,m_frames.last()->lineno);
00599   connect(m_frameList,SIGNAL(highlighted(int)),this,SLOT(showFrame(int)));
00600 }
00601 
00602 bool KJSDebugWin::setBreakpoint(int sourceId, int line)
00603 {
00604   if (haveBreakpoint(sourceId,line,line))
00605     return false;
00606 
00607   SourceBreakpoints *sbp = m_sourceBreakpoints;
00608   while(sbp && sbp->sourceId != sourceId)
00609     sbp = sbp->next;
00610   if (!sbp) {
00611     sbp = new SourceBreakpoints;
00612     sbp->sourceId = sourceId;
00613     sbp->breakpoints = 0;
00614     sbp->next = m_sourceBreakpoints;
00615     m_sourceBreakpoints = sbp;
00616   }
00617 
00618   Breakpoint *newbp = new Breakpoint;
00619   newbp->lineno = line;
00620   newbp->next = sbp->breakpoints;
00621   sbp->breakpoints = newbp;
00622 
00623   return true;
00624 }
00625 
00626 bool KJSDebugWin::deleteBreakpoint(int sourceId, int line)
00627 {
00628   for (SourceBreakpoints *sbp = m_sourceBreakpoints; sbp; sbp = sbp->next) {
00629     if (sbp->sourceId == sourceId) {
00630       // found breakpoints for this sourceId
00631       Breakpoint *bp = sbp->breakpoints;
00632       if (bp && bp->lineno == line) {
00633         // was the first breakpoint
00634         Breakpoint *next = bp->next;
00635         delete bp;
00636         sbp->breakpoints = next;
00637         return true;
00638       }
00639 
00640       while (bp->next && bp->next->lineno != line)
00641         bp = bp->next;
00642       if (bp->next && bp->next->lineno == line) {
00643         // found at subsequent breakpoint
00644         Breakpoint *next = bp->next->next;
00645         delete bp->next;
00646         bp->next = next;
00647         return true;
00648       }
00649       return false;
00650     }
00651   }
00652   // no breakpoints at all for this sourceId
00653   return false;
00654 }
00655 
00656 void KJSDebugWin::clearAllBreakpoints(int sourceId)
00657 {
00658   SourceBreakpoints *nextsbp = 0;
00659   for (SourceBreakpoints *sbp = m_sourceBreakpoints; sbp; sbp = nextsbp) {
00660     nextsbp = sbp->next;
00661     if (sourceId == -1 || sbp->sourceId == sourceId) {
00662       Breakpoint *nextbp;
00663       for (Breakpoint *bp = sbp->breakpoints; bp; bp = bp->next) {
00664         nextbp = bp->next;
00665         delete bp;
00666       }
00667       delete sbp;
00668     }
00669   }
00670 }
00671 
00672 int KJSDebugWin::breakpointLine(int sourceId, int line0, int line1)
00673 {
00674   for (SourceBreakpoints *sbp = m_sourceBreakpoints; sbp; sbp = sbp->next) {
00675     if (sbp->sourceId == sourceId) {
00676       // found breakpoints for this sourceId
00677       for (Breakpoint *bp = sbp->breakpoints; bp; bp = bp->next) {
00678         if (bp->lineno >= 0 && bp->lineno >= line0 && bp->lineno <= line1)
00679           return bp->lineno;
00680       }
00681       return -1;
00682     }
00683   }
00684   // no breakpoints at all for this sourceId
00685   return -1;
00686 }
00687 
00688 bool KJSDebugWin::haveBreakpoint(int sourceId, int line0, int line1)
00689 {
00690   return (breakpointLine(sourceId,line0,line1) != -1);
00691 }
00692 
00693 #include "kjs_debugwin.moc"
00694 
00695 #endif // KJS_DEBUGGER
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:13 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001