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 = ::qt_cast<KHTMLPart*>(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 breakpoint",
"&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 breakpoint",
"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
KParts::ReadOnlyPart *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
KParts::ReadOnlyPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part();
00796
KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart*>(part);
00797
if (khtmlpart && !khtmlpart->
settings()->
isJavaScriptErrorReportingEnabled())
00798
return true;
00799
00800 QWidget *dlgParent = (m_evalDepth == 0) ? (QWidget*)part->
widget() : (QWidget*)this;
00801
00802 QString exceptionMsg = value.toString(exec).qstring();
00803
00804
00805
00806
00807 Object valueObj = Object::dynamicCast(value);
00808 Object syntaxError = exec->interpreter()->builtinSyntaxError();
00809
if (valueObj.isValid() && valueObj.get(exec,
"constructor").imp() == syntaxError.imp()) {
00810 Value sidValue = valueObj.get(exec,
"sid");
00811
if (sidValue.isA(NumberType)) {
00812
int sourceId = (
int)sidValue.toNumber(exec);
00813 assert(m_sourceFragments[sourceId]);
00814 exceptionMsg = i18n(
"Parse error at %1 line %2")
00815 .arg(m_sourceFragments[sourceId]->sourceFile->url)
00816 .arg(m_sourceFragments[sourceId]->baseLine+m_sourceFragments[sourceId]->errorLine-1);
00817 }
00818 }
00819
00820
bool dontShowAgain =
false;
00821
if (m_execsCount == 0) {
00822
00823
00824
00825 QString msg = i18n(
"An error occurred while attempting to run a script on this page.\n\n%1")
00826 .arg(exceptionMsg);
00827 KJSErrorDialog dlg(dlgParent,msg,
false);
00828 dlg.exec();
00829 dontShowAgain = dlg.dontShowAgain();
00830 }
00831
else {
00832 Context ctx = m_execs[m_execsCount-1]->context();
00833 SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()];
00834 QString msg = i18n(
"An error occurred while attempting to run a script on this page.\n\n%1 line %2:\n%3")
00835 .arg(KStringHandler::rsqueeze( sourceFragment->sourceFile->url,80),
00836 QString::number( sourceFragment->baseLine+ctx.curStmtFirstLine()-1),
00837 exceptionMsg);
00838
00839 KJSErrorDialog dlg(dlgParent,msg,
true);
00840 dlg.exec();
00841 dontShowAgain = dlg.dontShowAgain();
00842
00843
if (dlg.debugSelected()) {
00844 m_mode = Next;
00845 m_steppingDepth = m_execsCount-1;
00846 enterSession(exec);
00847 }
00848 }
00849
00850
if (dontShowAgain) {
00851
KConfig *config = kapp->config();
00852
KConfigGroupSaver saver(config,QString::fromLatin1(
"Java/JavaScript Settings"));
00853 config->
writeEntry(
"ReportJavaScriptErrors",
QVariant(
false,0));
00854 config->
sync();
00855
QByteArray data;
00856 kapp->dcopClient()->send(
"konqueror*",
"KonquerorIface",
"reparseConfiguration()", data );
00857 }
00858
00859
return (m_mode != Stop);
00860 }
00861
00862
bool KJSDebugWin::atStatement(KJS::ExecState *exec)
00863 {
00864 assert(m_execsCount > 0);
00865 assert(m_execs[m_execsCount-1] == exec);
00866 checkBreak(exec);
00867
return (m_mode != Stop);
00868 }
00869
00870
bool KJSDebugWin::enterContext(ExecState *exec)
00871 {
00872
if (m_execsCount >= m_execsAlloc) {
00873 m_execsAlloc += 10;
00874 m_execs = (ExecState**)realloc(m_execs,m_execsAlloc*
sizeof(ExecState*));
00875 }
00876 m_execs[m_execsCount++] = exec;
00877
00878
if (m_mode == Step)
00879 m_steppingDepth = m_execsCount-1;
00880
00881 checkBreak(exec);
00882
return (m_mode != Stop);
00883 }
00884
00885
bool KJSDebugWin::exitContext(ExecState *exec,
const Completion &)
00886 {
00887 assert(m_execsCount > 0);
00888 assert(m_execs[m_execsCount-1] == exec);
00889
00890 checkBreak(exec);
00891
00892 m_execsCount--;
00893
if (m_steppingDepth > m_execsCount-1)
00894 m_steppingDepth = m_execsCount-1;
00895
if (m_execsCount == 0)
00896 updateContextList();
00897
00898
return (m_mode != Stop);
00899 }
00900
00901
void KJSDebugWin::displaySourceFile(SourceFile *sourceFile,
bool forceRefresh)
00902 {
00903
if (m_curSourceFile == sourceFile && !forceRefresh)
00904
return;
00905 sourceFile->ref();
00906 m_sourceDisplay->setSource(sourceFile);
00907
if (m_curSourceFile)
00908 m_curSourceFile->deref();
00909 m_curSourceFile = sourceFile;
00910 }
00911
00912
void KJSDebugWin::setSourceLine(
int sourceId,
int lineno)
00913 {
00914 SourceFragment *source = m_sourceFragments[sourceId];
00915
if (!source)
00916
return;
00917
00918 SourceFile *sourceFile = source->sourceFile;
00919
if (m_curSourceFile != source->sourceFile) {
00920
for (
int i = 0; i < m_sourceSel->count(); i++)
00921
if (m_sourceSelFiles.at(i) == sourceFile)
00922 m_sourceSel->setCurrentItem(i);
00923 displaySourceFile(sourceFile,
false);
00924 }
00925 m_sourceDisplay->setCurrentLine(source->baseLine+lineno-2);
00926 }
00927
00928
void KJSDebugWin::setNextSourceInfo(QString url,
int baseLine)
00929 {
00930 m_nextSourceUrl = url;
00931 m_nextSourceBaseLine = baseLine;
00932 }
00933
00934
void KJSDebugWin::sourceChanged(Interpreter *interpreter, QString url)
00935 {
00936 SourceFile *sourceFile = getSourceFile(interpreter,url);
00937
if (sourceFile && m_curSourceFile == sourceFile)
00938 displaySourceFile(sourceFile,
true);
00939 }
00940
00941
void KJSDebugWin::clearInterpreter(Interpreter *interpreter)
00942 {
00943
QMap<int,SourceFragment*>::Iterator it;
00944
00945
for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it)
00946
if (it.data() && it.data()->sourceFile->interpreter == interpreter)
00947 it.data()->sourceFile->interpreter = 0;
00948 }
00949
00950 SourceFile *KJSDebugWin::getSourceFile(Interpreter *interpreter, QString url)
00951 {
00952 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00953
return m_sourceFiles[
key];
00954 }
00955
00956
void KJSDebugWin::setSourceFile(Interpreter *interpreter, QString url, SourceFile *sourceFile)
00957 {
00958 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00959 m_sourceFiles[
key] = sourceFile;
00960 }
00961
00962
void KJSDebugWin::removeSourceFile(Interpreter *interpreter, QString url)
00963 {
00964 QString
key = QString(
"%1|%2").arg((
long)interpreter).arg(url);
00965 m_sourceFiles.remove(key);
00966 }
00967
00968
void KJSDebugWin::checkBreak(ExecState *exec)
00969 {
00970
if (m_breakpointCount > 0) {
00971 Context ctx = m_execs[m_execsCount-1]->context();
00972
if (haveBreakpoint(ctx.sourceId(),ctx.curStmtFirstLine(),ctx.curStmtLastLine())) {
00973 m_mode = Next;
00974 m_steppingDepth = m_execsCount-1;
00975 }
00976 }
00977
00978
if ((m_mode == Step || m_mode == Next) && m_steppingDepth == m_execsCount-1)
00979 enterSession(exec);
00980 }
00981
00982
void KJSDebugWin::enterSession(ExecState *exec)
00983 {
00984
00985
00986
00987
00988
00989
if (!isVisible())
00990 show();
00991
00992 m_mode = Continue;
00993
00994
if (m_execStates.isEmpty()) {
00995 disableOtherWindows();
00996 m_nextAction->setEnabled(
true);
00997 m_stepAction->setEnabled(
true);
00998 m_continueAction->setEnabled(
true);
00999 m_stopAction->setEnabled(
true);
01000 m_breakAction->setEnabled(
false);
01001 }
01002 m_execStates.push(exec);
01003
01004 updateContextList();
01005
01006 qApp->enter_loop();
01007 }
01008
01009
void KJSDebugWin::leaveSession()
01010 {
01011
01012
01013
01014
01015 assert(!m_execStates.isEmpty());
01016
01017 m_execStates.pop();
01018
01019
if (m_execStates.isEmpty()) {
01020 m_nextAction->setEnabled(
false);
01021 m_stepAction->setEnabled(
false);
01022 m_continueAction->setEnabled(
false);
01023 m_stopAction->setEnabled(
false);
01024 m_breakAction->setEnabled(
true);
01025 m_sourceDisplay->setCurrentLine(-1);
01026 enableOtherWindows();
01027 }
01028
01029 qApp->exit_loop();
01030 }
01031
01032
void KJSDebugWin::updateContextList()
01033 {
01034 disconnect(m_contextList,SIGNAL(highlighted(
int)),
this,SLOT(slotShowFrame(
int)));
01035
01036 m_contextList->clear();
01037
for (
int i = 0; i < m_execsCount; i++)
01038 m_contextList->insertItem(contextStr(m_execs[i]->context()));
01039
01040
if (m_execsCount > 0) {
01041 m_contextList->setSelected(m_execsCount-1,
true);
01042 Context ctx = m_execs[m_execsCount-1]->context();
01043 setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine());
01044 }
01045
01046 connect(m_contextList,SIGNAL(highlighted(
int)),
this,SLOT(slotShowFrame(
int)));
01047 }
01048
01049 QString KJSDebugWin::contextStr(
const Context &ctx)
01050 {
01051 QString str =
"";
01052 SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()];
01053 QString url = sourceFragment->sourceFile->url;
01054
int fileLineno = sourceFragment->baseLine+ctx.curStmtFirstLine()-1;
01055
01056
switch (ctx.codeType()) {
01057
case GlobalCode:
01058 str = QString(
"Global code at %1:%2").arg(url).arg(fileLineno);
01059
break;
01060
case EvalCode:
01061 str = QString(
"Eval code at %1:%2").arg(url).arg(fileLineno);
01062
break;
01063
case FunctionCode:
01064
if (!ctx.functionName().isNull())
01065 str = QString(
"%1() at %2:%3").arg(ctx.functionName().qstring()).arg(url).arg(fileLineno);
01066
else
01067 str = QString(
"Anonymous function at %1:%2").arg(url).arg(fileLineno);
01068
break;
01069 }
01070
01071
return str;
01072 }
01073
01074
bool KJSDebugWin::setBreakpoint(
int sourceId,
int lineno)
01075 {
01076
if (haveBreakpoint(sourceId,lineno,lineno))
01077
return false;
01078
01079 m_breakpointCount++;
01080 m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints,
01081 m_breakpointCount*
sizeof(Breakpoint)));
01082 m_breakpoints[m_breakpointCount-1].sourceId = sourceId;
01083 m_breakpoints[m_breakpointCount-1].lineno = lineno;
01084
01085
return true;
01086 }
01087
01088
bool KJSDebugWin::deleteBreakpoint(
int sourceId,
int lineno)
01089 {
01090
for (
int i = 0; i < m_breakpointCount; i++) {
01091
if (m_breakpoints[i].sourceId == sourceId && m_breakpoints[i].lineno == lineno) {
01092
01093 memmove(m_breakpoints+i,m_breakpoints+i+1,(m_breakpointCount-i-1)*
sizeof(Breakpoint));
01094 m_breakpointCount--;
01095 m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints,
01096 m_breakpointCount*
sizeof(Breakpoint)));
01097
return true;
01098 }
01099 }
01100
01101
return false;
01102 }
01103
01104
bool KJSDebugWin::haveBreakpoint(SourceFile *sourceFile,
int line0,
int line1)
01105 {
01106
for (
int i = 0; i < m_breakpointCount; i++) {
01107
int sourceId = m_breakpoints[i].sourceId;
01108
int lineno = m_breakpoints[i].lineno;
01109
if (m_sourceFragments.contains(sourceId) &&
01110 m_sourceFragments[sourceId]->sourceFile == sourceFile) {
01111
int absLineno = m_sourceFragments[sourceId]->baseLine+lineno-1;
01112
if (absLineno >= line0 && absLineno <= line1)
01113
return true;
01114 }
01115 }
01116
01117
return false;
01118 }
01119
01120
#include "kjs_debugwin.moc"
01121
01122
#endif // KJS_DEBUGGER