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.
kdbg/kdbg/brkpt.cpp

514 lines
14 KiB

/*
* Copyright Johannes Sixt
* This file is licensed under the GNU General Public License Version 2.
* See the file COPYING in the toplevel directory of the source directory.
*/
#include <tdeapplication.h>
#include <tdelocale.h> /* i18n */
#include <kiconloader.h>
#include <ksimpleconfig.h>
#include <tqdialog.h>
#include <tqkeycode.h>
#include <tqpainter.h>
#include <tqlabel.h>
#include <tqbitmap.h>
#include "debugger.h"
#include "brkpt.h"
#include "dbgdriver.h"
#include <ctype.h>
#include <list>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mydebug.h"
class BreakpointItem : public TQListViewItem, public Breakpoint
{
public:
BreakpointItem(TQListView* list, const Breakpoint& bp);
void updateFrom(const Breakpoint& bp);
void display(); /* sets icon and visible texts */
bool enabled() const { return Breakpoint::enabled; }
};
BreakpointTable::BreakpointTable(TQWidget* parent, const char* name) :
TQWidget(parent, name),
m_debugger(0),
m_bpEdit(this, "bpedit"),
m_list(this, "bptable"),
m_btAddBP(this, "addbp"),
m_btAddWP(this, "addwp"),
m_btRemove(this, "remove"),
m_btEnaDis(this, "enadis"),
m_btViewCode(this, "view"),
m_btConditional(this, "conditional"),
m_layout(this, 8),
m_listandedit(8),
m_buttons(8)
{
m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
initListAndIcons();
connect(&m_list, SIGNAL(currentChanged(TQListViewItem*)), SLOT(updateUI()));
// double click on item is same as View code
connect(&m_list, SIGNAL(doubleClicked(TQListViewItem*)), this, SLOT(viewBP()));
// need mouse button events
m_list.viewport()->installEventFilter(this);
m_btAddBP.setText(i18n("Add &Breakpoint"));
m_btAddBP.setMinimumSize(m_btAddBP.sizeHint());
connect(&m_btAddBP, SIGNAL(clicked()), this, SLOT(addBP()));
m_btAddWP.setText(i18n("Add &Watchpoint"));
m_btAddWP.setMinimumSize(m_btAddWP.sizeHint());
connect(&m_btAddWP, SIGNAL(clicked()), this, SLOT(addWP()));
m_btRemove.setText(i18n("&Remove"));
m_btRemove.setMinimumSize(m_btRemove.sizeHint());
connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP()));
// the Enable/Disable button changes its label
m_btEnaDis.setText(i18n("&Disable"));
// make a dummy button to get the size of the alternate label
{
TQSize size = m_btEnaDis.sizeHint();
TQPushButton dummy(this);
dummy.setText(i18n("&Enable"));
TQSize sizeAlt = dummy.sizeHint();
if (sizeAlt.width() > size.width())
size.setWidth(sizeAlt.width());
if (sizeAlt.height() > size.height())
size.setHeight(sizeAlt.height());
m_btEnaDis.setMinimumSize(size);
}
connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP()));
m_btViewCode.setText(i18n("&View Code"));
m_btViewCode.setMinimumSize(m_btViewCode.sizeHint());
connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP()));
m_btConditional.setText(i18n("&Conditional..."));
m_btConditional.setMinimumSize(m_btConditional.sizeHint());
connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP()));
m_layout.addLayout(&m_listandedit, 10);
m_layout.addLayout(&m_buttons);
m_listandedit.addWidget(&m_bpEdit);
m_listandedit.addWidget(&m_list, 10);
m_buttons.addWidget(&m_btAddBP);
m_buttons.addWidget(&m_btAddWP);
m_buttons.addWidget(&m_btRemove);
m_buttons.addWidget(&m_btEnaDis);
m_buttons.addWidget(&m_btViewCode);
m_buttons.addWidget(&m_btConditional);
m_buttons.addStretch(10);
m_layout.activate();
resize(350, 300);
m_bpEdit.setFocus();
}
BreakpointTable::~BreakpointTable()
{
}
void BreakpointTable::updateBreakList()
{
std::list<BreakpointItem*> deletedItems;
for (TQListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
deletedItems.push_back(static_cast<BreakpointItem*>(it));
}
// get the new list
for (KDebugger::BrkptROIterator bp = m_debugger->breakpointsBegin(); bp != m_debugger->breakpointsEnd(); ++bp)
{
// look up this item
for (std::list<BreakpointItem*>::iterator o = deletedItems.begin(); o != deletedItems.end(); ++o)
{
if ((*o)->id == bp->id) {
(*o)->updateFrom(*bp);
deletedItems.erase(o); /* don't delete */
goto nextItem;
}
}
// not in the list; add it
new BreakpointItem(&m_list, *bp);
nextItem:;
}
// delete all untouched breakpoints
while (!deletedItems.empty()) {
delete deletedItems.front();
deletedItems.pop_front();
}
}
BreakpointItem::BreakpointItem(TQListView* list, const Breakpoint& bp) :
TQListViewItem(list),
Breakpoint(bp)
{
display();
}
void BreakpointItem::updateFrom(const Breakpoint& bp)
{
Breakpoint::operator=(bp); /* assign new values */
display();
}
void BreakpointTable::addBP()
{
// set a breakpoint at the specified text
TQString bpText = m_bpEdit.text();
bpText = bpText.stripWhiteSpace();
if (m_debugger->isReady())
{
Breakpoint* bp = new Breakpoint;
bp->text = bpText;
m_debugger->setBreakpoint(bp, false);
}
}
void BreakpointTable::addWP()
{
// set a watchpoint for the specified expression
TQString wpExpr = m_bpEdit.text();
wpExpr = wpExpr.stripWhiteSpace();
if (m_debugger->isReady()) {
Breakpoint* bp = new Breakpoint;
bp->type = Breakpoint::watchpoint;
bp->text = wpExpr;
m_debugger->setBreakpoint(bp, false);
}
}
void BreakpointTable::removeBP()
{
BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
if (bp != 0) {
m_debugger->deleteBreakpoint(bp->id);
// note that bp may be deleted by now
// (if bp was an orphaned breakpoint)
}
}
void BreakpointTable::enadisBP()
{
BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
if (bp != 0) {
m_debugger->enableDisableBreakpoint(bp->id);
}
}
void BreakpointTable::viewBP()
{
BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
if (bp == 0)
return;
emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
}
void BreakpointTable::updateUI()
{
bool enableChkpt = m_debugger->canChangeBreakpoints();
m_btAddBP.setEnabled(enableChkpt);
m_btAddWP.setEnabled(enableChkpt);
BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
m_btViewCode.setEnabled(bp != 0);
if (bp == 0) {
enableChkpt = false;
} else {
if (bp->enabled()) {
m_btEnaDis.setText(i18n("&Disable"));
} else {
m_btEnaDis.setText(i18n("&Enable"));
}
}
m_btRemove.setEnabled(enableChkpt);
m_btEnaDis.setEnabled(enableChkpt);
m_btConditional.setEnabled(enableChkpt);
}
bool BreakpointTable::eventFilter(TQObject* ob, TQEvent* ev)
{
if (ev->type() == TQEvent::MouseButtonPress)
{
TQMouseEvent* mev = static_cast<TQMouseEvent*>(ev);
if (mev->button() == MidButton) {
// enable or disable the clicked-on item
BreakpointItem* bp =
static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
if (bp != 0)
{
m_debugger->enableDisableBreakpoint(bp->id);
}
return true;
}
}
return TQWidget::eventFilter(ob, ev);
}
class ConditionalDlg : public TQDialog
{
public:
ConditionalDlg(TQWidget* parent);
~ConditionalDlg();
void setCondition(const TQString& text) { m_condition.setText(text); }
TQString condition() { return m_condition.text(); }
void setIgnoreCount(uint count);
uint ignoreCount();
protected:
TQLabel m_conditionLabel;
TQLineEdit m_condition;
TQLabel m_ignoreLabel;
TQLineEdit m_ignoreCount;
TQPushButton m_buttonOK;
TQPushButton m_buttonCancel;
TQVBoxLayout m_layout;
TQGridLayout m_inputs;
TQHBoxLayout m_buttons;
};
void BreakpointTable::conditionalBP()
{
BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
if (bp == 0)
return;
/*
* Important: we must not keep a pointer to the Breakpoint around,
* since it may vanish while the modal dialog is open through other
* user interactions (like clicking at the breakpoint in the source
* window)!
*/
int id = bp->id;
ConditionalDlg dlg(this);
dlg.setCondition(bp->condition);
dlg.setIgnoreCount(bp->ignoreCount);
if (dlg.exec() != TQDialog::Accepted)
return;
TQString conditionInput = dlg.condition();
int ignoreCount = dlg.ignoreCount();
m_debugger->conditionalBreakpoint(id, conditionInput, ignoreCount);
}
void BreakpointTable::initListAndIcons()
{
m_list.addColumn(i18n("Location"), 220);
m_list.addColumn(i18n("Address"), 65);
m_list.addColumn(i18n("Hits"), 30);
m_list.addColumn(i18n("Ignore"), 30);
m_list.addColumn(i18n("Condition"), 200);
m_list.setMinimumSize(200, 100);
m_list.setSorting(-1);
// add pixmaps
TQPixmap brkena = UserIcon("brkena.xpm");
TQPixmap brkdis = UserIcon("brkdis.xpm");
TQPixmap watchena = UserIcon("watchena.xpm");
TQPixmap watchdis = UserIcon("watchdis.xpm");
TQPixmap brktmp = UserIcon("brktmp.xpm");
TQPixmap brkcond = UserIcon("brkcond.xpm");
TQPixmap brkorph = UserIcon("brkorph.xpm");
/*
* There are 32 different pixmaps: The basic enabled or disabled
* breakpoint, plus an optional overlaid brktmp icon plus an optional
* overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
* the same sequence for watchpoints.
*/
m_icons.resize(32);
TQPixmap canvas(16,16);
for (int i = 0; i < 32; i++) {
{
TQPainter p(&canvas);
// clear canvas
p.fillRect(0,0, canvas.width(),canvas.height(), cyan);
// basic icon
if (i & 1) {
p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
} else {
p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
}
// temporary overlay
if (i & 2) {
p.drawPixmap(1,1, brktmp);
}
// conditional overlay
if (i & 4) {
p.drawPixmap(1,1, brkcond);
}
// orphan overlay
if (i & 16) {
p.drawPixmap(1,1, brkorph);
}
}
canvas.setMask(canvas.createHeuristicMask());
m_icons[i] = canvas;
}
}
void BreakpointItem::display()
{
BreakpointTable* lb = static_cast<BreakpointTable*>(listView()->parent());
/* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
int code = enabled() ? 1 : 0;
if (temporary)
code += 2;
if (!condition.isEmpty() || ignoreCount > 0)
code += 4;
if (type == watchpoint)
code += 8;
if (isOrphaned())
code += 16;
setPixmap(0, lb->m_icons[code]);
// more breakpoint info
if (!location.isEmpty()) {
setText(0, location);
} else if (!Breakpoint::text.isEmpty()) {
setText(0, Breakpoint::text);
} else if (!fileName.isEmpty()) {
// use only the file name portion
TQString file = fileName;
int slash = file.findRev('/');
if (slash >= 0) {
file = file.mid(slash+1);
}
// correct zero-based line-numbers
setText(0, file + ":" + TQString::number(lineNo+1));
} else {
setText(0, "*" + address.asString());
}
int c = 0;
setText(++c, address.asString());
TQString tmp;
if (hitCount == 0) {
setText(++c, TQString());
} else {
tmp.setNum(hitCount);
setText(++c, tmp);
}
if (ignoreCount == 0) {
setText(++c, TQString());
} else {
tmp.setNum(ignoreCount);
setText(++c, tmp);
}
if (condition.isEmpty()) {
setText(++c, TQString());
} else {
setText(++c, condition);
}
}
ConditionalDlg::ConditionalDlg(TQWidget* parent) :
TQDialog(parent, "conditional", true),
m_conditionLabel(this, "condLabel"),
m_condition(this, "condition"),
m_ignoreLabel(this, "ignoreLabel"),
m_ignoreCount(this, "ignoreCount"),
m_buttonOK(this, "ok"),
m_buttonCancel(this, "cancel"),
m_layout(this, 10),
m_inputs(2, 2, 10),
m_buttons(4)
{
TQString title = kapp->caption();
title += i18n(": Conditional breakpoint");
setCaption(title);
m_conditionLabel.setText(i18n("&Condition:"));
m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
m_ignoreLabel.setText(i18n("Ignore &next hits:"));
m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
m_condition.setMinimumSize(150, 24);
m_condition.setMaxLength(10000);
m_condition.setFrame(true);
m_ignoreCount.setMinimumSize(150, 24);
m_ignoreCount.setMaxLength(10000);
m_ignoreCount.setFrame(true);
m_conditionLabel.setBuddy(&m_condition);
m_ignoreLabel.setBuddy(&m_ignoreCount);
m_buttonOK.setMinimumSize(100, 30);
connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
m_buttonOK.setText(i18n("OK"));
m_buttonOK.setDefault(true);
m_buttonCancel.setMinimumSize(100, 30);
connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
m_buttonCancel.setText(i18n("Cancel"));
m_layout.addLayout(&m_inputs);
m_inputs.addWidget(&m_conditionLabel, 0, 0);
m_inputs.addWidget(&m_condition, 0, 1);
m_inputs.addWidget(&m_ignoreLabel, 1, 0);
m_inputs.addWidget(&m_ignoreCount, 1, 1);
m_inputs.setColStretch(1, 10);
m_layout.addLayout(&m_buttons);
m_layout.addStretch(10);
m_buttons.addStretch(10);
m_buttons.addWidget(&m_buttonOK);
m_buttons.addSpacing(40);
m_buttons.addWidget(&m_buttonCancel);
m_buttons.addStretch(10);
m_layout.activate();
m_condition.setFocus();
resize(400, 100);
}
ConditionalDlg::~ConditionalDlg()
{
}
uint ConditionalDlg::ignoreCount()
{
bool ok;
TQString input = m_ignoreCount.text();
uint result = input.toUInt(&ok);
return ok ? result : 0;
}
void ConditionalDlg::setIgnoreCount(uint count)
{
TQString text;
// set empty if ignore count is zero
if (count > 0) {
text.setNum(count);
}
m_ignoreCount.setText(text);
}
#include "brkpt.moc"