|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 1999-2001 by John Birch *
|
|
|
|
* jbb@tdevelop.org *
|
|
|
|
* Copyright (C) 2001 by Bernd Gehrmann *
|
|
|
|
* bernd@tdevelop.org *
|
|
|
|
* *
|
|
|
|
* Adapted for ruby debugging *
|
|
|
|
* -------------------------- *
|
|
|
|
* begin : Mon Nov 1 2004 *
|
|
|
|
* copyright : (C) 2004 by Richard Dale *
|
|
|
|
* email : Richard_Dale@tipitina.demon.co.uk *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
#include "debuggerpart.h"
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kfiledialog.h>
|
|
|
|
#include <kdevgenericfactory.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmainwindow.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <kparts/part.h>
|
|
|
|
#include <ktexteditor/viewcursorinterface.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <dcopclient.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <kstringhandler.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
|
|
|
|
#include "kdevcore.h"
|
|
|
|
#include "kdevproject.h"
|
|
|
|
#include "kdevmainwindow.h"
|
|
|
|
#include "kdevappfrontend.h"
|
|
|
|
#include "kdevpartcontroller.h"
|
|
|
|
#include "kdevdebugger.h"
|
|
|
|
#include "domutil.h"
|
|
|
|
#include "variablewidget.h"
|
|
|
|
#include "rdbbreakpointwidget.h"
|
|
|
|
#include "framestackwidget.h"
|
|
|
|
#include "processwidget.h"
|
|
|
|
#include "rdbcontroller.h"
|
|
|
|
#include "breakpoint.h"
|
|
|
|
#include "dbgpsdlg.h"
|
|
|
|
#include "dbgtoolbar.h"
|
|
|
|
#include "rdbparser.h"
|
|
|
|
#include "rdboutputwidget.h"
|
|
|
|
#include "processlinemaker.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <kdevplugininfo.h>
|
|
|
|
#include <debugger.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace RDBDebugger
|
|
|
|
{
|
|
|
|
static const KDevPluginInfo data("kdevrbdebugger");
|
|
|
|
|
|
|
|
typedef KDevGenericFactory<RubyDebuggerPart> RubyDebuggerFactory;
|
|
|
|
K_EXPORT_COMPONENT_FACTORY( libkdevrbdebugger, RubyDebuggerFactory( data ) )
|
|
|
|
|
|
|
|
RubyDebuggerPart::RubyDebuggerPart( TQObject *parent, const char *name, const TQStringList & ) :
|
|
|
|
KDevPlugin( &data, parent, name ? name : "RubyDebuggerPart" ),
|
|
|
|
controller(0)
|
|
|
|
{
|
|
|
|
// setObjId("RubyDebuggerInterface");
|
|
|
|
setInstance(RubyDebuggerFactory::instance());
|
|
|
|
|
|
|
|
setXMLFile("kdevrbdebugger.rc");
|
|
|
|
|
|
|
|
m_debugger = new Debugger( partController() );
|
|
|
|
|
|
|
|
statusBarIndicator = new TQLabel(" ", mainWindow()->statusBar());
|
|
|
|
statusBarIndicator->setFixedWidth(15);
|
|
|
|
mainWindow()->statusBar()->addWidget(statusBarIndicator, 0, true);
|
|
|
|
statusBarIndicator->show();
|
|
|
|
|
|
|
|
// Setup widgets and dbgcontroller
|
|
|
|
variableWidget = new VariableWidget( 0, "rdbVariablewidget");
|
|
|
|
// /*variableWidget*/->setEnabled(false);
|
|
|
|
variableWidget->setIcon(SmallIcon("math_brace"));
|
|
|
|
variableWidget->setCaption(i18n("Variable Tree"));
|
|
|
|
TQWhatsThis::add
|
|
|
|
(variableWidget, i18n("<b>Variable tree</b><p>"
|
|
|
|
"The variable tree allows you to see "
|
|
|
|
"the variable values as you step "
|
|
|
|
"through your program using the internal "
|
|
|
|
"debugger. Click the right mouse button on items in "
|
|
|
|
"this view to get a popup menu.\n"
|
|
|
|
"To speed up stepping through your code "
|
|
|
|
"leave the tree items closed.\n"));
|
|
|
|
mainWindow()->embedSelectView(variableWidget, i18n("Variables"), i18n("Debugger variable-view"));
|
|
|
|
|
|
|
|
// mainWindow()->setViewAvailable(variableWidget, false);
|
|
|
|
|
|
|
|
rdbBreakpointWidget = new RDBBreakpointWidget( 0, "rdbBreakpointWidget" );
|
|
|
|
rdbBreakpointWidget->setCaption(i18n("Breakpoint List"));
|
|
|
|
TQWhatsThis::add
|
|
|
|
(rdbBreakpointWidget, i18n("<b>Breakpoint list</b><p>"
|
|
|
|
"Displays a list of breakpoints with "
|
|
|
|
"their current status. Clicking on a "
|
|
|
|
"breakpoint item allows you to change "
|
|
|
|
"the breakpoint and will take you "
|
|
|
|
"to the source in the editor window."));
|
|
|
|
rdbBreakpointWidget->setIcon( SmallIcon("stop") );
|
|
|
|
mainWindow()->embedOutputView(rdbBreakpointWidget, i18n("Breakpoints"), i18n("Debugger breakpoints"));
|
|
|
|
|
|
|
|
framestackWidget = new FramestackWidget( 0, "rdbFramestackWidget" );
|
|
|
|
framestackWidget->setEnabled(false);
|
|
|
|
framestackWidget->setCaption(i18n("Frame Stack"));
|
|
|
|
TQWhatsThis::add
|
|
|
|
(framestackWidget, i18n("<b>Frame stack</b><p>"
|
|
|
|
"Often referred to as the \"call stack\", "
|
|
|
|
"this is a list showing what method is "
|
|
|
|
"currently active and who called each "
|
|
|
|
"method to get to this point in your "
|
|
|
|
"program. By clicking on an item you "
|
|
|
|
"can see the values in any of the "
|
|
|
|
"previous calling methods."));
|
|
|
|
framestackWidget->setIcon( SmallIcon("table") );
|
|
|
|
mainWindow()->embedOutputView(framestackWidget, i18n("Frame Stack"), i18n("Debugger method call stack"));
|
|
|
|
mainWindow()->setViewAvailable(framestackWidget, false);
|
|
|
|
|
|
|
|
|
|
|
|
rdbOutputWidget = new RDBOutputWidget( 0, "rdbOutputWidget" );
|
|
|
|
rdbOutputWidget->setEnabled(false);
|
|
|
|
rdbOutputWidget->setIcon( SmallIcon("inline_image") );
|
|
|
|
rdbOutputWidget->setCaption(i18n("RDB Output"));
|
|
|
|
TQWhatsThis::add
|
|
|
|
(rdbOutputWidget, i18n("<b>RDB output</b><p>"
|
|
|
|
"Shows all rdb commands being executed. "
|
|
|
|
"You can also issue any other rdb command while debugging."));
|
|
|
|
mainWindow()->embedOutputView(rdbOutputWidget, i18n("RDB"),
|
|
|
|
i18n("RDB output"));
|
|
|
|
mainWindow()->setViewAvailable(rdbOutputWidget, false);
|
|
|
|
|
|
|
|
// rdbBreakpointWidget -> this
|
|
|
|
connect( rdbBreakpointWidget, TQT_SIGNAL(refreshBPState(const Breakpoint&)),
|
|
|
|
this, TQT_SLOT(slotRefreshBPState(const Breakpoint&)));
|
|
|
|
connect( rdbBreakpointWidget, TQT_SIGNAL(publishBPState(const Breakpoint&)),
|
|
|
|
this, TQT_SLOT(slotRefreshBPState(const Breakpoint&)));
|
|
|
|
connect( rdbBreakpointWidget, TQT_SIGNAL(gotoSourcePosition(const TQString&, int)),
|
|
|
|
this, TQT_SLOT(slotGotoSource(const TQString&, int)) );
|
|
|
|
|
|
|
|
// Now setup the actions
|
|
|
|
KAction *action;
|
|
|
|
|
|
|
|
// action = new KAction(i18n("&Start"), "1rightarrow", CTRL+SHIFT+Key_F9,
|
|
|
|
action = new KAction(i18n("&Start"), "dbgrun", CTRL+SHIFT+Key_F9,
|
|
|
|
this, TQT_SLOT(slotRun()),
|
|
|
|
actionCollection(), "debug_run");
|
|
|
|
action->setToolTip( i18n("Start in debugger") );
|
|
|
|
action->setWhatsThis( i18n("<b>Start in debugger</b><p>"
|
|
|
|
"Starts the debugger with the project's main "
|
|
|
|
"executable. You may set some breakpoints "
|
|
|
|
"before this, or you can interrupt the program "
|
|
|
|
"while it is running, in order to get information "
|
|
|
|
"about variables, frame stack, and so on.") );
|
|
|
|
|
|
|
|
action = new KAction(i18n("Sto&p"), "stop", 0,
|
|
|
|
this, TQT_SLOT(slotStop()),
|
|
|
|
actionCollection(), "debug_stop");
|
|
|
|
action->setToolTip( i18n("Stop debugger") );
|
|
|
|
action->setWhatsThis(i18n("<b>Stop debugger</b><p>Kills the executable and exits the debugger."));
|
|
|
|
|
|
|
|
action = new KAction(i18n("Interrupt"), "player_pause", 0,
|
|
|
|
this, TQT_SLOT(slotPause()),
|
|
|
|
actionCollection(), "debug_pause");
|
|
|
|
action->setToolTip( i18n("Interrupt application") );
|
|
|
|
action->setWhatsThis(i18n("<b>Interrupt application</b><p>Interrupts the debugged process or current RDB command."));
|
|
|
|
|
|
|
|
action = new KAction(i18n("Run to &Cursor"), "dbgrunto", 0,
|
|
|
|
this, TQT_SLOT(slotRunToCursor()),
|
|
|
|
actionCollection(), "debug_runtocursor");
|
|
|
|
action->setToolTip( i18n("Run to cursor") );
|
|
|
|
action->setWhatsThis(i18n("<b>Run to cursor</b><p>Continues execution until the cursor position is reached."));
|
|
|
|
|
|
|
|
|
|
|
|
action = new KAction(i18n("Step &Over"), "dbgnext", 0,
|
|
|
|
this, TQT_SLOT(slotStepOver()),
|
|
|
|
actionCollection(), "debug_stepover");
|
|
|
|
action->setToolTip( i18n("Step over the next line") );
|
|
|
|
action->setWhatsThis( i18n("<b>Step over</b><p>"
|
|
|
|
"Executes one line of source in the current source file. "
|
|
|
|
"If the source line is a call to a method the whole "
|
|
|
|
"method is executed and the app will stop at the line "
|
|
|
|
"following the method call.") );
|
|
|
|
|
|
|
|
|
|
|
|
action = new KAction(i18n("Step &Into"), "dbgstep", 0,
|
|
|
|
this, TQT_SLOT(slotStepInto()),
|
|
|
|
actionCollection(), "debug_stepinto");
|
|
|
|
action->setToolTip( i18n("Step into the next statement") );
|
|
|
|
action->setWhatsThis( i18n("<b>Step into</b><p>"
|
|
|
|
"Executes exactly one line of source. If the source line "
|
|
|
|
"is a call to a method then execution will stop after "
|
|
|
|
"the method has been entered.") );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
action = new KAction(i18n("Step O&ut"), "dbgstepout", 0,
|
|
|
|
this, TQT_SLOT(slotStepOut()),
|
|
|
|
actionCollection(), "debug_stepout");
|
|
|
|
action->setToolTip( i18n("Steps out of the current method") );
|
|
|
|
action->setWhatsThis( i18n("<b>Step out</b><p>"
|
|
|
|
"Executes the application until the currently executing "
|
|
|
|
"method is completed. The debugger will then display "
|
|
|
|
"the line after the original call to that method. If "
|
|
|
|
"program execution is in the outermost frame (i.e. in "
|
|
|
|
"the topleveltoggleWatchpoint) then this operation has no effect.") );
|
|
|
|
|
|
|
|
|
|
|
|
action = new KAction(i18n("Toggle Breakpoint"), 0, 0,
|
|
|
|
this, TQT_SLOT(toggleBreakpoint()),
|
|
|
|
actionCollection(), "debug_toggle_breakpoint");
|
|
|
|
action->setToolTip(i18n("Toggle breakpoint"));
|
|
|
|
action->setWhatsThis(i18n("<b>Toggle breakpoint</b><p>Toggles the breakpoint at the current line in editor."));
|
|
|
|
|
|
|
|
connect( mainWindow()->main()->guiFactory(), TQT_SIGNAL(clientAdded(KXMLGUIClient*)),
|
|
|
|
this, TQT_SLOT(guiClientAdded(KXMLGUIClient*)) );
|
|
|
|
|
|
|
|
|
|
|
|
connect( partController(), TQT_SIGNAL(loadedFile(const KURL &)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotRefreshBP(const KURL &)) );
|
|
|
|
connect( debugger(), TQT_SIGNAL(toggledBreakpoint(const TQString &, int)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotToggleBreakpoint(const TQString &, int)) );
|
|
|
|
connect( debugger(), TQT_SIGNAL(editedBreakpoint(const TQString &, int)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotEditBreakpoint(const TQString &, int)) );
|
|
|
|
connect( debugger(), TQT_SIGNAL(toggledBreakpointEnabled(const TQString &, int)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotToggleBreakpointEnabled(const TQString &, int)) );
|
|
|
|
|
|
|
|
connect( core(), TQT_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
|
|
|
|
this, TQT_SLOT(contextMenu(TQPopupMenu *, const Context *)) );
|
|
|
|
|
|
|
|
connect( core(), TQT_SIGNAL(stopButtonClicked(KDevPlugin*)),
|
|
|
|
this, TQT_SLOT(slotStop(KDevPlugin*)) );
|
|
|
|
connect( core(), TQT_SIGNAL(projectClosed()),
|
|
|
|
this, TQT_SLOT(projectClosed()) );
|
|
|
|
|
|
|
|
connect( partController(), TQT_SIGNAL(activePartChanged(KParts::Part*)),
|
|
|
|
this, TQT_SLOT(slotActivePartChanged(KParts::Part*)) );
|
|
|
|
|
|
|
|
procLineMaker = new ProcessLineMaker();
|
|
|
|
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedStdoutLine(const TQCString&)),
|
|
|
|
appFrontend(), TQT_SLOT(insertStdoutLine(const TQCString&)) );
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedStderrLine(const TQCString&)),
|
|
|
|
appFrontend(), TQT_SLOT(insertStderrLine(const TQCString&)) );
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedPartialStdoutLine(const TQCString&)),
|
|
|
|
appFrontend(), TQT_SLOT(addPartialStdoutLine(const TQCString&)) );
|
|
|
|
connect( procLineMaker, TQT_SIGNAL(receivedPartialStderrLine(const TQCString&)),
|
|
|
|
appFrontend(), TQT_SLOT(addPartialStderrLine(const TQCString&)) );
|
|
|
|
|
|
|
|
setupController();
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(setupDcop()));
|
|
|
|
}
|
|
|
|
|
|
|
|
RubyDebuggerPart::~RubyDebuggerPart()
|
|
|
|
{
|
|
|
|
kapp->dcopClient()->setNotifications(false);
|
|
|
|
|
|
|
|
if (variableWidget)
|
|
|
|
mainWindow()->removeView(variableWidget);
|
|
|
|
if (rdbBreakpointWidget)
|
|
|
|
mainWindow()->removeView(rdbBreakpointWidget);
|
|
|
|
if (framestackWidget)
|
|
|
|
mainWindow()->removeView(framestackWidget);
|
|
|
|
if(rdbOutputWidget)
|
|
|
|
mainWindow()->removeView(rdbOutputWidget);
|
|
|
|
|
|
|
|
delete variableWidget;
|
|
|
|
delete rdbBreakpointWidget;
|
|
|
|
delete framestackWidget;
|
|
|
|
delete rdbOutputWidget;
|
|
|
|
delete controller;
|
|
|
|
delete floatingToolBar;
|
|
|
|
delete statusBarIndicator;
|
|
|
|
delete procLineMaker;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::guiClientAdded( KXMLGUIClient* client )
|
|
|
|
{
|
|
|
|
// Can't change state until after XMLGUI has been loaded...
|
|
|
|
// Anyone know of a better way of doing this?
|
|
|
|
if( client == this )
|
|
|
|
stateChanged( TQString("stopped") );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::contextMenu(TQPopupMenu *popup, const Context *context)
|
|
|
|
{
|
|
|
|
if (!context->hasType( Context::EditorContext ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
const EditorContext *econtext = static_cast<const EditorContext*>(context);
|
|
|
|
m_contextIdent = econtext->currentWord();
|
|
|
|
|
|
|
|
popup->insertSeparator();
|
|
|
|
if (econtext->url().isLocalFile())
|
|
|
|
{
|
|
|
|
int id = popup->insertItem( i18n("Toggle Breakpoint"), this, TQT_SLOT(toggleBreakpoint()) );
|
|
|
|
popup->setWhatsThis(id, i18n("<b>Toggle breakpoint</b><p>Toggles breakpoint at the current line."));
|
|
|
|
}
|
|
|
|
if (!m_contextIdent.isEmpty())
|
|
|
|
{
|
|
|
|
TQString squeezed = KStringHandler::csqueeze(m_contextIdent, 30);
|
|
|
|
int id = popup->insertItem( i18n("Watch: %1").arg(squeezed), this, TQT_SLOT(contextWatch()) );
|
|
|
|
popup->setWhatsThis(id, i18n("<b>Watch</b><p>Adds an expression under the cursor to the Variables/Watch list."));
|
|
|
|
|
|
|
|
id = popup->insertItem( i18n("Inspect: %1").arg(squeezed), this, TQT_SLOT(contextRubyInspect()) );
|
|
|
|
popup->setWhatsThis(id, i18n("<b>Inspect</b><p>Evaluates an expression under the cursor."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::toggleBreakpoint()
|
|
|
|
{
|
|
|
|
KParts::ReadWritePart *rwpart
|
|
|
|
= dynamic_cast<KParts::ReadWritePart*>(partController()->activePart());
|
|
|
|
KTextEditor::ViewCursorInterface *cursorIface
|
|
|
|
= dynamic_cast<KTextEditor::ViewCursorInterface*>(partController()->activeWidget());
|
|
|
|
|
|
|
|
if (!rwpart || !cursorIface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint line, col;
|
|
|
|
cursorIface->cursorPositionReal(&line, &col);
|
|
|
|
|
|
|
|
rdbBreakpointWidget->slotToggleBreakpoint(rwpart->url().path(), line);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::contextWatch()
|
|
|
|
{
|
|
|
|
variableWidget->slotAddWatchExpression(m_contextIdent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Evaluates the selected text
|
|
|
|
void RubyDebuggerPart::contextRubyInspect()
|
|
|
|
{
|
|
|
|
emit rubyInspect(m_contextIdent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::setupController()
|
|
|
|
{
|
|
|
|
VariableTree *variableTree = variableWidget->varTree();
|
|
|
|
|
|
|
|
controller = new RDBController(variableTree, framestackWidget, *projectDom());
|
|
|
|
|
|
|
|
// this -> controller
|
|
|
|
connect( this, TQT_SIGNAL(rubyInspect(const TQString&)),
|
|
|
|
controller, TQT_SLOT(slotRubyInspect(const TQString&)));
|
|
|
|
|
|
|
|
// variableTree -> framestackWidget
|
|
|
|
connect( variableTree, TQT_SIGNAL(selectFrame(int, int)),
|
|
|
|
framestackWidget, TQT_SLOT(slotSelectFrame(int, int)));
|
|
|
|
|
|
|
|
// framestackWidget -> variableTree
|
|
|
|
connect( framestackWidget, TQT_SIGNAL(frameActive(int, int, const TQString&)),
|
|
|
|
variableTree, TQT_SLOT(slotFrameActive(int, int, const TQString&)));
|
|
|
|
|
|
|
|
// variableTree -> controller
|
|
|
|
connect( variableTree, TQT_SIGNAL(expandItem(VarItem*, const TQCString&)),
|
|
|
|
controller, TQT_SLOT(slotExpandItem(VarItem*, const TQCString&)));
|
|
|
|
connect( variableTree, TQT_SIGNAL(fetchGlobals(bool)),
|
|
|
|
controller, TQT_SLOT(slotFetchGlobals(bool)));
|
|
|
|
connect( variableTree, TQT_SIGNAL(addWatchExpression(const TQString&, bool)),
|
|
|
|
controller, TQT_SLOT(slotAddWatchExpression(const TQString&, bool)));
|
|
|
|
connect( variableTree, TQT_SIGNAL(removeWatchExpression(int)),
|
|
|
|
controller, TQT_SLOT(slotRemoveWatchExpression(int)));
|
|
|
|
|
|
|
|
// framestackWidget -> controller
|
|
|
|
connect( framestackWidget, TQT_SIGNAL(selectFrame(int,int,const TQString&)),
|
|
|
|
controller, TQT_SLOT(slotSelectFrame(int,int,const TQString&)));
|
|
|
|
|
|
|
|
// rdbBreakpointWidget -> controller
|
|
|
|
connect( rdbBreakpointWidget, TQT_SIGNAL(clearAllBreakpoints()),
|
|
|
|
controller, TQT_SLOT(slotClearAllBreakpoints()));
|
|
|
|
connect( rdbBreakpointWidget, TQT_SIGNAL(publishBPState(const Breakpoint&)),
|
|
|
|
controller, TQT_SLOT(slotBPState(const Breakpoint &)));
|
|
|
|
|
|
|
|
|
|
|
|
// rdbOutputWidget -> controller
|
|
|
|
connect( rdbOutputWidget, TQT_SIGNAL(userRDBCmd(const TQString &)),
|
|
|
|
controller, TQT_SLOT(slotUserRDBCmd(const TQString&)));
|
|
|
|
connect( rdbOutputWidget, TQT_SIGNAL(breakInto()),
|
|
|
|
controller, TQT_SLOT(slotBreakInto()));
|
|
|
|
|
|
|
|
// controller -> rdbBreakpointWidget
|
|
|
|
connect( controller, TQT_SIGNAL(acceptPendingBPs()),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotSetPendingBPs()));
|
|
|
|
connect( controller, TQT_SIGNAL(unableToSetBPNow(int)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotUnableToSetBPNow(int)));
|
|
|
|
connect( controller, TQT_SIGNAL(rawRDBBreakpointList (char*)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotParseRDBBrkptList(char*)));
|
|
|
|
connect( controller, TQT_SIGNAL(rawRDBBreakpointSet(char*, int)),
|
|
|
|
rdbBreakpointWidget, TQT_SLOT(slotParseRDBBreakpointSet(char*, int)));
|
|
|
|
|
|
|
|
|
|
|
|
// controller -> this
|
|
|
|
connect( controller, TQT_SIGNAL(dbgStatus(const TQString&, int)),
|
|
|
|
this, TQT_SLOT(slotStatus(const TQString&, int)));
|
|
|
|
connect( controller, TQT_SIGNAL(showStepInSource(const TQString&, int, const TQString&)),
|
|
|
|
this, TQT_SLOT(slotShowStep(const TQString&, int)));
|
|
|
|
|
|
|
|
// controller -> procLineMaker
|
|
|
|
connect( controller, TQT_SIGNAL(ttyStdout(const char*)),
|
|
|
|
procLineMaker, TQT_SLOT(slotReceivedStdout(const char*)));
|
|
|
|
connect( controller, TQT_SIGNAL(ttyStderr(const char*)),
|
|
|
|
procLineMaker, TQT_SLOT(slotReceivedStderr(const char*)));
|
|
|
|
|
|
|
|
// controller -> rdbOutputWidget
|
|
|
|
connect( controller, TQT_SIGNAL(rdbStdout(const char*)),
|
|
|
|
rdbOutputWidget, TQT_SLOT(slotReceivedStdout(const char*)) );
|
|
|
|
connect( controller, TQT_SIGNAL(rdbStderr(const char*)),
|
|
|
|
rdbOutputWidget, TQT_SLOT(slotReceivedStderr(const char*)) );
|
|
|
|
connect( controller, TQT_SIGNAL(dbgStatus(const TQString&, int)),
|
|
|
|
rdbOutputWidget, TQT_SLOT(slotDbgStatus(const TQString&, int)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RubyDebuggerPart::startDebugger()
|
|
|
|
{
|
|
|
|
TQString build_dir; // Currently selected build directory
|
|
|
|
TQString run_directory; // Directory from where the program should be run
|
|
|
|
TQString program; // Absolute path to application
|
|
|
|
TQString run_arguments; // Command line arguments to be passed to the application
|
|
|
|
TQString ruby_interpreter; // Absolute path to the ruby interpreter
|
|
|
|
TQString debuggee_path; // Absolute path to debuggee.rb debugger script
|
|
|
|
bool show_constants; // Show constants in the debugger
|
|
|
|
bool trace_into_ruby; // Trace into the ruby code installed under sitedir
|
|
|
|
|
|
|
|
if (project()) {
|
|
|
|
build_dir = project()->buildDirectory();
|
|
|
|
run_directory = DomUtil::readEntry(*projectDom(), "/kdevscriptproject/run/globalcwd");
|
|
|
|
if (run_directory.isEmpty())
|
|
|
|
run_directory = project()->buildDirectory();
|
|
|
|
}
|
|
|
|
|
|
|
|
int runMainProgram = DomUtil::readIntEntry(*projectDom(), "/kdevrubysupport/run/runmainprogram");
|
|
|
|
|
|
|
|
if (runMainProgram == 0) {
|
|
|
|
program = project()->projectDirectory() + "/" + DomUtil::readEntry(*projectDom(), "/kdevrubysupport/run/mainprogram");
|
|
|
|
} else {
|
|
|
|
KParts::ReadOnlyPart *ro_part = dynamic_cast<KParts::ReadOnlyPart*>(partController()->activePart());
|
|
|
|
if (ro_part != 0) {
|
|
|
|
program = ro_part->url().path();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
run_arguments = DomUtil::readEntry(*projectDom(), "/kdevrubysupport/run/programargs");
|
|
|
|
|
|
|
|
TQString shell = DomUtil::readEntry(*projectDom(), "/kdevrbdebugger/general/dbgshell");
|
|
|
|
if( !shell.isEmpty() )
|
|
|
|
{
|
|
|
|
TQFileInfo info( shell );
|
|
|
|
if( info.isRelative() )
|
|
|
|
{
|
|
|
|
shell = build_dir + "/" + shell;
|
|
|
|
info.setFile( shell );
|
|
|
|
}
|
|
|
|
if( !info.exists() )
|
|
|
|
{
|
|
|
|
KMessageBox::error(
|
|
|
|
mainWindow()->main(),
|
|
|
|
i18n("Could not locate the debugging shell '%1'.").arg( shell ),
|
|
|
|
i18n("Debugging Shell Not Found") );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
core()->running(this, true);
|
|
|
|
|
|
|
|
stateChanged( TQString("active") );
|
|
|
|
|
|
|
|
KActionCollection *ac = actionCollection();
|
|
|
|
ac->action("debug_run")->setText( i18n("&Continue") );
|
|
|
|
// ac->action("debug_run")->setIcon( "dbgrun" );
|
|
|
|
ac->action("debug_run")->setToolTip( i18n("Continues the application execution") );
|
|
|
|
ac->action("debug_run")->setWhatsThis( i18n("Continue application execution\n\n"
|
|
|
|
"Continues the execution of your application in the "
|
|
|
|
"debugger. This only takes effect when the application "
|
|
|
|
"has been halted by the debugger (i.e. a breakpoint has "
|
|
|
|
"been activated or the interrupt was pressed).") );
|
|
|
|
|
|
|
|
|
|
|
|
// mainWindow()->setViewAvailable(variableWidget, true);
|
|
|
|
mainWindow()->setViewAvailable(framestackWidget, true);
|
|
|
|
mainWindow()->setViewAvailable(rdbOutputWidget, true);
|
|
|
|
|
|
|
|
// variableWidget->setEnabled(true);
|
|
|
|
framestackWidget->setEnabled(true);
|
|
|
|
|
|
|
|
rdbOutputWidget->clear();
|
|
|
|
rdbOutputWidget->setEnabled(true);
|
|
|
|
|
|
|
|
if (DomUtil::readBoolEntry(*projectDom(), "/kdevrbdebugger/general/floatingtoolbar", false))
|
|
|
|
{
|
|
|
|
floatingToolBar = new DbgToolBar(this, mainWindow()->main());
|
|
|
|
floatingToolBar->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
ruby_interpreter = DomUtil::readEntry(*projectDom(), "/kdevrubysupport/run/interpreter");
|
|
|
|
|
|
|
|
int coding = DomUtil::readIntEntry(*projectDom(), "/kdevrubysupport/run/charactercoding");
|
|
|
|
TQString character_coding("-K");
|
|
|
|
|
|
|
|
switch (coding) {
|
|
|
|
case 0:
|
|
|
|
character_coding.append("A");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
character_coding.append("E");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
character_coding.append("S");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
character_coding.append("U");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ruby_interpreter.append(TQString(" -K") + code);
|
|
|
|
|
|
|
|
debuggee_path = ::locate("data", "kdevrbdebugger/debuggee.rb", instance());
|
|
|
|
|
|
|
|
show_constants = DomUtil::readBoolEntry(*projectDom(), "/kdevrbdebugger/general/showconstants");
|
|
|
|
trace_into_ruby = DomUtil::readBoolEntry(*projectDom(), "/kdevrbdebugger/general/traceintoruby");
|
|
|
|
|
|
|
|
controller->slotStart(ruby_interpreter, character_coding, run_directory, debuggee_path, program, run_arguments, show_constants, trace_into_ruby);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStopDebugger()
|
|
|
|
{
|
|
|
|
controller->slotStopDebugger();
|
|
|
|
debugger()->clearExecutionPoint();
|
|
|
|
|
|
|
|
delete floatingToolBar;
|
|
|
|
floatingToolBar = 0;
|
|
|
|
|
|
|
|
rdbBreakpointWidget->reset();
|
|
|
|
framestackWidget->clear();
|
|
|
|
variableWidget->varTree()->clear();
|
|
|
|
|
|
|
|
// variableWidget->setEnabled(false);
|
|
|
|
framestackWidget->setEnabled(false);
|
|
|
|
rdbOutputWidget->setEnabled(false);
|
|
|
|
|
|
|
|
// mainWindow()->setViewAvailable(variableWidget, false);
|
|
|
|
mainWindow()->setViewAvailable(framestackWidget, false);
|
|
|
|
mainWindow()->setViewAvailable(rdbOutputWidget, false);
|
|
|
|
|
|
|
|
KActionCollection *ac = actionCollection();
|
|
|
|
ac->action("debug_run")->setText( i18n("&Start") );
|
|
|
|
// ac->action("debug_run")->setIcon( "1rightarrow" );
|
|
|
|
ac->action("debug_run")->setToolTip( i18n("Runs the program in the debugger") );
|
|
|
|
ac->action("debug_run")->setWhatsThis( i18n("Start in debugger\n\n"
|
|
|
|
"Starts the debugger with the project's main "
|
|
|
|
"executable. You may set some breakpoints "
|
|
|
|
"before this, or you can interrupt the program "
|
|
|
|
"while it is running, in order to get information "
|
|
|
|
"about variables, frame stack, and so on.") );
|
|
|
|
|
|
|
|
stateChanged( TQString("stopped") );
|
|
|
|
|
|
|
|
core()->running(this, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::projectClosed()
|
|
|
|
{
|
|
|
|
slotStopDebugger();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotRun()
|
|
|
|
{
|
|
|
|
if (controller->stateIsOn(s_programExited)) {
|
|
|
|
rdbBreakpointWidget->reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( controller->stateIsOn( s_dbgNotStarted ) ) {
|
|
|
|
mainWindow()->statusBar()->message(i18n("Debugging program"), 1000);
|
|
|
|
mainWindow()->raiseView(rdbOutputWidget);
|
|
|
|
appFrontend()->clearView();
|
|
|
|
startDebugger();
|
|
|
|
} else {
|
|
|
|
KActionCollection *ac = actionCollection();
|
|
|
|
ac->action("debug_run")->setText( i18n("&Continue") );
|
|
|
|
ac->action("debug_run")->setToolTip( i18n("Continues the application execution") );
|
|
|
|
ac->action("debug_run")->setWhatsThis( i18n("Continue application execution\n\n"
|
|
|
|
"Continues the execution of your application in the "
|
|
|
|
"debugger. This only takes effect when the application "
|
|
|
|
"has been halted by the debugger (i.e. a breakpoint has "
|
|
|
|
"been activated or the interrupt was pressed).") );
|
|
|
|
|
|
|
|
mainWindow()->statusBar()->message(i18n("Continuing program"), 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
controller->slotRun();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStop(KDevPlugin* which)
|
|
|
|
{
|
|
|
|
if( which != 0 && which != this )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// if( !controller->stateIsOn( s_dbgNotStarted ) && !controller->stateIsOn( s_shuttingDown ) )
|
|
|
|
slotStopDebugger();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotPause()
|
|
|
|
{
|
|
|
|
controller->slotBreakInto();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotRunToCursor()
|
|
|
|
{
|
|
|
|
KParts::ReadWritePart *rwpart
|
|
|
|
= dynamic_cast<KParts::ReadWritePart*>(partController()->activePart());
|
|
|
|
KTextEditor::ViewCursorInterface *cursorIface
|
|
|
|
= dynamic_cast<KTextEditor::ViewCursorInterface*>(partController()->activeWidget());
|
|
|
|
|
|
|
|
if (!rwpart || !rwpart->url().isLocalFile() || !cursorIface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint line, col;
|
|
|
|
cursorIface->cursorPosition(&line, &col);
|
|
|
|
|
|
|
|
controller->slotRunUntil(rwpart->url().path(), line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStepOver()
|
|
|
|
{
|
|
|
|
controller->slotStepOver();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStepInto()
|
|
|
|
{
|
|
|
|
controller->slotStepInto();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStepOut()
|
|
|
|
{
|
|
|
|
controller->slotStepOutOff();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotRefreshBPState( const Breakpoint& BP)
|
|
|
|
{
|
|
|
|
if (BP.type() == BP_TYPE_FilePos)
|
|
|
|
{
|
|
|
|
const FilePosBreakpoint& bp = dynamic_cast<const FilePosBreakpoint&>(BP);
|
|
|
|
if (bp.isActionDie())
|
|
|
|
debugger()->setBreakpoint(bp.fileName(), bp.lineNum()-1, -1, true, false);
|
|
|
|
else
|
|
|
|
debugger()->setBreakpoint(bp.fileName(), bp.lineNum()-1,
|
|
|
|
1/*bp->id()*/, bp.isEnabled(), bp.isPending() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotStatus(const TQString &msg, int state)
|
|
|
|
{
|
|
|
|
TQString stateIndicator;
|
|
|
|
|
|
|
|
if (state & s_dbgNotStarted)
|
|
|
|
{
|
|
|
|
stateIndicator = " ";
|
|
|
|
}
|
|
|
|
else if (state & s_appBusy)
|
|
|
|
{
|
|
|
|
stateIndicator = "A";
|
|
|
|
debugger()->clearExecutionPoint();
|
|
|
|
stateChanged( TQString("active") );
|
|
|
|
}
|
|
|
|
else if (state & s_programExited)
|
|
|
|
{
|
|
|
|
stateIndicator = "E";
|
|
|
|
stateChanged( TQString("stopped") );
|
|
|
|
KActionCollection *ac = actionCollection();
|
|
|
|
ac->action("debug_run")->setText( i18n("Restart") );
|
|
|
|
// ac->action("debug_run")->setIcon( "1rightarrow" );
|
|
|
|
ac->action("debug_run")->setToolTip( i18n("Restart the program in the debugger") );
|
|
|
|
ac->action("debug_run")->setWhatsThis( i18n("Restart in debugger\n\n"
|
|
|
|
"Restarts the program in the debugger") );
|
|
|
|
// slotStop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stateIndicator = "P";
|
|
|
|
stateChanged( TQString("paused") );
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now? :-)
|
|
|
|
kdDebug(9012) << "Debugger state: " << stateIndicator << ": " << endl;
|
|
|
|
kdDebug(9012) << " " << msg << endl;
|
|
|
|
|
|
|
|
statusBarIndicator->setText(stateIndicator);
|
|
|
|
if (!msg.isEmpty())
|
|
|
|
mainWindow()->statusBar()->message(msg, 3000);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotShowStep(const TQString &fileName, int lineNum)
|
|
|
|
{
|
|
|
|
if ( ! fileName.isEmpty() )
|
|
|
|
{
|
|
|
|
// Debugger counts lines from 1
|
|
|
|
debugger()->gotoExecutionPoint(KURL( fileName ), lineNum-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotGotoSource(const TQString &fileName, int lineNum)
|
|
|
|
{
|
|
|
|
if ( ! fileName.isEmpty() )
|
|
|
|
partController()->editDocument(KURL( fileName ), lineNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RubyDebuggerPart::slotActivePartChanged( KParts::Part* part )
|
|
|
|
{
|
|
|
|
KAction* action = actionCollection()->action("debug_toggle_breakpoint");
|
|
|
|
if(!action)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(!part)
|
|
|
|
{
|
|
|
|
action->setEnabled(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KTextEditor::ViewCursorInterface *iface
|
|
|
|
= dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget());
|
|
|
|
action->setEnabled( iface != 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::restorePartialProjectSession(const TQDomElement* el)
|
|
|
|
{
|
|
|
|
rdbBreakpointWidget->restorePartialProjectSession(el);
|
|
|
|
variableWidget->restorePartialProjectSession(el);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RubyDebuggerPart::savePartialProjectSession(TQDomElement* el)
|
|
|
|
{
|
|
|
|
rdbBreakpointWidget->savePartialProjectSession(el);
|
|
|
|
variableWidget->savePartialProjectSession(el);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KDevAppFrontend * RDBDebugger::RubyDebuggerPart::appFrontend( )
|
|
|
|
{
|
|
|
|
return extension<KDevAppFrontend>("KDevelop/AppFrontend");
|
|
|
|
}
|
|
|
|
|
|
|
|
KDevDebugger * RDBDebugger::RubyDebuggerPart::debugger()
|
|
|
|
{
|
|
|
|
return m_debugger;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "debuggerpart.moc"
|