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