Breakpoints can be enabled and disabled from breakpoints list.
[kdbg.git] / kdbg / brkpt.cpp
blob7daf020ae9c34420164038ec525acf16f5ec3138
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <kapp.h> /* i18n */
7 #if QT_VERSION >= 200
8 #include <klocale.h> /* i18n */
9 #endif
10 #include <kiconloader.h>
11 #include <ksimpleconfig.h>
12 #include <qdialog.h>
13 #include <qkeycode.h>
14 #include <qpainter.h>
15 #include <qlabel.h>
16 #include <qbitmap.h>
17 #include "debugger.h"
18 #include "brkpt.h"
19 #include "dbgdriver.h"
20 #include "brkpt.moc"
21 #include <ctype.h>
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "mydebug.h"
28 class BreakpointItem : public QListViewItem, public Breakpoint
30 public:
31 BreakpointItem(QListView* list, const Breakpoint& bp);
32 void updateFrom(const Breakpoint& bp);
33 void display(); /* sets icon and visible texts */
37 BreakpointTable::BreakpointTable(QWidget* parent, const char* name) :
38 QWidget(parent, name),
39 m_debugger(0),
40 m_bpEdit(this, "bpedit"),
41 m_list(this, "bptable"),
42 m_btAdd(this, "add"),
43 m_btRemove(this, "remove"),
44 m_btEnaDis(this, "enadis"),
45 m_btViewCode(this, "view"),
46 m_btConditional(this, "conditional"),
47 m_layout(this, 8),
48 m_listandedit(8),
49 m_buttons(8)
51 m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
52 connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
54 initListAndIcons();
55 connect(&m_list, SIGNAL(currentChanged(QListViewItem*)), SLOT(updateUI()));
56 // double click on item is same as View code
57 connect(&m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(viewBP()));
59 // need mouse button events
60 m_list.viewport()->installEventFilter(this);
62 m_btAdd.setText(i18n("&Add"));
63 m_btAdd.setMinimumSize(m_btAdd.sizeHint());
64 connect(&m_btAdd, SIGNAL(clicked()), this, SLOT(addBP()));
66 m_btRemove.setText(i18n("&Remove"));
67 m_btRemove.setMinimumSize(m_btRemove.sizeHint());
68 connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP()));
70 // the Enable/Disable button changes its label
71 m_btEnaDis.setText(i18n("&Disable"));
72 // make a dummy button to get the size of the alternate label
74 QSize size = m_btEnaDis.sizeHint();
75 QPushButton dummy(this);
76 dummy.setText(i18n("&Enable"));
77 QSize sizeAlt = dummy.sizeHint();
78 if (sizeAlt.width() > size.width())
79 size.setWidth(sizeAlt.width());
80 if (sizeAlt.height() > size.height())
81 size.setHeight(sizeAlt.height());
82 m_btEnaDis.setMinimumSize(size);
84 connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP()));
86 m_btViewCode.setText(i18n("&View Code"));
87 m_btViewCode.setMinimumSize(m_btViewCode.sizeHint());
88 connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP()));
90 m_btConditional.setText(i18n("&Conditional..."));
91 m_btConditional.setMinimumSize(m_btConditional.sizeHint());
92 connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP()));
94 m_layout.addLayout(&m_listandedit, 10);
95 m_layout.addLayout(&m_buttons);
96 m_listandedit.addWidget(&m_bpEdit);
97 m_listandedit.addWidget(&m_list, 10);
98 m_buttons.addWidget(&m_btAdd);
99 m_buttons.addWidget(&m_btRemove);
100 m_buttons.addWidget(&m_btEnaDis);
101 m_buttons.addWidget(&m_btViewCode);
102 m_buttons.addWidget(&m_btConditional);
103 m_buttons.addStretch(10);
105 m_layout.activate();
107 resize(350, 300);
109 m_bpEdit.setFocus();
112 BreakpointTable::~BreakpointTable()
116 void BreakpointTable::updateBreakList()
118 QList<BreakpointItem> deletedItems;
120 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
121 deletedItems.append(static_cast<BreakpointItem*>(it));
124 // get the new list
125 for (int i = m_debugger->numBreakpoints()-1; i >= 0; i--) {
126 const Breakpoint* bp = m_debugger->breakpoint(i);
127 // look up this item
128 for (BreakpointItem* oldbp = deletedItems.first(); oldbp != 0;
129 oldbp = deletedItems.next())
131 if (oldbp->id == bp->id) {
132 oldbp->updateFrom(*bp);
133 deletedItems.take(); /* don't delete */
134 goto nextItem;
137 // not in the list; add it
138 new BreakpointItem(&m_list, *bp);
139 nextItem:;
142 // delete all untouched breakpoints
143 deletedItems.setAutoDelete(true);
146 BreakpointItem::BreakpointItem(QListView* list, const Breakpoint& bp) :
147 QListViewItem(list),
148 Breakpoint(bp)
150 display();
153 void BreakpointItem::updateFrom(const Breakpoint& bp)
155 Breakpoint::operator=(bp); /* assign new values */
156 display();
159 void BreakpointTable::addBP()
161 // set a breakpoint at the specified text
162 QString bpText = m_bpEdit.text();
163 bpText = bpText.stripWhiteSpace();
164 if (m_debugger->isReady()) {
165 m_debugger->driver()->executeCmd(DCbreaktext, bpText);
166 // clear text if successfully set
167 m_bpEdit.setText("");
171 void BreakpointTable::removeBP()
173 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
174 if (bp == 0)
175 return;
177 m_debugger->driver()->executeCmd(DCdelete, bp->id);
180 void BreakpointTable::enadisBP()
182 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
183 if (bp == 0)
184 return;
186 DbgCommand cmd = bp->enabled ? DCdisable : DCenable;
187 m_debugger->driver()->executeCmd(cmd, bp->id);
190 void BreakpointTable::viewBP()
192 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
193 if (bp == 0)
194 return;
196 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
199 void BreakpointTable::updateUI()
201 bool enableChkpt = m_debugger->canChangeBreakpoints();
202 m_btAdd.setEnabled(enableChkpt);
204 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
205 m_btViewCode.setEnabled(bp != 0);
207 if (bp == 0) {
208 enableChkpt = false;
209 } else {
210 if (bp->enabled) {
211 m_btEnaDis.setText(i18n("&Disable"));
212 } else {
213 m_btEnaDis.setText(i18n("&Enable"));
216 m_btRemove.setEnabled(enableChkpt);
217 m_btEnaDis.setEnabled(enableChkpt);
218 m_btConditional.setEnabled(enableChkpt);
221 #if QT_VERSION < 200
222 # define MOUSEPRESS Event_MouseButtonPress
223 #else
224 # define MOUSEPRESS QEvent::MouseButtonPress
225 #endif
227 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
229 if (ev->type() == MOUSEPRESS)
231 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
232 if (mev->button() == MidButton) {
233 // enable or disable the clicked-on item
234 BreakpointItem* bp =
235 static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
236 if (bp != 0 && m_debugger->canChangeBreakpoints())
238 DbgCommand cmd = bp->enabled ? DCdisable : DCenable;
239 m_debugger->driver()->executeCmd(cmd, bp->id);
241 return true;
244 return QWidget::eventFilter(ob, ev);
247 class ConditionalDlg : public QDialog
249 public:
250 ConditionalDlg(QWidget* parent);
251 ~ConditionalDlg();
253 void setCondition(const char* text) { m_condition.setText(text); }
254 const char* condition() { return m_condition.text(); }
255 void setIgnoreCount(uint count);
256 uint ignoreCount();
258 protected:
259 QLabel m_conditionLabel;
260 QLineEdit m_condition;
261 QLabel m_ignoreLabel;
262 QLineEdit m_ignoreCount;
263 QPushButton m_buttonOK;
264 QPushButton m_buttonCancel;
265 QVBoxLayout m_layout;
266 QGridLayout m_inputs;
267 QHBoxLayout m_buttons;
270 void BreakpointTable::conditionalBP()
272 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
273 if (bp == 0)
274 return;
277 * Important: we must not keep a pointer to the Breakpoint around,
278 * since it may vanish while the modal dialog is open through other
279 * user interactions (like clicking at the breakpoint in the source
280 * window)!
282 int id = bp->id;
284 ConditionalDlg dlg(this);
285 dlg.setCondition(bp->condition);
286 dlg.setIgnoreCount(bp->ignoreCount);
288 if (dlg.exec() != QDialog::Accepted)
289 return;
291 QString conditionInput = dlg.condition();
292 int ignoreCount = dlg.ignoreCount();
293 updateBreakpointCondition(id, conditionInput, ignoreCount);
296 void BreakpointTable::updateBreakpointCondition(int id,
297 const QString& condition,
298 int ignoreCount)
300 BreakpointItem* bp = itemByBreakId(id);
301 if (bp == 0)
302 return; /* breakpoint no longer exists */
304 bool changed = false;
306 if (bp->condition != condition) {
307 // change condition
308 m_debugger->driver()->executeCmd(DCcondition, condition, bp->id);
309 bp->condition = condition;
310 changed = true;
312 if (bp->ignoreCount != ignoreCount) {
313 // change ignore count
314 m_debugger->driver()->executeCmd(DCignore, bp->id, ignoreCount);
315 changed = true;
317 if (changed) {
318 // get the changes
319 m_debugger->driver()->queueCmd(DCinfobreak, DebuggerDriver::QMoverride);
324 BreakpointItem* BreakpointTable::itemByBreakId(int id)
326 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
327 BreakpointItem* bp = static_cast<BreakpointItem*>(it);
328 if (bp->id == id) {
329 return bp;
332 return 0;
336 void BreakpointTable::initListAndIcons()
338 m_list.addColumn(i18n("Location"), 220);
339 m_list.addColumn(i18n("Address"), 65);
340 m_list.addColumn(i18n("Hits"), 30);
341 m_list.addColumn(i18n("Ignore"), 30);
342 m_list.addColumn(i18n("Condition"), 200);
344 m_list.setMinimumSize(200, 100);
345 setFocusPolicy(QWidget::StrongFocus);
347 m_list.setSorting(-1);
349 // add pixmaps
350 #if QT_VERSION < 200
351 KIconLoader* loader = kapp->getIconLoader();
352 QPixmap brkena = loader->loadIcon("brkena.xpm");
353 QPixmap brkdis = loader->loadIcon("brkdis.xpm");
354 QPixmap brktmp = loader->loadIcon("brktmp.xpm");
355 QPixmap brkcond = loader->loadIcon("brkcond.xpm");
356 #else
357 QPixmap brkena = BarIcon("brkena.xpm");
358 QPixmap brkdis = BarIcon("brkdis.xpm");
359 QPixmap brktmp = BarIcon("brktmp.xpm");
360 QPixmap brkcond = BarIcon("brkcond.xpm");
361 #endif
363 * There are 8 different pixmaps: The basic enabled or disabled
364 * breakpoint, plus an optional overlaid brktmp icon plus an optional
365 * overlaid brkcond icon.
367 m_icons.setSize(8);
368 QPixmap canvas(16,16);
370 for (int i = 0; i < 8; i++) {
372 QPainter p(&canvas);
373 // clear canvas
374 p.fillRect(0,0, canvas.width(),canvas.height(), cyan);
375 // basic icon
376 if (i & 1) {
377 p.drawPixmap(1,1, brkena);
378 } else {
379 p.drawPixmap(1,1, brkdis);
381 // temporary overlay
382 if (i & 2) {
383 p.drawPixmap(1,1, brktmp);
385 // conditional overlay
386 if (i & 4) {
387 p.drawPixmap(1,1, brkcond);
390 canvas.setMask(canvas.createHeuristicMask());
391 m_icons[i] = canvas;
395 void BreakpointItem::display()
397 BreakpointTable* lb = static_cast<BreakpointTable*>(listView()->parent());
399 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
400 int code = enabled ? 1 : 0;
401 if (temporary)
402 code += 2;
403 if (!condition.isEmpty() || ignoreCount > 0)
404 code += 4;
405 setPixmap(0, lb->m_icons[code]);
407 // more breakpoint info
408 setText(0, location);
409 int c = 0;
410 setText(++c, address.asString());
411 QString tmp;
412 if (hitCount == 0) {
413 setText(++c, QString());
414 } else {
415 tmp.setNum(hitCount);
416 setText(++c, tmp);
418 if (ignoreCount == 0) {
419 setText(++c, QString());
420 } else {
421 tmp.setNum(ignoreCount);
422 setText(++c, tmp);
424 if (condition.isEmpty()) {
425 setText(++c, QString());
426 } else {
427 setText(++c, condition);
432 ConditionalDlg::ConditionalDlg(QWidget* parent) :
433 QDialog(parent, "conditional", true),
434 m_conditionLabel(this, "condLabel"),
435 m_condition(this, "condition"),
436 m_ignoreLabel(this, "ignoreLabel"),
437 m_ignoreCount(this, "ignoreCount"),
438 m_buttonOK(this, "ok"),
439 m_buttonCancel(this, "cancel"),
440 m_layout(this, 10),
441 m_inputs(2, 2, 10),
442 m_buttons(4)
444 QString title = kapp->getCaption();
445 title += i18n(": Conditional breakpoint");
446 setCaption(title);
448 m_conditionLabel.setText(i18n("&Condition:"));
449 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
450 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
451 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
453 m_condition.setMinimumSize(150, 24);
454 m_condition.setMaxLength(10000);
455 m_condition.setFrame(true);
456 m_ignoreCount.setMinimumSize(150, 24);
457 m_ignoreCount.setMaxLength(10000);
458 m_ignoreCount.setFrame(true);
460 m_conditionLabel.setBuddy(&m_condition);
461 m_ignoreLabel.setBuddy(&m_ignoreCount);
463 m_buttonOK.setMinimumSize(100, 30);
464 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
465 m_buttonOK.setText(i18n("OK"));
466 m_buttonOK.setDefault(true);
468 m_buttonCancel.setMinimumSize(100, 30);
469 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
470 m_buttonCancel.setText(i18n("Cancel"));
472 m_layout.addLayout(&m_inputs);
473 m_inputs.addWidget(&m_conditionLabel, 0, 0);
474 m_inputs.addWidget(&m_condition, 0, 1);
475 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
476 m_inputs.addWidget(&m_ignoreCount, 1, 1);
477 m_inputs.setColStretch(1, 10);
478 m_layout.addLayout(&m_buttons);
479 m_layout.addStretch(10);
480 m_buttons.addStretch(10);
481 m_buttons.addWidget(&m_buttonOK);
482 m_buttons.addSpacing(40);
483 m_buttons.addWidget(&m_buttonCancel);
484 m_buttons.addStretch(10);
486 m_layout.activate();
488 m_condition.setFocus();
489 resize(400, 100);
492 ConditionalDlg::~ConditionalDlg()
496 uint ConditionalDlg::ignoreCount()
498 bool ok;
499 QString input = m_ignoreCount.text();
500 uint result = input.toUInt(&ok);
501 return ok ? result : 0;
504 void ConditionalDlg::setIgnoreCount(uint count)
506 QString text;
507 // set empty if ignore count is zero
508 if (count > 0) {
509 text.setNum(count);
511 m_ignoreCount.setText(text);