Upgraded the build system for KDE2.
[kdbg.git] / kdbg / brkpt.cpp
blobe1fa5c34d942cbfa35065b49be03693a781ad0a4
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_btAddBP(this, "addbp"),
43 m_btAddWP(this, "addwp"),
44 m_btRemove(this, "remove"),
45 m_btEnaDis(this, "enadis"),
46 m_btViewCode(this, "view"),
47 m_btConditional(this, "conditional"),
48 m_layout(this, 8),
49 m_listandedit(8),
50 m_buttons(8)
52 m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
53 connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
55 initListAndIcons();
56 connect(&m_list, SIGNAL(currentChanged(QListViewItem*)), SLOT(updateUI()));
57 // double click on item is same as View code
58 connect(&m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(viewBP()));
60 // need mouse button events
61 m_list.viewport()->installEventFilter(this);
63 m_btAddBP.setText(i18n("Add &Breakpoint"));
64 m_btAddBP.setMinimumSize(m_btAddBP.sizeHint());
65 connect(&m_btAddBP, SIGNAL(clicked()), this, SLOT(addBP()));
67 m_btAddWP.setText(i18n("Add &Watchpoint"));
68 m_btAddWP.setMinimumSize(m_btAddWP.sizeHint());
69 connect(&m_btAddWP, SIGNAL(clicked()), this, SLOT(addWP()));
71 m_btRemove.setText(i18n("&Remove"));
72 m_btRemove.setMinimumSize(m_btRemove.sizeHint());
73 connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP()));
75 // the Enable/Disable button changes its label
76 m_btEnaDis.setText(i18n("&Disable"));
77 // make a dummy button to get the size of the alternate label
79 QSize size = m_btEnaDis.sizeHint();
80 QPushButton dummy(this);
81 dummy.setText(i18n("&Enable"));
82 QSize sizeAlt = dummy.sizeHint();
83 if (sizeAlt.width() > size.width())
84 size.setWidth(sizeAlt.width());
85 if (sizeAlt.height() > size.height())
86 size.setHeight(sizeAlt.height());
87 m_btEnaDis.setMinimumSize(size);
89 connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP()));
91 m_btViewCode.setText(i18n("&View Code"));
92 m_btViewCode.setMinimumSize(m_btViewCode.sizeHint());
93 connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP()));
95 m_btConditional.setText(i18n("&Conditional..."));
96 m_btConditional.setMinimumSize(m_btConditional.sizeHint());
97 connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP()));
99 m_layout.addLayout(&m_listandedit, 10);
100 m_layout.addLayout(&m_buttons);
101 m_listandedit.addWidget(&m_bpEdit);
102 m_listandedit.addWidget(&m_list, 10);
103 m_buttons.addWidget(&m_btAddBP);
104 m_buttons.addWidget(&m_btAddWP);
105 m_buttons.addWidget(&m_btRemove);
106 m_buttons.addWidget(&m_btEnaDis);
107 m_buttons.addWidget(&m_btViewCode);
108 m_buttons.addWidget(&m_btConditional);
109 m_buttons.addStretch(10);
111 m_layout.activate();
113 resize(350, 300);
115 m_bpEdit.setFocus();
118 BreakpointTable::~BreakpointTable()
122 void BreakpointTable::updateBreakList()
124 QList<BreakpointItem> deletedItems;
126 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
127 deletedItems.append(static_cast<BreakpointItem*>(it));
130 // get the new list
131 for (int i = m_debugger->numBreakpoints()-1; i >= 0; i--) {
132 const Breakpoint* bp = m_debugger->breakpoint(i);
133 // look up this item
134 for (BreakpointItem* oldbp = deletedItems.first(); oldbp != 0;
135 oldbp = deletedItems.next())
137 if (oldbp->id == bp->id) {
138 oldbp->updateFrom(*bp);
139 deletedItems.take(); /* don't delete */
140 goto nextItem;
143 // not in the list; add it
144 new BreakpointItem(&m_list, *bp);
145 nextItem:;
148 // delete all untouched breakpoints
149 deletedItems.setAutoDelete(true);
152 BreakpointItem::BreakpointItem(QListView* list, const Breakpoint& bp) :
153 QListViewItem(list),
154 Breakpoint(bp)
156 display();
159 void BreakpointItem::updateFrom(const Breakpoint& bp)
161 Breakpoint::operator=(bp); /* assign new values */
162 display();
165 void BreakpointTable::addBP()
167 // set a breakpoint at the specified text
168 QString bpText = m_bpEdit.text();
169 bpText = bpText.stripWhiteSpace();
170 if (m_debugger->isReady()) {
171 m_debugger->driver()->executeCmd(DCbreaktext, bpText);
172 // clear text if successfully set
173 m_bpEdit.setText("");
177 void BreakpointTable::addWP()
179 // set a watchpoint for the specified expression
180 QString wpExpr = m_bpEdit.text();
181 wpExpr = wpExpr.stripWhiteSpace();
182 if (m_debugger->isReady()) {
183 m_debugger->driver()->executeCmd(DCwatchpoint, wpExpr);
187 void BreakpointTable::removeBP()
189 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
190 if (bp == 0)
191 return;
193 m_debugger->driver()->executeCmd(DCdelete, bp->id);
196 void BreakpointTable::enadisBP()
198 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
199 if (bp == 0)
200 return;
202 DbgCommand cmd = bp->enabled ? DCdisable : DCenable;
203 m_debugger->driver()->executeCmd(cmd, bp->id);
206 void BreakpointTable::viewBP()
208 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
209 if (bp == 0)
210 return;
212 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
215 void BreakpointTable::updateUI()
217 bool enableChkpt = m_debugger->canChangeBreakpoints();
218 m_btAddBP.setEnabled(enableChkpt);
219 m_btAddWP.setEnabled(enableChkpt);
221 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
222 m_btViewCode.setEnabled(bp != 0);
224 if (bp == 0) {
225 enableChkpt = false;
226 } else {
227 if (bp->enabled) {
228 m_btEnaDis.setText(i18n("&Disable"));
229 } else {
230 m_btEnaDis.setText(i18n("&Enable"));
233 m_btRemove.setEnabled(enableChkpt);
234 m_btEnaDis.setEnabled(enableChkpt);
235 m_btConditional.setEnabled(enableChkpt);
238 #if QT_VERSION < 200
239 # define MOUSEPRESS Event_MouseButtonPress
240 #else
241 # define MOUSEPRESS QEvent::MouseButtonPress
242 #endif
244 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
246 if (ev->type() == MOUSEPRESS)
248 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
249 if (mev->button() == MidButton) {
250 // enable or disable the clicked-on item
251 BreakpointItem* bp =
252 static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
253 if (bp != 0 && m_debugger->canChangeBreakpoints())
255 DbgCommand cmd = bp->enabled ? DCdisable : DCenable;
256 m_debugger->driver()->executeCmd(cmd, bp->id);
258 return true;
261 return QWidget::eventFilter(ob, ev);
264 class ConditionalDlg : public QDialog
266 public:
267 ConditionalDlg(QWidget* parent);
268 ~ConditionalDlg();
270 void setCondition(const char* text) { m_condition.setText(text); }
271 const char* condition() { return m_condition.text(); }
272 void setIgnoreCount(uint count);
273 uint ignoreCount();
275 protected:
276 QLabel m_conditionLabel;
277 QLineEdit m_condition;
278 QLabel m_ignoreLabel;
279 QLineEdit m_ignoreCount;
280 QPushButton m_buttonOK;
281 QPushButton m_buttonCancel;
282 QVBoxLayout m_layout;
283 QGridLayout m_inputs;
284 QHBoxLayout m_buttons;
287 void BreakpointTable::conditionalBP()
289 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
290 if (bp == 0)
291 return;
294 * Important: we must not keep a pointer to the Breakpoint around,
295 * since it may vanish while the modal dialog is open through other
296 * user interactions (like clicking at the breakpoint in the source
297 * window)!
299 int id = bp->id;
301 ConditionalDlg dlg(this);
302 dlg.setCondition(bp->condition);
303 dlg.setIgnoreCount(bp->ignoreCount);
305 if (dlg.exec() != QDialog::Accepted)
306 return;
308 QString conditionInput = dlg.condition();
309 int ignoreCount = dlg.ignoreCount();
310 updateBreakpointCondition(id, conditionInput, ignoreCount);
313 void BreakpointTable::updateBreakpointCondition(int id,
314 const QString& condition,
315 int ignoreCount)
317 BreakpointItem* bp = itemByBreakId(id);
318 if (bp == 0)
319 return; /* breakpoint no longer exists */
321 bool changed = false;
323 if (bp->condition != condition) {
324 // change condition
325 m_debugger->driver()->executeCmd(DCcondition, condition, bp->id);
326 bp->condition = condition;
327 changed = true;
329 if (bp->ignoreCount != ignoreCount) {
330 // change ignore count
331 m_debugger->driver()->executeCmd(DCignore, bp->id, ignoreCount);
332 changed = true;
334 if (changed) {
335 // get the changes
336 m_debugger->driver()->queueCmd(DCinfobreak, DebuggerDriver::QMoverride);
341 BreakpointItem* BreakpointTable::itemByBreakId(int id)
343 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
344 BreakpointItem* bp = static_cast<BreakpointItem*>(it);
345 if (bp->id == id) {
346 return bp;
349 return 0;
353 void BreakpointTable::initListAndIcons()
355 m_list.addColumn(i18n("Location"), 220);
356 m_list.addColumn(i18n("Address"), 65);
357 m_list.addColumn(i18n("Hits"), 30);
358 m_list.addColumn(i18n("Ignore"), 30);
359 m_list.addColumn(i18n("Condition"), 200);
361 m_list.setMinimumSize(200, 100);
363 m_list.setSorting(-1);
365 // add pixmaps
366 #if QT_VERSION < 200
367 KIconLoader* loader = kapp->getIconLoader();
368 QPixmap brkena = loader->loadIcon("brkena.xpm");
369 QPixmap brkdis = loader->loadIcon("brkdis.xpm");
370 QPixmap watchena = loader->loadIcon("watchena.xpm");
371 QPixmap watchdis = loader->loadIcon("watchdis.xpm");
372 QPixmap brktmp = loader->loadIcon("brktmp.xpm");
373 QPixmap brkcond = loader->loadIcon("brkcond.xpm");
374 #else
375 QPixmap brkena = BarIcon("brkena.xpm");
376 QPixmap brkdis = BarIcon("brkdis.xpm");
377 QPixmap watchena = BarIcon("watchena.xpm");
378 QPixmap watchdis = BarIcon("watchdis.xpm");
379 QPixmap brktmp = BarIcon("brktmp.xpm");
380 QPixmap brkcond = BarIcon("brkcond.xpm");
381 #endif
383 * There are 16 different pixmaps: The basic enabled or disabled
384 * breakpoint, plus an optional overlaid brktmp icon plus an optional
385 * overlaid brkcond icon. Then the same sequence for watchpoints.
387 m_icons.setSize(16);
388 QPixmap canvas(16,16);
390 for (int i = 0; i < 16; i++) {
392 QPainter p(&canvas);
393 // clear canvas
394 p.fillRect(0,0, canvas.width(),canvas.height(), cyan);
395 // basic icon
396 if (i & 1) {
397 p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
398 } else {
399 p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
401 // temporary overlay
402 if (i & 2) {
403 p.drawPixmap(1,1, brktmp);
405 // conditional overlay
406 if (i & 4) {
407 p.drawPixmap(1,1, brkcond);
410 canvas.setMask(canvas.createHeuristicMask());
411 m_icons[i] = canvas;
415 void BreakpointItem::display()
417 BreakpointTable* lb = static_cast<BreakpointTable*>(listView()->parent());
419 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
420 int code = enabled ? 1 : 0;
421 if (temporary)
422 code += 2;
423 if (!condition.isEmpty() || ignoreCount > 0)
424 code += 4;
425 if (type == watchpoint)
426 code += 8;
427 setPixmap(0, lb->m_icons[code]);
429 // more breakpoint info
430 setText(0, location);
431 int c = 0;
432 setText(++c, address.asString());
433 QString tmp;
434 if (hitCount == 0) {
435 setText(++c, QString());
436 } else {
437 tmp.setNum(hitCount);
438 setText(++c, tmp);
440 if (ignoreCount == 0) {
441 setText(++c, QString());
442 } else {
443 tmp.setNum(ignoreCount);
444 setText(++c, tmp);
446 if (condition.isEmpty()) {
447 setText(++c, QString());
448 } else {
449 setText(++c, condition);
454 ConditionalDlg::ConditionalDlg(QWidget* parent) :
455 QDialog(parent, "conditional", true),
456 m_conditionLabel(this, "condLabel"),
457 m_condition(this, "condition"),
458 m_ignoreLabel(this, "ignoreLabel"),
459 m_ignoreCount(this, "ignoreCount"),
460 m_buttonOK(this, "ok"),
461 m_buttonCancel(this, "cancel"),
462 m_layout(this, 10),
463 m_inputs(2, 2, 10),
464 m_buttons(4)
466 QString title = kapp->getCaption();
467 title += i18n(": Conditional breakpoint");
468 setCaption(title);
470 m_conditionLabel.setText(i18n("&Condition:"));
471 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
472 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
473 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
475 m_condition.setMinimumSize(150, 24);
476 m_condition.setMaxLength(10000);
477 m_condition.setFrame(true);
478 m_ignoreCount.setMinimumSize(150, 24);
479 m_ignoreCount.setMaxLength(10000);
480 m_ignoreCount.setFrame(true);
482 m_conditionLabel.setBuddy(&m_condition);
483 m_ignoreLabel.setBuddy(&m_ignoreCount);
485 m_buttonOK.setMinimumSize(100, 30);
486 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
487 m_buttonOK.setText(i18n("OK"));
488 m_buttonOK.setDefault(true);
490 m_buttonCancel.setMinimumSize(100, 30);
491 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
492 m_buttonCancel.setText(i18n("Cancel"));
494 m_layout.addLayout(&m_inputs);
495 m_inputs.addWidget(&m_conditionLabel, 0, 0);
496 m_inputs.addWidget(&m_condition, 0, 1);
497 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
498 m_inputs.addWidget(&m_ignoreCount, 1, 1);
499 m_inputs.setColStretch(1, 10);
500 m_layout.addLayout(&m_buttons);
501 m_layout.addStretch(10);
502 m_buttons.addStretch(10);
503 m_buttons.addWidget(&m_buttonOK);
504 m_buttons.addSpacing(40);
505 m_buttons.addWidget(&m_buttonCancel);
506 m_buttons.addStretch(10);
508 m_layout.activate();
510 m_condition.setFocus();
511 resize(400, 100);
514 ConditionalDlg::~ConditionalDlg()
518 uint ConditionalDlg::ignoreCount()
520 bool ok;
521 QString input = m_ignoreCount.text();
522 uint result = input.toUInt(&ok);
523 return ok ? result : 0;
526 void ConditionalDlg::setIgnoreCount(uint count)
528 QString text;
529 // set empty if ignore count is zero
530 if (count > 0) {
531 text.setNum(count);
533 m_ignoreCount.setText(text);