00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "kjs_debugwin.h"
00022
#include "kjs_proxy.h"
00023
00024
#ifdef KJS_DEBUGGER
00025
00026
#include <assert.h>
00027
#include <stdlib.h>
00028
#include <qlayout.h>
00029
#include <qpushbutton.h>
00030
#include <qtextedit.h>
00031
#include <qlistbox.h>
00032
#include <qmultilineedit.h>
00033
#include <qapplication.h>
00034
#include <qsplitter.h>
00035
#include <qcombobox.h>
00036
#include <qbitmap.h>
00037
#include <qwidgetlist.h>
00038
#include <qlabel.h>
00039
#include <qdatastream.h>
00040
#include <qcstring.h>
00041
#include <qpainter.h>
00042
#include <qscrollbar.h>
00043
00044
#include <klocale.h>
00045
#include <kdebug.h>
00046
#include <kiconloader.h>
00047
#include <kglobal.h>
00048
#include <kmessagebox.h>
00049
#include <kguiitem.h>
00050
#include <kpopupmenu.h>
00051
#include <kmenubar.h>
00052
#include <kaction.h>
00053
#include <kactioncollection.h>
00054
#include <kglobalsettings.h>
00055
#include <kshortcut.h>
00056
#include <kconfig.h>
00057
#include <kconfigbase.h>
00058
#include <kapplication.h>
00059
#include <dcop/dcopclient.h>
00060
00061
#include "kjs_dom.h"
00062
#include "kjs_binding.h"
00063
#include "khtml_part.h"
00064
#include "khtmlview.h"
00065
#include "khtml_pagecache.h"
00066
#include "khtml_settings.h"
00067
#include "khtml_factory.h"
00068
#include "misc/decoder.h"
00069
#include <kjs/ustring.h>
00070
#include <kjs/object.h>
00071
#include <kjs/function.h>
00072
#include <kjs/interpreter.h>
00073
00074
using namespace KJS;
00075
using namespace khtml;
00076
00077 SourceDisplay::SourceDisplay(KJSDebugWin *debugWin,
QWidget *parent,
const char *name)
00078 :
QScrollView(parent,
name), m_currentLine(-1), m_sourceFile(0), m_debugWin(debugWin),
00079 m_font(
KGlobalSettings::fixedFont())
00080 {
00081 verticalScrollBar()->setLineStep(
QFontMetrics(m_font).height());
00082 viewport()->setBackgroundMode(Qt::NoBackground);
00083 m_breakpointIcon =
KGlobal::iconLoader()->
loadIcon(
"stop",KIcon::Small);
00084 }
00085
00086 SourceDisplay::~SourceDisplay()
00087 {
00088
if (m_sourceFile) {
00089 m_sourceFile->deref();
00090 m_sourceFile = 0L;
00091 }
00092 }
00093
00094
void SourceDisplay::setSource(SourceFile *sourceFile)
00095 {
00096
if ( sourceFile )
00097 sourceFile->ref();
00098
if (m_sourceFile)
00099 m_sourceFile->deref();
00100 m_sourceFile = sourceFile;
00101
if ( m_sourceFile )
00102 m_sourceFile->ref();
00103
00104
if (!m_sourceFile || !m_debugWin->isVisible()) {
00105
return;
00106 }
00107
00108
QString code = sourceFile->getCode();
00109
const QChar *chars = code.unicode();
00110 uint len = code.length();
00111
QChar newLine(
'\n');
00112
QChar cr(
'\r');
00113
QChar tab(
'\t');
00114
QString tabstr(
" ");
00115
QString line;
00116 m_lines.clear();
00117
int width = 0;
00118
QFontMetrics metrics(m_font);
00119
00120
for (uint pos = 0; pos < len; pos++) {
00121
QChar c = chars[pos];
00122
if (c == cr) {
00123
if (pos < len-1 && chars[pos+1] == newLine)
00124
continue;
00125
else
00126 c = newLine;
00127 }
00128
if (c == newLine) {
00129 m_lines.append(line);
00130
int lineWidth = metrics.width(line);
00131
if (lineWidth > width)
00132 width = lineWidth;
00133 line =
"";
00134 }
00135
else if (c == tab) {
00136 line += tabstr;
00137 }
00138
else {
00139 line += c;
00140 }
00141 }
00142
if (line.length()) {
00143 m_lines.append(line);
00144
int lineWidth = metrics.width(line);
00145
if (lineWidth > width)
00146 width = lineWidth;
00147 }
00148
00149
int linenoDisplayWidth = metrics.width(
"888888");
00150 resizeContents(linenoDisplayWidth+4+width,metrics.height()*m_lines.count());
00151 update();
00152 sourceFile->deref();
00153 }
00154
00155
void SourceDisplay::setCurrentLine(
int lineno,
bool doCenter)
00156 {
00157 m_currentLine = lineno;
00158
00159
if (doCenter && m_currentLine >= 0) {
00160
QFontMetrics metrics(m_font);
00161
int height = metrics.height();
00162 center(0,height*m_currentLine+height/2);
00163 }
00164
00165 updateContents();
00166 }
00167
00168
void SourceDisplay::contentsMousePressEvent(
QMouseEvent *e)
00169 {
00170 QScrollView::mouseDoubleClickEvent(e);
00171
QFontMetrics metrics(m_font);
00172
int lineno = e->y()/metrics.height();
00173 emit lineDoubleClicked(lineno+1);
00174 }
00175
00176
void SourceDisplay::showEvent(
QShowEvent *)
00177 {
00178 setSource(m_sourceFile);
00179 }
00180
00181
void SourceDisplay::drawContents(
QPainter *p,
int clipx,
int clipy,
int clipw,
int cliph)
00182 {
00183
if (!m_sourceFile) {
00184 p->fillRect(clipx,clipy,clipw,cliph,palette().active().base());
00185
return;
00186 }
00187
00188
QFontMetrics metrics(m_font);
00189
int height = metrics.height();
00190
00191
int bottom = clipy + cliph;
00192
int right = clipx + clipw;
00193
00194
int firstLine = clipy/height-1;
00195
if (firstLine < 0)
00196 firstLine = 0;
00197
int lastLine = bottom/height+2;
00198
if (lastLine > (
int)m_lines.count())
00199 lastLine = m_lines.count();
00200
00201 p->setFont(m_font);
00202
00203
int linenoWidth = metrics.width(
"888888");
00204
00205
for (
int lineno = firstLine; lineno <= lastLine; lineno++) {
00206
QString linenoStr =
QString().sprintf(
"%d",lineno+1);
00207
00208
00209 p->fillRect(0,height*lineno,linenoWidth,height,palette().active().mid());
00210
00211 p->setPen(palette().active().text());
00212 p->drawText(0,height*lineno,linenoWidth,height,Qt::AlignRight,linenoStr);
00213
00214
QColor bgColor;
00215
QColor textColor;
00216
00217
if (lineno == m_currentLine) {
00218 bgColor = palette().active().highlight();
00219 textColor = palette().active().highlightedText();
00220 }
00221
else if (m_debugWin->haveBreakpoint(m_sourceFile,lineno+1,lineno+1)) {
00222 bgColor = palette().active().text();
00223 textColor = palette().active().base();
00224 p->drawPixmap(2,height*lineno+height/2-m_breakpointIcon.height()/2,m_breakpointIcon);
00225 }
00226
else {
00227 bgColor = palette().active().base();
00228 textColor = palette().active().text();
00229 }
00230
00231 p->fillRect(linenoWidth,height*lineno,right-linenoWidth,height,bgColor);
00232 p->setPen(textColor);
00233 p->drawText(linenoWidth+4,height*lineno,contentsWidth()-linenoWidth-4,height,
00234 Qt::AlignLeft,m_lines[lineno]);
00235 }
00236
00237
int remainingTop = height*(lastLine+1);
00238 p->fillRect(0,remainingTop,linenoWidth,bottom-remainingTop,palette().active().mid());
00239
00240 p->fillRect(linenoWidth,remainingTop,
00241 right-linenoWidth,bottom-remainingTop,palette().active().base());
00242 }
00243
00244
00245
00246 KJSDebugWin * KJSDebugWin::kjs_html_debugger = 0;
00247
00248 QString SourceFile::getCode()
00249 {
00250
if (interpreter) {
00251
KHTMLPart *part = static_cast<ScriptInterpreter*>(interpreter)->part();
00252
if (part && url == part->
url().
url() &&
KHTMLPageCache::self()->
isValid(part->
cacheId())) {
00253 Decoder *decoder = part->
createDecoder();
00254
QByteArray data;
00255
QDataStream stream(data,IO_WriteOnly);
00256
KHTMLPageCache::self()->
saveData(part->
cacheId(),&stream);
00257 QString str;
00258
if (data.size() == 0)
00259 str =
"";
00260
else
00261 str = decoder->decode(data.data(),data.size()) + decoder->flush();
00262
delete decoder;
00263
return str;
00264 }
00265 }
00266
00267
return code;
00268 }
00269
00270
00271
00272 SourceFragment::SourceFragment(
int sid,
int bl,
int el, SourceFile *sf)
00273 {
00274 sourceId = sid;
00275 baseLine = bl;
00276 errorLine = el;
00277 sourceFile = sf;
00278 sourceFile->ref();
00279 }
00280
00281 SourceFragment::~SourceFragment()
00282 {
00283 sourceFile->deref();
00284 sourceFile = 0L;
00285 }
00286
00287
00288
00289 KJSErrorDialog::KJSErrorDialog(
QWidget *parent,
const QString& errorMessage,
bool showDebug)
00290 :
KDialogBase(parent,0,true,i18n("JavaScript
Error"),
00291 showDebug ?
KDialogBase::Ok|
KDialogBase::User1 :
KDialogBase::Ok,
00292
KDialogBase::Ok,false,KGuiItem("&Debug","gear"))
00293 {
00294
QWidget *page =
new QWidget(
this);
00295 setMainWidget(page);
00296
00297
QLabel *iconLabel =
new QLabel(
"",page);
00298 iconLabel->setPixmap(KGlobal::iconLoader()->loadIcon(
"messagebox_critical",
00299 KIcon::NoGroup,KIcon::SizeMedium,
00300 KIcon::DefaultState,0,
true));
00301
00302 QWidget *contents =
new QWidget(page);
00303 QLabel *
label =
new QLabel(errorMessage,contents);
00304 m_dontShowAgainCb =
new QCheckBox(i18n(
"&Do not show this message again"),contents);
00305
00306
QVBoxLayout *vl =
new QVBoxLayout(contents,0,spacingHint());
00307 vl->addWidget(label);
00308 vl->addWidget(m_dontShowAgainCb);
00309
00310
QHBoxLayout *topLayout =
new QHBoxLayout(page,0,spacingHint());
00311 topLayout->addWidget(iconLabel);
00312 topLayout->addWidget(contents);
00313 topLayout->addStretch(10);
00314
00315 m_debugSelected =
false;
00316 }
00317
00318 KJSErrorDialog::~KJSErrorDialog()
00319 {
00320 }
00321
00322
void KJSErrorDialog::slotUser1()
00323 {
00324 m_debugSelected =
true;
00325
close();
00326 }
00327
00328
00329 EvalMultiLineEdit::EvalMultiLineEdit(QWidget *parent)
00330 :
QMultiLineEdit(parent) {
00331 }
00332
00333
void EvalMultiLineEdit::keyPressEvent(
QKeyEvent * e)
00334 {
00335
if (e->key() == Qt::Key_Return) {
00336
if (hasSelectedText()) {
00337 m_code = selectedText();
00338 }
else {
00339
int para, index;
00340 getCursorPosition(¶, &index);
00341 m_code = text(para);
00342 }
00343
end();
00344 }
00345 QMultiLineEdit::keyPressEvent(e);
00346 }
00347
00348 KJSDebugWin::KJSDebugWin(QWidget *parent,
const char *name)
00349 :
KMainWindow(parent,
name, WType_TopLevel),
KInstance("kjs_debugger")
00350 {
00351 m_breakpoints = 0;
00352 m_breakpointCount = 0;
00353
00354 m_curSourceFile = 0;
00355 m_mode = Continue;
00356 m_nextSourceUrl =
"";
00357 m_nextSourceBaseLine = 1;
00358 m_execs = 0;
00359 m_execsCount = 0;
00360 m_execsAlloc = 0;
00361 m_steppingDepth = 0;
00362
00363 m_stopIcon =
KGlobal::iconLoader()->
loadIcon(
"stop",KIcon::Small);
00364 m_emptyIcon =
QPixmap(m_stopIcon.width(),m_stopIcon.height());
00365
QBitmap emptyMask(m_stopIcon.width(),m_stopIcon.height(),
true);
00366 m_emptyIcon.setMask(emptyMask);
00367
00368 setCaption(i18n(
"JavaScript Debugger"));
00369
00370 QWidget *mainWidget =
new QWidget(
this);
00371 setCentralWidget(mainWidget);
00372
00373 QVBoxLayout *vl =
new QVBoxLayout(mainWidget,5);
00374
00375
00376
QSplitter *hsplitter =
new QSplitter(Qt::Vertical,mainWidget);
00377 QSplitter *vsplitter =
new QSplitter(hsplitter);
00378
QFont font(KGlobalSettings::fixedFont());
00379
00380 QWidget *contextContainer =
new QWidget(vsplitter);
00381
00382 QLabel *contextLabel =
new QLabel(i18n(
"Call stack"),contextContainer);
00383 QWidget *contextListContainer =
new QWidget(contextContainer);
00384 m_contextList =
new QListBox(contextListContainer);
00385 m_contextList->setMinimumSize(100,200);
00386 connect(m_contextList,SIGNAL(highlighted(
int)),
this,SLOT(slotShowFrame(
int)));
00387
00388 QHBoxLayout *clistLayout =
new QHBoxLayout(contextListContainer);
00389 clistLayout->addWidget(m_contextList);
00390 clistLayout->addSpacing(KDialog::spacingHint());
00391
00392 QVBoxLayout *contextLayout =
new QVBoxLayout(contextContainer);
00393 contextLayout->addWidget(contextLabel);
00394 contextLayout->addSpacing(KDialog::spacingHint());
00395 contextLayout->addWidget(contextListContainer);
00396
00397
00398 QWidget *sourceSelDisplay =
new QWidget(vsplitter);
00399 QVBoxLayout *ssdvl =
new QVBoxLayout(sourceSelDisplay);
00400
00401 m_sourceSel =
new QComboBox(toolBar());
00402 connect(m_sourceSel,SIGNAL(activated(
int)),
this,SLOT(slotSourceSelected(
int)));
00403
00404 m_sourceDisplay =
new SourceDisplay(
this,sourceSelDisplay);
00405 ssdvl->addWidget(m_sourceDisplay);
00406 connect(m_sourceDisplay,SIGNAL(lineDoubleClicked(
int)),SLOT(slotToggleBreakpoint(
int)));
00407
00408
QValueList<int> vsplitSizes;
00409 vsplitSizes.insert(vsplitSizes.end(),120);
00410 vsplitSizes.insert(vsplitSizes.end(),480);
00411 vsplitter->setSizes(vsplitSizes);
00412
00413
00414
00415 QWidget *evalContainer =
new QWidget(hsplitter);
00416
00417 QLabel *evalLabel =
new QLabel(i18n(
"JavaScript console"),evalContainer);
00418 m_evalEdit =
new EvalMultiLineEdit(evalContainer);
00419 m_evalEdit->setWordWrap(QMultiLineEdit::NoWrap);
00420 m_evalEdit->setFont(font);
00421 connect(m_evalEdit,SIGNAL(returnPressed()),SLOT(slotEval()));
00422 m_evalDepth = 0;
00423
00424 QVBoxLayout *evalLayout =
new QVBoxLayout(evalContainer);
00425 evalLayout->addSpacing(KDialog::spacingHint());
00426 evalLayout->addWidget(evalLabel);
00427 evalLayout->addSpacing(KDialog::spacingHint());
00428 evalLayout->addWidget(m_evalEdit);
00429
00430
QValueList<int> hsplitSizes;
00431 hsplitSizes.insert(hsplitSizes.end(),400);
00432 hsplitSizes.insert(hsplitSizes.end(),200);
00433 hsplitter->setSizes(hsplitSizes);
00434
00435 vl->addWidget(hsplitter);
00436
00437
00438
KPopupMenu *debugMenu =
new KPopupMenu(
this);
00439 menuBar()->insertItem(
"&Debug",debugMenu);
00440
00441 m_actionCollection =
new KActionCollection(
this);
00442 m_actionCollection->setInstance(
this);
00443 m_nextAction =
new KAction(i18n(
"&Next"),
"dbgnext",
KShortcut(),
this,SLOT(slotNext()),
00444 m_actionCollection,
"next");
00445 m_stepAction =
new KAction(i18n(
"&Step"),
"dbgstep",
KShortcut(),
this,SLOT(slotStep()),
00446 m_actionCollection,
"step");
00447 m_continueAction =
new KAction(i18n(
"&Continue"),
"dbgrun",
KShortcut(),
this,SLOT(slotContinue()),
00448 m_actionCollection,
"cont");
00449 m_stopAction =
new KAction(i18n(
"St&op"),
"stop",
KShortcut(),
this,SLOT(slotStop()),
00450 m_actionCollection,
"stop");
00451 m_breakAction =
new KAction(i18n(
"&Break at Next Statement"),
"dbgrunto",
KShortcut(),
this,SLOT(slotBreakNext()),
00452 m_actionCollection,
"breaknext");
00453
00454 m_nextAction->setToolTip(i18n(
"Next"));
00455 m_stepAction->setToolTip(i18n(
"Step"));
00456 m_continueAction->setToolTip(i18n(
"Continue"));
00457 m_stopAction->setToolTip(i18n(
"Stop"));
00458 m_breakAction->setToolTip(
"Break at next Statement");
00459
00460 m_nextAction->setEnabled(
false);
00461 m_stepAction->setEnabled(
false);
00462 m_continueAction->setEnabled(
false);
00463 m_stopAction->setEnabled(
false);
00464 m_breakAction->setEnabled(
true);
00465
00466 m_nextAction->plug(debugMenu);
00467 m_stepAction->plug(debugMenu);
00468 m_continueAction->plug(debugMenu);
00469
00470 m_breakAction->plug(debugMenu);
00471
00472 m_nextAction->plug(toolBar());
00473 m_stepAction->plug(toolBar());
00474 m_continueAction->plug(toolBar());
00475
00476 m_breakAction->plug(toolBar());
00477
00478 toolBar()->insertWidget(1,300,m_sourceSel);
00479 toolBar()->setItemAutoSized(1);
00480
00481 updateContextList();
00482 setMinimumSize(300,200);
00483 resize(600,450);
00484
00485 }
00486
00487 KJSDebugWin::~KJSDebugWin()
00488 {
00489 free(m_breakpoints);
00490 free(m_execs);
00491 }
00492
00493 KJSDebugWin *KJSDebugWin::createInstance()
00494 {
00495 assert(!kjs_html_debugger);
00496 kjs_html_debugger =
new KJSDebugWin();
00497
return kjs_html_debugger;
00498 }
00499
00500
void KJSDebugWin::destroyInstance()
00501 {
00502 assert(kjs_html_debugger);
00503 kjs_html_debugger->hide();
00504
delete kjs_html_debugger;
00505 }
00506
00507
void KJSDebugWin::slotNext()
00508 {
00509 m_mode = Next;
00510 leaveSession();
00511 }
00512
00513
void KJSDebugWin::slotStep()
00514 {
00515 m_mode = Step;
00516 leaveSession();
00517 }
00518
00519
void KJSDebugWin::slotContinue()
00520 {
00521 m_mode = Continue;
00522 leaveSession();
00523 }
00524
00525
void KJSDebugWin::slotStop()
00526 {
00527 m_mode = Stop;
00528
while (!m_execStates.isEmpty())
00529 leaveSession();
00530 }
00531
00532
void KJSDebugWin::slotBreakNext()
00533 {
00534 m_mode = Step;
00535 }
00536
00537
void KJSDebugWin::slotToggleBreakpoint(
int lineno)
00538 {
00539
if (m_sourceSel->currentItem() < 0)
00540
return;
00541
00542 SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem());
00543
00544
00545
int sourceId = -1;
00546
int highestBaseLine = -1;
00547
QMap<int,SourceFragment*>::Iterator it;
00548
00549
for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it) {
00550 SourceFragment *sourceFragment = it.data();
00551
if (sourceFragment &&
00552 sourceFragment->sourceFile == sourceFile &&
00553 sourceFragment->baseLine <= lineno &&
00554 sourceFragment->baseLine > highestBaseLine) {
00555
00556 sourceId = sourceFragment->sourceId;
00557 highestBaseLine = sourceFragment->baseLine;
00558 }
00559 }
00560
00561
if (sourceId < 0)
00562
return;
00563
00564
00565
int fragmentLineno = lineno-highestBaseLine+1;
00566
if (!setBreakpoint(sourceId,fragmentLineno))
00567 deleteBreakpoint(sourceId,fragmentLineno);
00568
00569 m_sourceDisplay->updateContents();
00570 }
00571
00572
void KJSDebugWin::slotShowFrame(
int frameno)
00573 {
00574
if (frameno < 0 || frameno >= m_execsCount)
00575
return;
00576
00577 Context ctx = m_execs[frameno]->context();
00578 setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine());
00579 }
00580
00581
void KJSDebugWin::slotSourceSelected(
int sourceSelIndex)
00582 {
00583
00584
if (sourceSelIndex < 0 || sourceSelIndex >= (
int)m_sourceSel->count())
00585
return;
00586 SourceFile *sourceFile = m_sourceSelFiles.at(sourceSelIndex);
00587 displaySourceFile(sourceFile,
true);
00588
00589
00590
00591
if (m_contextList->currentItem() >= 0) {
00592 Context ctx = m_execs[m_contextList->currentItem()]->context();
00593
if (m_sourceFragments[ctx.sourceId()]->sourceFile == m_sourceSelFiles.at(sourceSelIndex))
00594 setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine());
00595 }
00596 }
00597
00598
void KJSDebugWin::slotEval()
00599 {
00600
00601
00602
00603 ExecState *exec;
00604 Object thisobj;
00605
if (m_execStates.isEmpty()) {
00606
if (m_sourceSel->currentItem() < 0)
00607
return;
00608 SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem());
00609
if (!sourceFile->interpreter)
00610
return;
00611 exec = sourceFile->interpreter->globalExec();
00612 thisobj = exec->interpreter()->globalObject();
00613 }
00614
else {
00615 exec = m_execStates.top();
00616 thisobj = exec->context().thisValue();
00617 }
00618
00619
00620 UString code(m_evalEdit->code());
00621 QString msg;
00622
00623 KJSCPUGuard guard;
00624 guard.start();
00625
00626 Interpreter *interp = exec->interpreter();
00627
00628 Object obj = Object::dynamicCast(interp->globalObject().get(exec,
"eval"));
00629 List args;
00630 args.append(String(code));
00631
00632 m_evalDepth++;
00633 Value retval = obj.call(exec, thisobj, args);
00634 m_evalDepth--;
00635 guard.stop();
00636
00637
00638
if (exec->hadException()) {
00639 Value exc = exec->exception();
00640 exec->clearException();
00641 msg =
"Exception: " + exc.toString(interp->globalExec()).qstring();
00642 }
00643
else {
00644 msg = retval.toString(interp->globalExec()).qstring();
00645 }
00646
00647 m_evalEdit->insert(msg+
"\n");
00648 updateContextList();
00649 }
00650
00651
void KJSDebugWin::closeEvent(
QCloseEvent *e)
00652 {
00653
while (!m_execStates.isEmpty())
00654 leaveSession();
00655
return QWidget::closeEvent(e);
00656 }
00657
00658
bool KJSDebugWin::eventFilter(
QObject *o,
QEvent *e)
00659 {
00660
switch (e->type()) {
00661
case QEvent::MouseButtonPress:
00662
case QEvent::MouseButtonRelease:
00663
case QEvent::MouseButtonDblClick:
00664
case QEvent::MouseMove:
00665
case QEvent::KeyPress:
00666
case QEvent::KeyRelease:
00667
case QEvent::Destroy:
00668
case QEvent::Close:
00669
case QEvent::Quit:
00670
while (o->parent())
00671 o = o->parent();
00672
if (o ==
this)
00673
return QWidget::eventFilter(o,e);
00674
else
00675
return true;
00676
break;
00677
default:
00678
return QWidget::eventFilter(o,e);
00679 }
00680 }
00681
00682
void KJSDebugWin::disableOtherWindows()
00683 {
00684 QWidgetList *widgets = QApplication::allWidgets();
00685 QWidgetListIt it(*widgets);
00686
for (; it.current(); ++it)
00687 it.current()->installEventFilter(
this);
00688 }
00689
00690
void KJSDebugWin::enableOtherWindows()
00691 {
00692 QWidgetList *widgets = QApplication::allWidgets();
00693 QWidgetListIt it(*widgets);
00694
for (; it.current(); ++it)
00695 it.current()->removeEventFilter(
this);
00696 }
00697
00698
bool KJSDebugWin::sourceParsed(KJS::ExecState *exec,
int sourceId,
00699
const KJS::UString &source,
int errorLine)
00700 {
00701
00702 SourceFile *sourceFile = 0;
00703
if (!m_nextSourceUrl.isEmpty())
00704 sourceFile = getSourceFile(exec->interpreter(),m_nextSourceUrl);
00705
00706
int index;
00707
if (!sourceFile) {
00708 index = m_sourceSel->count();
00709
if (!m_nextSourceUrl.isEmpty()) {
00710
00711 QString code = source.qstring();
00712
KHTMLPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part();
00713
if (m_nextSourceUrl == part->
url().
url()) {
00714
00715
00716 code = QString::null;
00717 }
00718
00719 sourceFile =
new SourceFile(m_nextSourceUrl,code,exec->interpreter());
00720 setSourceFile(exec->interpreter(),m_nextSourceUrl,sourceFile);
00721 m_sourceSelFiles.append(sourceFile);
00722 m_sourceSel->insertItem(m_nextSourceUrl);
00723 }
00724
else {
00725
00726
00727 sourceFile =
new SourceFile(
"(unknown)",source.qstring(),exec->interpreter());
00728 m_sourceSelFiles.append(sourceFile);
00729 m_sourceSel->insertItem(
"???");
00730 }
00731 }
00732
else {
00733
for (index = 0; index < m_sourceSel->count(); index++) {
00734
if (m_sourceSelFiles.at(index) == sourceFile)
00735
break;
00736 }
00737 assert(index < m_sourceSel->count());
00738 }
00739
00740 SourceFragment *sf =
new SourceFragment(sourceId,m_nextSourceBaseLine,errorLine,sourceFile);
00741 m_sourceFragments[sourceId] = sf;
00742
00743
if (m_sourceSel->currentItem() < 0)
00744 m_sourceSel->setCurrentItem(index);
00745
00746
if (m_sourceSel->currentItem() == index) {
00747 displaySourceFile(sourceFile,
true);
00748 }
00749
00750 m_nextSourceBaseLine = 1;
00751 m_nextSourceUrl =
"";
00752
00753
return (m_mode != Stop);
00754 }
00755
00756
bool KJSDebugWin::sourceUnused(KJS::ExecState *exec,
int sourceId)
00757 {
00758
00759
00760
00761
for (
int e = 0; e < m_execsCount; e++)
00762 assert(m_execs[e]->context().sourceId() != sourceId);
00763
00764
00765 SourceFragment *fragment = m_sourceFragments[sourceId];
00766
if (fragment) {
00767 m_sourceFragments.erase(sourceId);
00768
00769 SourceFile *sourceFile = fragment->sourceFile;
00770
if (sourceFile->hasOneRef()) {
00771
for (
int i = 0; i < m_sourceSel->count(); i++) {
00772
if (m_sourceSelFiles.at(i) == sourceFile) {
00773 m_sourceSel->removeItem(i);
00774 m_sourceSelFiles.remove(i);
00775
break;
00776 }
00777 }
00778 removeSourceFile(exec->interpreter(),sourceFile->url);
00779 }
00780
delete fragment;
00781 }
00782
00783
return (m_mode != Stop);
00784 }
00785
00786
bool KJSDebugWin::exception(ExecState *exec,
const Value &value,
bool inTryCatch)
00787 {
00788 assert(value.isValid());
00789
00790
00791
if (inTryCatch)
00792
return true;
00793
00794
KHTMLPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part();
00795
if (!part->
settings()->
isJavaScriptErrorReportingEnabled())
00796
return true;
00797
00798 QWidget *dlgParent = (m_evalDepth == 0) ? (QWidget*)part->
view() : (QWidget*)this;
00799
00800 QString exceptionMsg = value.toString(exec).qstring();
00801
00802
00803
00804
00805 Object valueObj = Object::dynamicCast(value);
00806 Object syntaxError = exec->interpreter()->builtinSyntaxError();
00807
if (valueObj.isValid() && valueObj.get(exec,
"constructor").imp() == syntaxError.imp()) {
00808 Value sidValue = valueObj.get(exec,
"sid");
00809
if (sidValue.isA(NumberType)) {
00810
int sourceId = (
int)sidValue.toNumber(exec);
00811 assert(m_sourceFragments[sourceId]);
00812 exceptionMsg = i18n(
"Parse error at %1 line %2")
00813 .arg(m_sourceFragments[sourceId]->sourceFile->url)
00814 .arg(m_sourceFragments[sourceId]->baseLine+m_sourceFragments[sourceId]->errorLine-1);
00815 }
00816 }
00817
00818
bool dontShowAgain =
false;
00819
if (m_execsCount == 0) {
00820
00821
00822
00823 QString msg = i18n(
"An error occurred while attempting to run a script on this page.\n\n%1")
00824 .arg(exceptionMsg);
00825 KJSErrorDialog dlg(dlgParent,msg,
false);
00826 dlg.exec();
00827 dontShowAgain = dlg.dontShowAgain();
00828 }
00829
else {
00830 Context ctx = m_execs[m_execsCount-1]->context();
00831 SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()];
00832 QString msg = i18n(
"An error occurred while attempting to run a script on this page.\n\n%1 line %2:\n%3")
00833 .arg(sourceFragment->sourceFile->url)
00834 .arg(sourceFragment->baseLine+ctx.curStmtFirstLine()-1)
00835 .arg(exceptionMsg);
00836
00837 KJSErrorDialog dlg(dlgParent,msg,
true);
00838 dlg.exec();
00839 dontShowAgain = dlg.dontShowAgain();
00840
00841
if (dlg.debugSelected()) {
00842 m_mode = Next;
00843 m_steppingDepth = m_execsCount-1;
00844 enterSession(exec);
00845 }
00846 }
00847
00848
if (dontShowAgain) {
00849
KConfig *config = kapp->config();
00850
KConfigGroupSaver saver(config,QString::fromLatin1(
"Java/JavaScript Settings"));
00851 config->
writeEntry(
"ReportJavaScriptErrors",
QVariant(
false,0));
00852 config->
sync();
00853
QByteArray data;
00854 kapp->dcopClient()->send(
"konqueror*",
"KonquerorIface",
"reparseConfiguration()", data );
00855 }
00856
00857
return (m_mode != Stop);
00858 }
00859
00860
bool KJSDebugWin::atStatement(KJS::ExecState *exec)
00861 {
00862 assert(m_execsCount > 0);
00863 assert(m_execs[m_execsCount-1] == exec);
00864 checkBreak(exec);
00865
return (m_mode != Stop);
00866 }
00867
00868
bool KJSDebugWin::enterContext(ExecState *exec)
00869 {
00870
if (m_execsCount >= m_execsAlloc) {
00871 m_execsAlloc += 10;
00872 m_execs = (ExecState**)realloc(m_execs,m_execsAlloc*
sizeof(ExecState*));
00873 }
00874 m_execs[m_execsCount++] = exec;
00875
00876
if (m_mode == Step)
00877 m_steppingDepth = m_execsCount-1;
00878
00879 checkBreak(exec);
00880
return (m_mode != Stop);
00881 }
00882
00883
bool KJSDebugWin::exitContext(ExecState *exec,
const Completion &)
00884 {
00885 assert(m_execsCount > 0);
00886 assert(m_execs[m_execsCount-1] == exec);
00887
00888 checkBreak(exec);
00889
00890 m_execsCount--;
00891
if (m_steppingDepth > m_execsCount-1)
00892 m_steppingDepth = m_execsCount-1;
00893
if (m_execsCount == 0)
00894 updateContextList();
00895
00896
return (m_mode != Stop);
00897 }
00898
00899
void KJSDebugWin::displaySourceFile(SourceFile *sourceFile,
bool forceRefresh)
00900 {
00901
if (m_curSourceFile == sourceFile && !forceRefresh)
00902
return;
00903 sourceFile->ref();
00904 m_sourceDisplay->setSource(sourceFile);
00905
if (m_curSourceFile)
00906 m_curSourceFile->deref();
00907 m_curSourceFile = sourceFile;
00908 }
00909
00910
void KJSDebugWin::setSourceLine(
int sourceId,
int lineno)
00911 {
00912 SourceFragment *source = m_sourceFragments[sourceId];
00913
if (!source)
00914
return;
00915
00916 SourceFile *sourceFile = source->sourceFile;
00917
if (m_curSourceFile != source->sourceFile) {
00918
for (
int i = 0; i < m_sourceSel->count(); i++)
00919
if (m_sourceSelFiles.at(i) == sourceFile)
00920 m_sourceSel->setCurrentItem(i);
00921 displaySourceFile(sourceFile,
false);
00922 }
00923 m_sourceDisplay->setCurrentLine(source->baseLine+lineno-2);
00924 }
00925
00926
void KJSDebugWin::setNextSourceInfo(QString url,
int baseLine)
00927 {
00928 m_nextSourceUrl = url;
00929 m_nextSourceBaseLine = baseLine;
00930 }
00931
00932
void KJSDebugWin::sourceChanged(Interpreter *interpreter, QString url)
00933 {
00934 SourceFile *sourceFile = getSourceFile(interpreter,url);
00935
if (sourceFile && m_curSourceFile == sourceFile)
00936 displaySourceFile(sourceFile,
true);
00937 }
00938
00939
void KJSDebugWin::clearInterpreter(Interpreter *interpreter)
00940 {
00941
QMap<int,SourceFragment*>::Iterator it;
00942
00943
for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it)
00944
if (it.data() && it.data()->sourceFile->interpreter == interpreter)
00945 it.data()->sourceFile->interpreter = 0;
00946 }
00947
00948 SourceFile *KJSDebugWin::getSourceFile(Interpreter *interpreter, QString url)
00949 {
00950 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00951
return m_sourceFiles[
key];
00952 }
00953
00954
void KJSDebugWin::setSourceFile(Interpreter *interpreter, QString url, SourceFile *sourceFile)
00955 {
00956 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00957 m_sourceFiles[
key] = sourceFile;
00958 }
00959
00960
void KJSDebugWin::removeSourceFile(Interpreter *interpreter, QString url)
00961 {
00962 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00963 m_sourceFiles.remove(key);
00964 }
00965
00966
void KJSDebugWin::checkBreak(ExecState *exec)
00967 {
00968
if (m_breakpointCount > 0) {
00969 Context ctx = m_execs[m_execsCount-1]->context();
00970
if (haveBreakpoint(ctx.sourceId(),ctx.curStmtFirstLine(),ctx.curStmtLastLine())) {
00971 m_mode = Next;
00972 m_steppingDepth = m_execsCount-1;
00973 }
00974 }
00975
00976
if ((m_mode == Step || m_mode == Next) && m_steppingDepth == m_execsCount-1)
00977 enterSession(exec);
00978 }
00979
00980
void KJSDebugWin::enterSession(ExecState *exec)
00981 {
00982
00983
00984
00985
00986
00987
if (!isVisible())
00988 show();
00989
00990 m_mode = Continue;
00991
00992
if (m_execStates.isEmpty()) {
00993 disableOtherWindows();
00994 m_nextAction->setEnabled(
true);
00995 m_stepAction->setEnabled(
true);
00996 m_continueAction->setEnabled(
true);
00997 m_stopAction->setEnabled(
true);
00998 m_breakAction->setEnabled(
false);
00999 }
01000 m_execStates.push(exec);
01001
01002 updateContextList();
01003
01004 qApp->enter_loop();
01005 }
01006
01007
void KJSDebugWin::leaveSession()
01008 {
01009
01010
01011
01012
01013 assert(!m_execStates.isEmpty());
01014
01015 m_execStates.pop();
01016
01017
if (m_execStates.isEmpty()) {
01018 m_nextAction->setEnabled(
false);
01019 m_stepAction->setEnabled(
false);
01020 m_continueAction->setEnabled(
false);
01021 m_stopAction->setEnabled(
false);
01022 m_breakAction->setEnabled(
true);
01023 m_sourceDisplay->setCurrentLine(-1);
01024 enableOtherWindows();
01025 }
01026
01027 qApp->exit_loop();
01028 }
01029
01030
void KJSDebugWin::updateContextList()
01031 {
01032 disconnect(m_contextList,SIGNAL(highlighted(
int)),
this,SLOT(slotShowFrame(
int)));
01033
01034 m_contextList->clear();
01035
for (
int i = 0; i < m_execsCount; i++)
01036 m_contextList->insertItem(contextStr(m_execs[i]->context()));
01037
01038
if (m_execsCount > 0) {
01039 m_contextList->setSelected(m_execsCount-1,
true);
01040 Context ctx = m_execs[m_execsCount-1]->context();
01041 setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine());
01042 }
01043
01044 connect(m_contextList,SIGNAL(highlighted(
int)),
this,SLOT(slotShowFrame(
int)));
01045 }
01046
01047 QString KJSDebugWin::contextStr(
const Context &ctx)
01048 {
01049 QString str =
"";
01050 SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()];
01051 QString url = sourceFragment->sourceFile->url;
01052
int fileLineno = sourceFragment->baseLine+ctx.curStmtFirstLine()-1;
01053
01054
switch (ctx.codeType()) {
01055
case GlobalCode:
01056 str = QString(
"Global code at %1:%2").arg(url).arg(fileLineno);
01057
break;
01058
case EvalCode:
01059 str = QString(
"Eval code at %1:%2").arg(url).arg(fileLineno);
01060
break;
01061
case FunctionCode:
01062
if (!ctx.functionName().isNull())
01063 str = QString(
"%1() at %2:%3").arg(ctx.functionName().qstring()).arg(url).arg(fileLineno);
01064
else
01065 str = QString(
"Anonymous function at %1:%2").arg(url).arg(fileLineno);
01066
break;
01067 }
01068
01069
return str;
01070 }
01071
01072
bool KJSDebugWin::setBreakpoint(
int sourceId,
int lineno)
01073 {
01074
if (haveBreakpoint(sourceId,lineno,lineno))
01075
return false;
01076
01077 m_breakpointCount++;
01078 m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints,
01079 m_breakpointCount*
sizeof(Breakpoint)));
01080 m_breakpoints[m_breakpointCount-1].sourceId = sourceId;
01081 m_breakpoints[m_breakpointCount-1].lineno = lineno;
01082
01083
return true;
01084 }
01085
01086
bool KJSDebugWin::deleteBreakpoint(
int sourceId,
int lineno)
01087 {
01088
for (
int i = 0; i < m_breakpointCount; i++) {
01089
if (m_breakpoints[i].sourceId == sourceId && m_breakpoints[i].lineno == lineno) {
01090
01091 memmove(m_breakpoints+i,m_breakpoints+i+1,(m_breakpointCount-i-1)*
sizeof(Breakpoint));
01092 m_breakpointCount--;
01093 m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints,
01094 m_breakpointCount*
sizeof(Breakpoint)));
01095
return true;
01096 }
01097 }
01098
01099
return false;
01100 }
01101
01102
bool KJSDebugWin::haveBreakpoint(SourceFile *sourceFile,
int line0,
int line1)
01103 {
01104
for (
int i = 0; i < m_breakpointCount; i++) {
01105
int sourceId = m_breakpoints[i].sourceId;
01106
int lineno = m_breakpoints[i].lineno;
01107
if (m_sourceFragments.contains(sourceId) &&
01108 m_sourceFragments[sourceId]->sourceFile == sourceFile) {
01109
int absLineno = m_sourceFragments[sourceId]->baseLine+lineno-1;
01110
if (absLineno >= line0 && absLineno <= line1)
01111
return true;
01112 }
01113 }
01114
01115
return false;
01116 }
01117
01118
#include "kjs_debugwin.moc"
01119
01120
#endif // KJS_DEBUGGER