You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
851 lines
26 KiB
851 lines
26 KiB
/***************************************************************************
|
|
phpdebuggerinterface.cpp
|
|
-------------------
|
|
begin : 2004-03-12
|
|
copyright : (C) 2004 Linus McCabe <linus@mccabe.nu>
|
|
Based on work by Mathieu Kooiman
|
|
***************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* *
|
|
* 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 <tdetexteditor/document.h>
|
|
#include <tdetexteditor/markinterfaceextension.h>
|
|
#include <tdetexteditor/viewcursorinterface.h>
|
|
#include <kdebug.h>
|
|
#include <tdelocale.h>
|
|
#include <kcombobox.h>
|
|
#include <tdeparts/componentfactory.h>
|
|
#include <kiconloader.h>
|
|
#include <tdemessagebox.h>
|
|
#include <qextfileinfo.h>
|
|
#include <kinputdialog.h>
|
|
#include <tqlineedit.h>
|
|
|
|
#include "quanta.h"
|
|
#include "document.h"
|
|
#include "resource.h"
|
|
#include "project.h"
|
|
#include "quantadebuggerinterface.h"
|
|
#include "debuggerclient.h"
|
|
#include "debuggerbreakpoint.h"
|
|
#include "debuggerbreakpointlist.h"
|
|
#include "debuggermanager.h"
|
|
#include "messageoutput.h"
|
|
#include "viewmanager.h"
|
|
#include "quantaview.h"
|
|
#include "debuggerui.h"
|
|
#include "debuggervariable.h"
|
|
#include "pathmapper.h"
|
|
#include "variableslistview.h"
|
|
#include "conditionalbreakpointdialog.h"
|
|
|
|
// dialogs
|
|
#include "debuggervariablesets.h"
|
|
|
|
DebuggerManager::DebuggerManager(TQObject *myparent)
|
|
: TQObject(myparent)
|
|
{
|
|
initActions();
|
|
|
|
// Create objects
|
|
m_breakpointList = new DebuggerBreakpointList();
|
|
m_pathmapper = new PathMapper(this, "pathmapper");
|
|
m_debuggerui = NULL;
|
|
m_interface = new QuantaDebuggerInterface(this, "interface");
|
|
m_client = NULL;
|
|
}
|
|
|
|
void DebuggerManager::slotNewProjectLoaded(const TQString &projectname, const KURL &, const KURL &)
|
|
{
|
|
if(m_client)
|
|
{
|
|
|
|
disconnect(m_client, TQ_SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, TQ_SLOT(slotStatus(DebuggerUI::DebuggerStatus)));
|
|
|
|
delete m_client;
|
|
m_client = NULL;
|
|
}
|
|
enableAction("*", false);
|
|
|
|
// Remove all breakpoints
|
|
m_breakpointList->clear();
|
|
|
|
if(m_debuggerui)
|
|
{
|
|
delete m_debuggerui;
|
|
m_debuggerui = NULL;
|
|
}
|
|
//kdDebug(24002) << "DebuggerManager::slotNewProjectLoaded " << projectname << ", " << Project::ref()->debuggerClient << endl;
|
|
|
|
// Load new client
|
|
if(!projectname.isEmpty())
|
|
{
|
|
|
|
TDETrader::OfferList offers = TDETrader::self()->query("Quanta/Debugger");
|
|
TDETrader::OfferList::ConstIterator iterDbg;
|
|
for(iterDbg = offers.begin(); iterDbg != offers.end(); ++iterDbg)
|
|
{
|
|
KService::Ptr service = *iterDbg;
|
|
if(Project::ref()->debuggerClient() == service->name())
|
|
{
|
|
int errCode = 0;
|
|
//Workaround for dynamic_cast not working correctly on SUSE 10, gcc 4.0.2
|
|
//The correct way should be a simple:
|
|
// m_client = KParts::ComponentFactory::createInstanceFromService<DebuggerClient>(service, this, 0, TQStringList(), &errCode);
|
|
TQObject* obj = KParts::ComponentFactory::createInstanceFromService<TQObject>(service, this, 0, TQStringList(), &errCode);
|
|
if (obj && obj->inherits("DebuggerClient"))
|
|
m_client = static_cast<DebuggerClient *>(obj);
|
|
|
|
//kdDebug(24002) << service->name() << " (" << m_client << ")" << endl;
|
|
|
|
if(!m_client)
|
|
{
|
|
emit hideSplash();
|
|
KMessageBox::error(NULL, i18n("<qt>Unable to load the debugger plugin, error code %1 was returned: <b>%2</b>.</qt>").arg(errCode).arg(KLibLoader::self()->lastErrorMessage()), i18n("Debugger Error"));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tell client to load its settings
|
|
if (m_client)
|
|
{
|
|
TQDomNode nodeThisDbg;
|
|
TQDomDocument *dom = Project::ref()->sessionDom();
|
|
TQDomNode projectNode = dom->firstChild().firstChild();
|
|
TQDomNode nodeDbg = projectNode.namedItem("debuggers");
|
|
if(nodeDbg.isNull())
|
|
{
|
|
nodeDbg = dom->createElement("debuggers");
|
|
projectNode.appendChild(nodeDbg);
|
|
}
|
|
|
|
// Load this project's mapped paths
|
|
m_pathmapper->readConfig();
|
|
|
|
// Load this projects debugger's settings
|
|
nodeThisDbg = nodeDbg.namedItem(m_client->getName());
|
|
if(nodeThisDbg.isNull())
|
|
{
|
|
nodeThisDbg = dom->createElement(m_client->getName());
|
|
nodeDbg.appendChild(nodeThisDbg);
|
|
}
|
|
|
|
m_client->readConfig(nodeThisDbg);
|
|
|
|
// recreate UI
|
|
m_debuggerui = new DebuggerUI(this, "debuggerui");
|
|
connect(m_client, TQ_SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, TQ_SLOT(slotStatus(DebuggerUI::DebuggerStatus)));
|
|
|
|
// Load saved breakpoints
|
|
if(Project::ref()->debuggerPersistentBreakpoints())
|
|
{
|
|
TQDomNode nodeBreakpoints = nodeDbg.namedItem("breakpoints");
|
|
if(!nodeBreakpoints.isNull())
|
|
{
|
|
TQDomNode child = nodeBreakpoints.firstChild();
|
|
while(!child.isNull())
|
|
{
|
|
DebuggerBreakpoint* bp = new DebuggerBreakpoint();
|
|
bp->setFilePath( child.attributes().namedItem("filepath").nodeValue());
|
|
bp->setClass( child.attributes().namedItem("class").nodeValue());
|
|
bp->setFunction( child.attributes().namedItem("function").nodeValue());
|
|
bp->setCondition( child.attributes().namedItem("condition").nodeValue());
|
|
bp->setLine( child.attributes().namedItem("line").nodeValue().toLong());
|
|
if(child.attributes().namedItem("type").nodeValue() == "true")
|
|
bp->setType(DebuggerBreakpoint::ConditionalTrue);
|
|
else if(child.attributes().namedItem("type").nodeValue() == "change")
|
|
bp->setType(DebuggerBreakpoint::ConditionalChange);
|
|
else
|
|
bp->setType(DebuggerBreakpoint::LineBreakpoint);
|
|
|
|
// Update client and ui
|
|
m_client->addBreakpoint(bp);
|
|
m_breakpointList->add(bp);
|
|
|
|
// loop
|
|
child = child.nextSibling();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load saved Watches
|
|
if(Project::ref()->debuggerPersistentWatches())
|
|
{
|
|
TQDomNode nodeWatches = nodeDbg.namedItem("watches");
|
|
if(!nodeWatches.isNull())
|
|
{
|
|
TQDomNode child = nodeWatches.firstChild();
|
|
while(!child.isNull())
|
|
{
|
|
TQString watch = child.attributes().namedItem("name").nodeValue();
|
|
DebuggerVariable *var = new DebuggerVariable(watch, "", DebuggerVariableTypes::Undefined);
|
|
m_debuggerui->addVariable(var);
|
|
m_client->addWatch(watch);
|
|
|
|
child = child.nextSibling();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
initClientActions();
|
|
|
|
// Disable all debugactions that need a session (ie not breakpoints, etc)
|
|
slotDebugStartSession();
|
|
}
|
|
|
|
void DebuggerManager::initActions()
|
|
{
|
|
TDEAction * newaction;
|
|
TDEActionCollection *ac = quantaApp->actionCollection();
|
|
if(!ac)
|
|
return;
|
|
|
|
//Debugger, breakpoint
|
|
newaction = new TDEAction(i18n("Toggle &Breakpoint"), SmallIcon("debug_breakpoint"), TQt::CTRL+TQt::SHIFT+TQt::Key_B, this, TQ_SLOT(toggleBreakpoint()), ac, "debug_breakpoints_toggle");
|
|
newaction->setToolTip(i18n("Toggles a breakpoint at the current cursor location"));
|
|
|
|
newaction = new TDEAction(i18n("&Clear Breakpoints"), 0, this, TQ_SLOT(clearBreakpoints()), ac, "debug_breakpoints_clear");
|
|
newaction->setToolTip(i18n("Clears all breakpoints"));
|
|
|
|
newaction = new TDEAction(i18n("Break When..."), SmallIcon("math_int"), 0, this, TQ_SLOT(slotConditionalBreakpoint()), ac, "debug_conditional_break");
|
|
newaction->setToolTip(i18n("Adds a new conditional breakpoint"));
|
|
|
|
newaction = new TDEAction(i18n("Break When..."), SmallIcon("math_int"), 0, this, TQ_SLOT(slotConditionalBreakpoint()), ac, "debug_conditional_breakdialog");
|
|
newaction->setToolTip(i18n("Adds a new conditional breakpoint"));
|
|
|
|
// Execution
|
|
newaction = new TDEAction(i18n("Send HTTP R&equest"), SmallIcon("debug_currentline"), 0, this, TQ_SLOT(slotDebugRequest()), ac, "debug_request");
|
|
newaction->setToolTip(i18n("Initiate HTTP Request to the server with debugging activated"));
|
|
|
|
newaction = new TDEAction(i18n("&Trace"), SmallIcon("debug_run"), 0, this, TQ_SLOT(slotDebugTrace()), ac, "debug_trace");
|
|
newaction->setToolTip(i18n("Traces through the script. If a script is currently not being debugged, it will start in trace mode when started"));
|
|
|
|
newaction = new TDEAction(i18n("&Run"), SmallIcon("debug_leap"), 0, this, TQ_SLOT(slotDebugRun()), ac, "debug_run");
|
|
newaction->setToolTip(i18n("Runs the script. If a script is currently not being debugged, it will start in run mode when started"));
|
|
|
|
newaction = new TDEAction(i18n("&Step"), SmallIcon("debug_stepover"), 0, this, TQ_SLOT(slotDebugStepOver()), ac, "debug_stepover");
|
|
newaction->setToolTip(i18n("Executes the next line of execution, but does not step into functions or includes"));
|
|
|
|
newaction = new TDEAction(i18n("Step &Into"), SmallIcon("debug_stepinto"), 0, this, TQ_SLOT(slotDebugStepInto()), ac, "debug_stepinto");
|
|
newaction->setToolTip(i18n("Executes the next line of execution and steps into it if it is a function call or inclusion of a file"));
|
|
|
|
newaction = new TDEAction(i18n("S&kip"), SmallIcon("debug_skip"), 0, this, TQ_SLOT(slotDebugSkip()), ac, "debug_skip");
|
|
newaction->setToolTip(i18n("Skips the next command of execution and makes the next command the current one"));
|
|
|
|
newaction = new TDEAction(i18n("Step &Out"), SmallIcon("debug_stepout"), 0, this, TQ_SLOT(slotDebugStepOut()), ac, "debug_stepout");
|
|
newaction->setToolTip(i18n("Executes the rest of the commands in the current function/file and pauses when it is done (when it reaches a higher level in the backtrace)"));
|
|
|
|
newaction = new TDEAction(i18n("&Pause"), SmallIcon("debug_pause"), 0, this, TQ_SLOT(slotDebugPause()), ac, "debug_pause");
|
|
newaction->setToolTip(i18n("Pauses the scripts if it is running or tracing. If a script is currently not being debugged, it will start in paused mode when started"));
|
|
newaction = new TDEAction(i18n("Kill"), SmallIcon("debug_kill"), 0, this, TQ_SLOT(slotDebugKill()), ac, "debug_kill");
|
|
newaction->setToolTip(i18n("Kills the currently running script"));
|
|
|
|
newaction = new TDEAction(i18n("Start Session"), SmallIcon("debug_connect"), 0, this, TQ_SLOT(slotDebugStartSession()), ac, "debug_connect");
|
|
newaction->setToolTip(i18n("Starts the debugger internally (Makes debugging possible)"));
|
|
|
|
newaction = new TDEAction(i18n("End Session"), SmallIcon("debug_disconnect"), 0, this, TQ_SLOT(slotDebugEndSession()), ac, "debug_disconnect");
|
|
newaction->setToolTip(i18n("Stops the debugger internally (debugging not longer possible)"));
|
|
|
|
// Variables
|
|
newaction = new TDEAction(i18n("Watch Variable"), SmallIcon("math_brace"), 0, this, TQ_SLOT(slotAddWatch()), ac, "debug_addwatch");
|
|
newaction->setToolTip(i18n("Adds a variable to the watch list"));
|
|
|
|
newaction = new TDEAction(i18n("Watch Variable"), SmallIcon("math_brace"), 0, this, TQ_SLOT(slotAddWatch()), ac, "debug_addwatchdialog");
|
|
newaction->setToolTip(i18n("Adds a variable to the watch list"));
|
|
|
|
newaction = new TDEAction(i18n("Set Value of Variable"), SmallIcon("edit"), 0, this, TQ_SLOT(slotVariableSet()), ac, "debug_variable_set");
|
|
newaction->setToolTip(i18n("Changes the value of a variable"));
|
|
|
|
newaction = new TDEAction(i18n("Set Value of Variable"), SmallIcon("edit"), 0, this, TQ_SLOT(slotVariableSet()), ac, "debug_variable_setdialog");
|
|
newaction->setToolTip(i18n("Changes the value of a variable"));
|
|
|
|
newaction = new TDEAction(i18n("Open Profiler Output"), SmallIcon("launch"), 0, this, TQ_SLOT(slotProfilerOpen()), ac, "debug_profiler_open");
|
|
newaction->setToolTip(i18n("Opens the profiler output file"));
|
|
|
|
enableAction("*", false);
|
|
|
|
}
|
|
|
|
void DebuggerManager::initClientActions()
|
|
{
|
|
enableAction("*", false);
|
|
|
|
if(m_client)
|
|
{
|
|
// Get actioncollection and add appropriate actions depending on capabilities of the debugger
|
|
if(m_client->supports(DebuggerClientCapabilities::LineBreakpoints))
|
|
enableAction("debug_breakpoints_toggle", true);
|
|
if(m_client->supports(DebuggerClientCapabilities::LineBreakpoints))
|
|
enableAction("debug_breakpoints_clear", true);
|
|
}
|
|
}
|
|
|
|
DebuggerManager::~DebuggerManager()
|
|
{
|
|
delete m_breakpointList;
|
|
m_breakpointList = 0L;
|
|
|
|
if(m_client)
|
|
{
|
|
|
|
disconnect(m_client, TQ_SIGNAL(updateStatus(DebuggerUI::DebuggerStatus)), m_debuggerui, TQ_SLOT(slotStatus(DebuggerUI::DebuggerStatus)));
|
|
|
|
delete m_client;
|
|
m_client = 0L;
|
|
}
|
|
|
|
delete m_debuggerui;
|
|
m_debuggerui = 0L;
|
|
delete m_interface;
|
|
m_interface = 0L;
|
|
delete m_pathmapper;
|
|
m_pathmapper = 0L;
|
|
}
|
|
|
|
void DebuggerManager::enableAction(const TQString& action, bool enable)
|
|
{
|
|
if(action == "*")
|
|
{
|
|
// Enable/Disable all session related actions + connect/disconnect
|
|
enableAction("debug_request", enable);
|
|
enableAction("debug_run", enable);
|
|
enableAction("debug_trace", enable);
|
|
enableAction("debug_pause", enable);
|
|
enableAction("debug_kill", enable);
|
|
enableAction("debug_stepover", enable);
|
|
enableAction("debug_stepinto", enable);
|
|
enableAction("debug_stepout", enable);
|
|
enableAction("debug_skip", enable);
|
|
|
|
enableAction("debug_connect", enable);
|
|
enableAction("debug_disconnect", enable);
|
|
|
|
enableAction("debug_breakpoints_toggle", enable);
|
|
enableAction("debug_breakpoints_clear", enable);
|
|
|
|
enableAction("debug_profiler_open", enable);
|
|
|
|
}
|
|
else
|
|
{
|
|
// The action may or may not exist, depending on capabilities of the debugger plugin
|
|
TDEActionCollection *ac = quantaApp->actionCollection();
|
|
if(ac && ac->action(action.ascii()))
|
|
ac->action(action.ascii())->setEnabled(enable);
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotRemoveVariable(DebuggerVariable* var)
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->removeWatch(var);
|
|
|
|
}
|
|
|
|
void DebuggerManager::slotRemoveBreakpoint(DebuggerBreakpoint* bp)
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
m_breakpointList->remove(bp);
|
|
m_client->removeBreakpoint(bp);
|
|
|
|
}
|
|
|
|
|
|
void DebuggerManager::slotAddWatch()
|
|
{
|
|
kdDebug(24002) << "DebuggerManager::slotAddWatch() " << endl;
|
|
if(!m_client)
|
|
return;
|
|
|
|
|
|
TQString watch = KInputDialog::getText(i18n("Add Watch"), i18n("Specify variable to watch:"), quantaApp->popupWord);
|
|
quantaApp->popupWord = "";
|
|
if(!watch.isEmpty())
|
|
{
|
|
DebuggerVariable *var = new DebuggerVariable(watch, "", DebuggerVariableTypes::Undefined);
|
|
m_debuggerui->addVariable(var);
|
|
m_client->addWatch(watch);
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotVariableSet()
|
|
{
|
|
kdDebug(24002) << "DebuggerManager::slotVariableSet(" << quantaApp->popupWord << ") " << endl;
|
|
if(!m_client)
|
|
return;
|
|
|
|
|
|
DebuggerVariableSetS dlg;
|
|
dlg.lineVariable->setText(quantaApp->popupWord);
|
|
quantaApp->popupWord = "";
|
|
if(dlg.exec() == TQDialog::Accepted)
|
|
{
|
|
DebuggerVariable var;
|
|
var.setName(dlg.lineVariable->text());
|
|
var.setValue(dlg.lineValue->text());
|
|
m_client->variableSetValue(var);
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotConditionalBreakpoint()
|
|
{
|
|
TQString file;
|
|
|
|
kdDebug(24002) << "DebuggerManager::slotConditionalBreakpoint() " << quantaApp->popupWord << endl;
|
|
if(!m_client)
|
|
return;
|
|
|
|
Document *w = ViewManager::ref()->activeDocument();
|
|
if (w)
|
|
file = w->url().prettyURL(0, KURL::StripFileProtocol);
|
|
|
|
ConditionalBreakpointDialog dlg(quantaApp->popupWord, file, "", "");
|
|
quantaApp->popupWord = "";
|
|
if(dlg.exec() == TQDialog::Accepted)
|
|
{
|
|
DebuggerBreakpoint * bp = dlg.breakpoint();
|
|
if(bp)
|
|
{
|
|
m_client->addBreakpoint(bp);
|
|
m_breakpointList->add(bp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotDebugStartSession()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->startSession();
|
|
}
|
|
|
|
void DebuggerManager::slotDebugEndSession()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->endSession();
|
|
}
|
|
|
|
void DebuggerManager::slotDebugRequest()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->request();
|
|
}
|
|
|
|
void DebuggerManager::slotDebugTrace()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->trace();
|
|
}
|
|
|
|
void DebuggerManager::slotDebugRun()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->run();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugSkip()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->skip();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugStepOver()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->stepOver();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugStepInto()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->stepInto();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugPause()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->pause();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugKill()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->kill();
|
|
|
|
}
|
|
void DebuggerManager::slotDebugStepOut()
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->stepOut();
|
|
|
|
}
|
|
|
|
void DebuggerManager::slotProfilerOpen( )
|
|
{
|
|
if(!m_client)
|
|
return;
|
|
|
|
m_client->profilerOpen();
|
|
}
|
|
|
|
// A new file was opened, tell the debugger so it can tell us about breakpoints etc
|
|
void DebuggerManager::fileOpened(const TQString& file)
|
|
{
|
|
|
|
// Set breakpoint markers if we have a bp in the file
|
|
m_breakpointList->rewind();
|
|
DebuggerBreakpoint* bp;
|
|
while((bp = m_breakpointList->next()))
|
|
{
|
|
if(bp->filePath() == file)
|
|
{
|
|
setMark(bp->filePath(), bp->line(), true, KTextEditor::MarkInterface::markType02);
|
|
}
|
|
}
|
|
|
|
//lets keep the eye on toggling bp's through the editor margin
|
|
QuantaView *view = ViewManager::ref()->isOpened(KURL::fromPathOrURL(file));
|
|
if (view)
|
|
{
|
|
::Document* qdoc = view->document();
|
|
if(qdoc)
|
|
{
|
|
connectBreakpointSignals(qdoc);
|
|
}
|
|
}
|
|
|
|
// Also, if we have a debug-session, let the debugger know...
|
|
if(m_client)
|
|
m_client->fileOpened(file);
|
|
}
|
|
|
|
// Check with editors if breakpoints changed and send all breakpoint (again) to client
|
|
void DebuggerManager::refreshBreakpoints()
|
|
{
|
|
// Resend bps
|
|
m_breakpointList->rewind();
|
|
DebuggerBreakpoint* bp;
|
|
while((bp = m_breakpointList->next()))
|
|
{
|
|
m_client->addBreakpoint(bp);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// The debug server told us we have a breakpoint, mark it in the file
|
|
void DebuggerManager::haveBreakpoint (const TQString& file, int line)
|
|
{
|
|
setMark(file, line, true, KTextEditor::MarkInterface::markType02);
|
|
}
|
|
|
|
// The debug server told us we DONT have a breakpoint, remove it
|
|
void DebuggerManager::havenoBreakpoint (const TQString& file, int line)
|
|
{
|
|
DebuggerBreakpoint* br = new DebuggerBreakpoint(file, line);
|
|
m_breakpointList->remove(br);
|
|
setMark(file, line, false, KTextEditor::MarkInterface::markType02);
|
|
m_breakpointList->remove(br);
|
|
}
|
|
|
|
// New current line
|
|
bool DebuggerManager::setActiveLine (const TQString& file, int line )
|
|
{
|
|
//Get local filename
|
|
TQString filename = file;
|
|
|
|
// Remove old active line mark
|
|
setMark(m_currentFile, m_currentLine, false, KTextEditor::MarkInterface::markType05);
|
|
|
|
// Update vars with active line
|
|
m_currentFile = filename;
|
|
m_currentLine = line;
|
|
|
|
// No new current position
|
|
if(filename.isEmpty() || quantaApp->previewVisible())
|
|
return true;
|
|
|
|
// Find new position in editor
|
|
if(ViewManager::ref()->isOpened(filename) || QExtFileInfo::exists(filename, true, 0L))
|
|
quantaApp->gotoFileAndLine(filename, line, 0);
|
|
else
|
|
{
|
|
showStatus(i18n("Unable to open file %1, check your basedirs and mappings.").arg(filename), true);
|
|
}
|
|
|
|
// Add new active line mark
|
|
setMark(filename, line, true, KTextEditor::MarkInterface::markType05);
|
|
return true;
|
|
}
|
|
|
|
// Set/clear a mark in a document
|
|
void DebuggerManager::setMark(const TQString& filename, long line, bool set, int mark)
|
|
{
|
|
if((!filename.isEmpty()) && ViewManager::ref()->isOpened(filename))
|
|
{
|
|
::Document* qdoc = ViewManager::ref()->isOpened(filename)->document();
|
|
if(qdoc)
|
|
{
|
|
disconnectBreakpointSignals(qdoc);
|
|
|
|
KTextEditor::Document* doc = qdoc->doc();
|
|
if(doc)
|
|
{
|
|
KTextEditor::MarkInterface *markIf = dynamic_cast<KTextEditor::MarkInterface*>(doc);
|
|
if(markIf)
|
|
{
|
|
if(set)
|
|
markIf->addMark(line, mark);
|
|
else
|
|
markIf->removeMark(line, mark);
|
|
}
|
|
}
|
|
connectBreakpointSignals(qdoc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::connectBreakpointSignals(Document* qdoc)
|
|
{
|
|
connect(qdoc, TQ_SIGNAL(breakpointMarked(Document*, int)),
|
|
this, TQ_SLOT(slotBreakpointMarked(Document*, int)));
|
|
|
|
connect(qdoc, TQ_SIGNAL(breakpointUnmarked(Document*, int)),
|
|
this, TQ_SLOT(slotBreakpointUnmarked(Document*, int)));
|
|
}
|
|
|
|
void DebuggerManager::disconnectBreakpointSignals(Document* qdoc)
|
|
{
|
|
disconnect(qdoc, TQ_SIGNAL(breakpointMarked(Document*, int)),
|
|
this, TQ_SLOT(slotBreakpointMarked(Document*, int)));
|
|
|
|
disconnect(qdoc, TQ_SIGNAL(breakpointUnmarked(Document*, int)),
|
|
this, TQ_SLOT(slotBreakpointUnmarked(Document*, int)));
|
|
}
|
|
|
|
// Show a status message and optionally put it on the log
|
|
bool DebuggerManager::showStatus(const TQString& a_message, bool log)
|
|
{
|
|
TQString message = a_message;
|
|
quantaApp->slotStatusMsg(m_client->getName() + ": " + message);
|
|
|
|
if(log)
|
|
{
|
|
if(!message.endsWith("\n"))
|
|
message.append("\n");
|
|
quantaApp->messageOutput()->showMessage(m_client->getName() + ": " + message);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void DebuggerManager::toggleBreakpoint ()
|
|
{
|
|
Document *w = ViewManager::ref()->activeDocument();
|
|
if (w)
|
|
{
|
|
uint line, col;
|
|
w->viewCursorIf->cursorPositionReal(&line, &col);
|
|
|
|
DebuggerBreakpoint* br = m_breakpointList->retrieve(w->url().prettyURL(0, KURL::StripFileProtocol), line);
|
|
|
|
if(!br)
|
|
{
|
|
DebuggerBreakpoint* br = new DebuggerBreakpoint(w->url().prettyURL(0, KURL::StripFileProtocol), line);
|
|
m_breakpointList->add(br);
|
|
// setMark(w->url().prettyURL(0, KURL::StripFileProtocol), br->line(), true, KTextEditor::MarkInterface::markType02); // FIXME Is this really needed?
|
|
if(m_client && m_client->isActive())
|
|
{
|
|
DebuggerBreakpoint tmpbp = *br;
|
|
m_client->addBreakpoint(br);
|
|
|
|
}
|
|
else
|
|
// Trigger pathmapper to make sure we have a valid translation...
|
|
m_pathmapper->mapLocalPathToServer(w->url().prettyURL(0, KURL::StripFileProtocol));
|
|
}
|
|
else
|
|
{
|
|
m_breakpointList->remove(br);
|
|
// setMark(w->url().prettyURL(0, KURL::StripFileProtocol), br->line(), false, KTextEditor::MarkInterface::markType02); // FIXME Is this really needed?
|
|
|
|
if(m_client && m_client->isActive())
|
|
{
|
|
m_client->removeBreakpoint(br);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void DebuggerManager::clearBreakpoints ()
|
|
{
|
|
m_breakpointList->clear();
|
|
}
|
|
|
|
void DebuggerManager::slotBreakpointMarked(Document* qdoc, int line)
|
|
{
|
|
DebuggerBreakpoint* br = new DebuggerBreakpoint(qdoc->url().prettyURL(0, KURL::StripFileProtocol), line);
|
|
|
|
m_breakpointList->add(br);
|
|
if(m_client && m_client->isActive())
|
|
{
|
|
m_client->addBreakpoint(br);
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotBreakpointUnmarked(Document* qdoc, int line)
|
|
{
|
|
TQString filePath = qdoc->url().prettyURL(0, KURL::StripFileProtocol);
|
|
|
|
DebuggerBreakpoint* br = m_breakpointList->retrieve(filePath, line);
|
|
|
|
if (br)
|
|
{
|
|
if(m_client && m_client->isActive())
|
|
{
|
|
m_client->removeBreakpoint(br);
|
|
}
|
|
|
|
m_breakpointList->remove(br);
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::updateBreakpointKey( const DebuggerBreakpoint & bp, const TQString & newkey )
|
|
{
|
|
m_breakpointList->updateBreakpointKey(bp, newkey);
|
|
|
|
// Update UI
|
|
m_debuggerui->deleteBreakpoint(bp);
|
|
DebuggerBreakpoint bpnew(bp);
|
|
bpnew.setKey(newkey);
|
|
m_debuggerui->showBreakpoint(bpnew);
|
|
|
|
}
|
|
|
|
DebuggerBreakpoint * DebuggerManager::findDebuggerBreakpoint( const TQString & key )
|
|
{
|
|
return m_breakpointList->findDebuggerBreakpoint(key);
|
|
}
|
|
|
|
void DebuggerManager::saveProperties( )
|
|
{
|
|
|
|
if (m_client)
|
|
{
|
|
TQDomDocument *dom = Project::ref()->sessionDom();
|
|
TQDomNode projectNode = dom->firstChild().firstChild();
|
|
TQDomNode nodeDbg = projectNode.namedItem("debuggers");
|
|
if(nodeDbg.isNull())
|
|
{
|
|
nodeDbg = dom->createElement("debuggers");
|
|
projectNode.appendChild(nodeDbg);
|
|
}
|
|
|
|
// Save breakpoints
|
|
if(Project::ref()->debuggerPersistentBreakpoints())
|
|
{
|
|
// (Re)create breakpoints section
|
|
TQDomNode nodeBreakpoints = nodeDbg.namedItem("breakpoints");
|
|
if(!nodeBreakpoints.isNull())
|
|
nodeBreakpoints.parentNode().removeChild(nodeBreakpoints);
|
|
|
|
if(m_breakpointList->count() > 0)
|
|
{
|
|
nodeBreakpoints = dom->createElement("breakpoints");
|
|
nodeDbg.appendChild(nodeBreakpoints);
|
|
|
|
|
|
// Loop breakpoints and save 'em
|
|
m_breakpointList->rewind();
|
|
DebuggerBreakpoint* bp;
|
|
while((bp = m_breakpointList->next()))
|
|
{
|
|
TQDomElement child = dom->createElement("breakpoint");
|
|
child.setAttribute("filepath", bp->filePath());
|
|
child.setAttribute("class", bp->inClass());
|
|
child.setAttribute("function", bp->inFunction());
|
|
child.setAttribute("condition", bp->condition());
|
|
child.setAttribute("line", TQString::number(bp->line()));
|
|
if(bp->type() == DebuggerBreakpoint::ConditionalTrue)
|
|
child.setAttribute("type", "true");
|
|
else if(bp->type() == DebuggerBreakpoint::ConditionalChange)
|
|
child.setAttribute("type", "change");
|
|
else
|
|
child.setAttribute("type", "line");
|
|
|
|
nodeBreakpoints.appendChild(child);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save Watches
|
|
if(Project::ref()->debuggerPersistentWatches())
|
|
{
|
|
// (Re)create watches section
|
|
TQDomNode nodeWatches = nodeDbg.namedItem("watches");
|
|
if(!nodeWatches.isNull())
|
|
nodeWatches.parentNode().removeChild(nodeWatches);
|
|
|
|
if(m_debuggerui->watches()->first())
|
|
{
|
|
nodeWatches = dom->createElement("watches");
|
|
nodeDbg.appendChild(nodeWatches);
|
|
|
|
// Loop watches and save 'em
|
|
for( DebuggerVariable *v = m_debuggerui->watches()->first(); v; v = m_debuggerui->watches()->next())
|
|
{
|
|
TQDomElement child = dom->createElement("watch");
|
|
child.setAttribute("name", v->name());
|
|
|
|
nodeWatches.appendChild(child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebuggerManager::slotHandleEvent( const TQString & event, const TQString &, const TQString & )
|
|
{
|
|
if(event == "before_project_close")
|
|
saveProperties();
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "debuggermanager.moc"
|