📄 kjs_debugwin.cpp
字号:
QSplitter *hsplitter = new QSplitter(Qt::Vertical,mainWidget); QSplitter *vsplitter = new QSplitter(hsplitter); QFont font(KGlobalSettings::fixedFont()); QWidget *contextContainer = new QWidget(vsplitter); QLabel *contextLabel = new QLabel(i18n("Call stack"),contextContainer); QWidget *contextListContainer = new QWidget(contextContainer); m_contextList = new QListBox(contextListContainer); m_contextList->setMinimumSize(100,200); connect(m_contextList,SIGNAL(highlighted(int)),this,SLOT(slotShowFrame(int))); QHBoxLayout *clistLayout = new QHBoxLayout(contextListContainer); clistLayout->addWidget(m_contextList); clistLayout->addSpacing(KDialog::spacingHint()); QVBoxLayout *contextLayout = new QVBoxLayout(contextContainer); contextLayout->addWidget(contextLabel); contextLayout->addSpacing(KDialog::spacingHint()); contextLayout->addWidget(contextListContainer); // source selection & display QWidget *sourceSelDisplay = new QWidget(vsplitter); QVBoxLayout *ssdvl = new QVBoxLayout(sourceSelDisplay); m_sourceSel = new QComboBox(toolBar()); connect(m_sourceSel,SIGNAL(activated(int)),this,SLOT(slotSourceSelected(int))); m_sourceDisplay = new SourceDisplay(this,sourceSelDisplay); ssdvl->addWidget(m_sourceDisplay); connect(m_sourceDisplay,SIGNAL(lineDoubleClicked(int)),SLOT(slotToggleBreakpoint(int))); QValueList<int> vsplitSizes; vsplitSizes.insert(vsplitSizes.end(),120); vsplitSizes.insert(vsplitSizes.end(),480); vsplitter->setSizes(vsplitSizes); // evaluate QWidget *evalContainer = new QWidget(hsplitter); QLabel *evalLabel = new QLabel(i18n("JavaScript console"),evalContainer); m_evalEdit = new EvalMultiLineEdit(evalContainer); m_evalEdit->setWordWrap(QMultiLineEdit::NoWrap); m_evalEdit->setFont(font); connect(m_evalEdit,SIGNAL(returnPressed()),SLOT(slotEval())); m_evalDepth = 0; QVBoxLayout *evalLayout = new QVBoxLayout(evalContainer); evalLayout->addSpacing(KDialog::spacingHint()); evalLayout->addWidget(evalLabel); evalLayout->addSpacing(KDialog::spacingHint()); evalLayout->addWidget(m_evalEdit); QValueList<int> hsplitSizes; hsplitSizes.insert(hsplitSizes.end(),400); hsplitSizes.insert(hsplitSizes.end(),200); hsplitter->setSizes(hsplitSizes); vl->addWidget(hsplitter); // actions KPopupMenu *debugMenu = new KPopupMenu(this); menuBar()->insertItem("&Debug",debugMenu); m_actionCollection = new KActionCollection(this); m_actionCollection->setInstance(this); m_nextAction = new KAction(i18n("Next breakpoint","&Next"),"dbgnext",KShortcut(),this,SLOT(slotNext()), m_actionCollection,"next"); m_stepAction = new KAction(i18n("&Step"),"dbgstep",KShortcut(),this,SLOT(slotStep()), m_actionCollection,"step"); m_continueAction = new KAction(i18n("&Continue"),"dbgrun",KShortcut(),this,SLOT(slotContinue()), m_actionCollection,"cont"); m_stopAction = new KAction(i18n("St&op"),"stop",KShortcut(),this,SLOT(slotStop()), m_actionCollection,"stop"); m_breakAction = new KAction(i18n("&Break at Next Statement"),"dbgrunto",KShortcut(),this,SLOT(slotBreakNext()), m_actionCollection,"breaknext"); m_nextAction->setToolTip(i18n("Next breakpoint","Next")); m_stepAction->setToolTip(i18n("Step")); m_continueAction->setToolTip(i18n("Continue")); m_stopAction->setToolTip(i18n("Stop")); m_breakAction->setToolTip("Break at next Statement"); m_nextAction->setEnabled(false); m_stepAction->setEnabled(false); m_continueAction->setEnabled(false); m_stopAction->setEnabled(false); m_breakAction->setEnabled(true); m_nextAction->plug(debugMenu); m_stepAction->plug(debugMenu); m_continueAction->plug(debugMenu);// m_stopAction->plug(debugMenu); ### disabled until DebuggerImp::stop() works reliably m_breakAction->plug(debugMenu); m_nextAction->plug(toolBar()); m_stepAction->plug(toolBar()); m_continueAction->plug(toolBar());// m_stopAction->plug(toolBar()); ### m_breakAction->plug(toolBar()); toolBar()->insertWidget(1,300,m_sourceSel); toolBar()->setItemAutoSized(1); updateContextList(); setMinimumSize(300,200); resize(600,450);}KJSDebugWin::~KJSDebugWin(){ free(m_breakpoints); free(m_execs);}KJSDebugWin *KJSDebugWin::createInstance(){ assert(!kjs_html_debugger); kjs_html_debugger = new KJSDebugWin(); return kjs_html_debugger;}void KJSDebugWin::destroyInstance(){ assert(kjs_html_debugger); kjs_html_debugger->hide(); delete kjs_html_debugger;}void KJSDebugWin::slotNext(){ m_mode = Next; leaveSession();}void KJSDebugWin::slotStep(){ m_mode = Step; leaveSession();}void KJSDebugWin::slotContinue(){ m_mode = Continue; leaveSession();}void KJSDebugWin::slotStop(){ m_mode = Stop; while (!m_execStates.isEmpty()) leaveSession();}void KJSDebugWin::slotBreakNext(){ m_mode = Step;}void KJSDebugWin::slotToggleBreakpoint(int lineno){ if (m_sourceSel->currentItem() < 0) return; SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem()); // Find the source fragment containing the selected line (if any) int sourceId = -1; int highestBaseLine = -1; QMap<int,SourceFragment*>::Iterator it; for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it) { SourceFragment *sourceFragment = it.data(); if (sourceFragment && sourceFragment->sourceFile == sourceFile && sourceFragment->baseLine <= lineno && sourceFragment->baseLine > highestBaseLine) { sourceId = sourceFragment->sourceId; highestBaseLine = sourceFragment->baseLine; } } if (sourceId < 0) return; // Update the source code display with the appropriate icon int fragmentLineno = lineno-highestBaseLine+1; if (!setBreakpoint(sourceId,fragmentLineno)) // was already set deleteBreakpoint(sourceId,fragmentLineno); m_sourceDisplay->updateContents();}void KJSDebugWin::slotShowFrame(int frameno){ if (frameno < 0 || frameno >= m_execsCount) return; Context ctx = m_execs[frameno]->context(); setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine());}void KJSDebugWin::slotSourceSelected(int sourceSelIndex){ // A source file has been selected from the drop-down list - display the file if (sourceSelIndex < 0 || sourceSelIndex >= (int)m_sourceSel->count()) return; SourceFile *sourceFile = m_sourceSelFiles.at(sourceSelIndex); displaySourceFile(sourceFile,true); // If the currently selected context is in the current source file, then hilight // the line it's on. if (m_contextList->currentItem() >= 0) { Context ctx = m_execs[m_contextList->currentItem()]->context(); if (m_sourceFragments[ctx.sourceId()]->sourceFile == m_sourceSelFiles.at(sourceSelIndex)) setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine()); }}void KJSDebugWin::slotEval(){ // Work out which execution state to use. If we're currently in a debugging session, // use the current context - otherwise, use the global execution state from the interpreter // corresponding to the currently displayed source file. ExecState *exec; Object thisobj; if (m_execStates.isEmpty()) { if (m_sourceSel->currentItem() < 0) return; SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem()); if (!sourceFile->interpreter) return; exec = sourceFile->interpreter->globalExec(); thisobj = exec->interpreter()->globalObject(); } else { exec = m_execStates.top(); thisobj = exec->context().thisValue(); } // Evaluate the js code from m_evalEdit UString code(m_evalEdit->code()); QString msg; KJSCPUGuard guard; guard.start(); Interpreter *interp = exec->interpreter(); Object obj = Object::dynamicCast(interp->globalObject().get(exec, "eval")); List args; args.append(String(code)); m_evalDepth++; Value retval = obj.call(exec, thisobj, args); m_evalDepth--; guard.stop(); // Print the return value or exception message to the console if (exec->hadException()) { Value exc = exec->exception(); exec->clearException(); msg = "Exception: " + exc.toString(interp->globalExec()).qstring(); } else { msg = retval.toString(interp->globalExec()).qstring(); } m_evalEdit->insert(msg+"\n"); updateContextList();}void KJSDebugWin::closeEvent(QCloseEvent *e){ while (!m_execStates.isEmpty()) // ### not sure if this will work leaveSession(); return QWidget::closeEvent(e);}bool KJSDebugWin::eventFilter(QObject *o, QEvent *e){ switch (e->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::Destroy: case QEvent::Close: case QEvent::Quit: while (o->parent()) o = o->parent(); if (o == this) return QWidget::eventFilter(o,e); else return true; break; default: return QWidget::eventFilter(o,e); }}void KJSDebugWin::disableOtherWindows(){ QWidgetList *widgets = QApplication::allWidgets(); QWidgetListIt it(*widgets); for (; it.current(); ++it) it.current()->installEventFilter(this);}void KJSDebugWin::enableOtherWindows(){ QWidgetList *widgets = QApplication::allWidgets(); QWidgetListIt it(*widgets); for (; it.current(); ++it) it.current()->removeEventFilter(this);}bool KJSDebugWin::sourceParsed(KJS::ExecState *exec, int sourceId, const KJS::UString &source, int errorLine){ // Work out which source file this fragment is in SourceFile *sourceFile = 0; if (!m_nextSourceUrl.isEmpty()) sourceFile = getSourceFile(exec->interpreter(),m_nextSourceUrl); int index; if (!sourceFile) { index = m_sourceSel->count(); if (!m_nextSourceUrl.isEmpty()) { QString code = source.qstring(); KParts::ReadOnlyPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part(); if (m_nextSourceUrl == part->url().url()) { // Only store the code here if it's not from the part's html page... in that // case we can get it from KHTMLPageCache code = QString::null; } sourceFile = new SourceFile(m_nextSourceUrl,code,exec->interpreter()); setSourceFile(exec->interpreter(),m_nextSourceUrl,sourceFile); m_sourceSelFiles.append(sourceFile); m_sourceSel->insertItem(m_nextSourceUrl); } else { // Sourced passed from somewhere else (possibly an eval call)... we don't know the url, // but we still know the interpreter sourceFile = new SourceFile("(unknown)",source.qstring(),exec->interpreter()); m_sourceSelFiles.append(sourceFile); m_sourceSel->insertItem("???"); } } else { for (index = 0; index < m_sourceSel->count(); index++) { if (m_sourceSelFiles.at(index) == sourceFile) break; } assert(index < m_sourceSel->count()); } SourceFragment *sf = new SourceFragment(sourceId,m_nextSourceBaseLine,errorLine,sourceFile); m_sourceFragments[sourceId] = sf; if (m_sourceSel->currentItem() < 0) m_sourceSel->setCurrentItem(index); if (m_sourceSel->currentItem() == index) { displaySourceFile(sourceFile,true); } m_nextSourceBaseLine = 1; m_nextSourceUrl = "";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -