Updates to compile for Qt3 and KDE3.
[kdbg.git] / kdbg / brkpt.cpp
blob595e00b2059e7ac489f22fddf4c17a479740553d
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 */
34 bool enabled() const { return Breakpoint::enabled; }
38 BreakpointTable::BreakpointTable(QWidget* parent, const char* name) :
39 QWidget(parent, name),
40 m_debugger(0),
41 m_bpEdit(this, "bpedit"),
42 m_list(this, "bptable"),
43 m_btAddBP(this, "addbp"),
44 m_btAddWP(this, "addwp"),
45 m_btRemove(this, "remove"),
46 m_btEnaDis(this, "enadis"),
47 m_btViewCode(this, "view"),
48 m_btConditional(this, "conditional"),
49 m_layout(this, 8),
50 m_listandedit(8),
51 m_buttons(8)
53 m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
54 connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
56 initListAndIcons();
57 connect(&m_list, SIGNAL(currentChanged(QListViewItem*)), SLOT(updateUI()));
58 // double click on item is same as View code
59 connect(&m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(viewBP()));
61 // need mouse button events
62 m_list.viewport()->installEventFilter(this);
64 m_btAddBP.setText(i18n("Add &Breakpoint"));
65 m_btAddBP.setMinimumSize(m_btAddBP.sizeHint());
66 connect(&m_btAddBP, SIGNAL(clicked()), this, SLOT(addBP()));
68 m_btAddWP.setText(i18n("Add &Watchpoint"));
69 m_btAddWP.setMinimumSize(m_btAddWP.sizeHint());
70 connect(&m_btAddWP, SIGNAL(clicked()), this, SLOT(addWP()));
72 m_btRemove.setText(i18n("&Remove"));
73 m_btRemove.setMinimumSize(m_btRemove.sizeHint());
74 connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP()));
76 // the Enable/Disable button changes its label
77 m_btEnaDis.setText(i18n("&Disable"));
78 // make a dummy button to get the size of the alternate label
80 QSize size = m_btEnaDis.sizeHint();
81 QPushButton dummy(this);
82 dummy.setText(i18n("&Enable"));
83 QSize sizeAlt = dummy.sizeHint();
84 if (sizeAlt.width() > size.width())
85 size.setWidth(sizeAlt.width());
86 if (sizeAlt.height() > size.height())
87 size.setHeight(sizeAlt.height());
88 m_btEnaDis.setMinimumSize(size);
90 connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP()));
92 m_btViewCode.setText(i18n("&View Code"));
93 m_btViewCode.setMinimumSize(m_btViewCode.sizeHint());
94 connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP()));
96 m_btConditional.setText(i18n("&Conditional..."));
97 m_btConditional.setMinimumSize(m_btConditional.sizeHint());
98 connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP()));
100 m_layout.addLayout(&m_listandedit, 10);
101 m_layout.addLayout(&m_buttons);
102 m_listandedit.addWidget(&m_bpEdit);
103 m_listandedit.addWidget(&m_list, 10);
104 m_buttons.addWidget(&m_btAddBP);
105 m_buttons.addWidget(&m_btAddWP);
106 m_buttons.addWidget(&m_btRemove);
107 m_buttons.addWidget(&m_btEnaDis);
108 m_buttons.addWidget(&m_btViewCode);
109 m_buttons.addWidget(&m_btConditional);
110 m_buttons.addStretch(10);
112 m_layout.activate();
114 resize(350, 300);
116 m_bpEdit.setFocus();
119 BreakpointTable::~BreakpointTable()
123 void BreakpointTable::updateBreakList()
125 QList<BreakpointItem> deletedItems;
127 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
128 deletedItems.append(static_cast<BreakpointItem*>(it));
131 // get the new list
132 for (int i = m_debugger->numBreakpoints()-1; i >= 0; i--) {
133 const Breakpoint* bp = m_debugger->breakpoint(i);
134 // look up this item
135 for (BreakpointItem* oldbp = deletedItems.first(); oldbp != 0;
136 oldbp = deletedItems.next())
138 if (oldbp->id == bp->id) {
139 oldbp->updateFrom(*bp);
140 deletedItems.take(); /* don't delete */
141 goto nextItem;
144 // not in the list; add it
145 new BreakpointItem(&m_list, *bp);
146 nextItem:;
149 // delete all untouched breakpoints
150 deletedItems.setAutoDelete(true);
153 BreakpointItem::BreakpointItem(QListView* list, const Breakpoint& bp) :
154 QListViewItem(list),
155 Breakpoint(bp)
157 display();
160 void BreakpointItem::updateFrom(const Breakpoint& bp)
162 Breakpoint::operator=(bp); /* assign new values */
163 display();
166 void BreakpointTable::addBP()
168 // set a breakpoint at the specified text
169 QString bpText = m_bpEdit.text();
170 bpText = bpText.stripWhiteSpace();
171 if (m_debugger->isReady()) {
172 m_debugger->driver()->executeCmd(DCbreaktext, bpText);
173 // clear text if successfully set
174 m_bpEdit.setText("");
178 void BreakpointTable::addWP()
180 // set a watchpoint for the specified expression
181 QString wpExpr = m_bpEdit.text();
182 wpExpr = wpExpr.stripWhiteSpace();
183 if (m_debugger->isReady()) {
184 m_debugger->driver()->executeCmd(DCwatchpoint, wpExpr);
188 void BreakpointTable::removeBP()
190 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
191 if (bp == 0)
192 return;
194 m_debugger->driver()->executeCmd(DCdelete, bp->id);
197 void BreakpointTable::enadisBP()
199 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
200 if (bp == 0)
201 return;
203 DbgCommand cmd = bp->enabled() ? DCdisable : DCenable;
204 m_debugger->driver()->executeCmd(cmd, bp->id);
207 void BreakpointTable::viewBP()
209 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
210 if (bp == 0)
211 return;
213 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
216 void BreakpointTable::updateUI()
218 bool enableChkpt = m_debugger->canChangeBreakpoints();
219 m_btAddBP.setEnabled(enableChkpt);
220 m_btAddWP.setEnabled(enableChkpt);
222 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
223 m_btViewCode.setEnabled(bp != 0);
225 if (bp == 0) {
226 enableChkpt = false;
227 } else {
228 if (bp->enabled()) {
229 m_btEnaDis.setText(i18n("&Disable"));
230 } else {
231 m_btEnaDis.setText(i18n("&Enable"));
234 m_btRemove.setEnabled(enableChkpt);
235 m_btEnaDis.setEnabled(enableChkpt);
236 m_btConditional.setEnabled(enableChkpt);
239 #if QT_VERSION < 200
240 # define MOUSEPRESS Event_MouseButtonPress
241 #else
242 # define MOUSEPRESS QEvent::MouseButtonPress
243 #endif
245 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
247 if (ev->type() == MOUSEPRESS)
249 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
250 if (mev->button() == MidButton) {
251 // enable or disable the clicked-on item
252 BreakpointItem* bp =
253 static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
254 if (bp != 0 && m_debugger->canChangeBreakpoints())
256 DbgCommand cmd = bp->enabled() ? DCdisable : DCenable;
257 m_debugger->driver()->executeCmd(cmd, bp->id);
259 return true;
262 return QWidget::eventFilter(ob, ev);
265 class ConditionalDlg : public QDialog
267 public:
268 ConditionalDlg(QWidget* parent);
269 ~ConditionalDlg();
271 void setCondition(const char* text) { m_condition.setText(text); }
272 const char* condition() { return m_condition.text(); }
273 void setIgnoreCount(uint count);
274 uint ignoreCount();
276 protected:
277 QLabel m_conditionLabel;
278 QLineEdit m_condition;
279 QLabel m_ignoreLabel;
280 QLineEdit m_ignoreCount;
281 QPushButton m_buttonOK;
282 QPushButton m_buttonCancel;
283 QVBoxLayout m_layout;
284 QGridLayout m_inputs;
285 QHBoxLayout m_buttons;
288 void BreakpointTable::conditionalBP()
290 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
291 if (bp == 0)
292 return;
295 * Important: we must not keep a pointer to the Breakpoint around,
296 * since it may vanish while the modal dialog is open through other
297 * user interactions (like clicking at the breakpoint in the source
298 * window)!
300 int id = bp->id;
302 ConditionalDlg dlg(this);
303 dlg.setCondition(bp->condition);
304 dlg.setIgnoreCount(bp->ignoreCount);
306 if (dlg.exec() != QDialog::Accepted)
307 return;
309 QString conditionInput = dlg.condition();
310 int ignoreCount = dlg.ignoreCount();
311 updateBreakpointCondition(id, conditionInput, ignoreCount);
314 void BreakpointTable::updateBreakpointCondition(int id,
315 const QString& condition,
316 int ignoreCount)
318 BreakpointItem* bp = itemByBreakId(id);
319 if (bp == 0)
320 return; /* breakpoint no longer exists */
322 bool changed = false;
324 if (bp->condition != condition) {
325 // change condition
326 m_debugger->driver()->executeCmd(DCcondition, condition, bp->id);
327 bp->condition = condition;
328 changed = true;
330 if (bp->ignoreCount != ignoreCount) {
331 // change ignore count
332 m_debugger->driver()->executeCmd(DCignore, bp->id, ignoreCount);
333 changed = true;
335 if (changed) {
336 // get the changes
337 m_debugger->driver()->queueCmd(DCinfobreak, DebuggerDriver::QMoverride);
342 BreakpointItem* BreakpointTable::itemByBreakId(int id)
344 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
345 BreakpointItem* bp = static_cast<BreakpointItem*>(it);
346 if (bp->id == id) {
347 return bp;
350 return 0;
354 void BreakpointTable::initListAndIcons()
356 m_list.addColumn(i18n("Location"), 220);
357 m_list.addColumn(i18n("Address"), 65);
358 m_list.addColumn(i18n("Hits"), 30);
359 m_list.addColumn(i18n("Ignore"), 30);
360 m_list.addColumn(i18n("Condition"), 200);
362 m_list.setMinimumSize(200, 100);
364 m_list.setSorting(-1);
366 // add pixmaps
367 #if QT_VERSION < 200
368 KIconLoader* loader = kapp->getIconLoader();
369 QPixmap brkena = loader->loadIcon("brkena.xpm");
370 QPixmap brkdis = loader->loadIcon("brkdis.xpm");
371 QPixmap watchena = loader->loadIcon("watchena.xpm");
372 QPixmap watchdis = loader->loadIcon("watchdis.xpm");
373 QPixmap brktmp = loader->loadIcon("brktmp.xpm");
374 QPixmap brkcond = loader->loadIcon("brkcond.xpm");
375 #else
376 QPixmap brkena = BarIcon("brkena.xpm");
377 QPixmap brkdis = BarIcon("brkdis.xpm");
378 QPixmap watchena = BarIcon("watchena.xpm");
379 QPixmap watchdis = BarIcon("watchdis.xpm");
380 QPixmap brktmp = BarIcon("brktmp.xpm");
381 QPixmap brkcond = BarIcon("brkcond.xpm");
382 #endif
384 * There are 16 different pixmaps: The basic enabled or disabled
385 * breakpoint, plus an optional overlaid brktmp icon plus an optional
386 * overlaid brkcond icon. Then the same sequence for watchpoints.
388 m_icons.setSize(16);
389 QPixmap canvas(16,16);
391 for (int i = 0; i < 16; i++) {
393 QPainter p(&canvas);
394 // clear canvas
395 p.fillRect(0,0, canvas.width(),canvas.height(), cyan);
396 // basic icon
397 if (i & 1) {
398 p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
399 } else {
400 p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
402 // temporary overlay
403 if (i & 2) {
404 p.drawPixmap(1,1, brktmp);
406 // conditional overlay
407 if (i & 4) {
408 p.drawPixmap(1,1, brkcond);
411 canvas.setMask(canvas.createHeuristicMask());
412 m_icons[i] = canvas;
416 void BreakpointItem::display()
418 BreakpointTable* lb = static_cast<BreakpointTable*>(listView()->parent());
420 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
421 int code = enabled() ? 1 : 0;
422 if (temporary)
423 code += 2;
424 if (!condition.isEmpty() || ignoreCount > 0)
425 code += 4;
426 if (type == watchpoint)
427 code += 8;
428 setPixmap(0, lb->m_icons[code]);
430 // more breakpoint info
431 setText(0, location);
432 int c = 0;
433 setText(++c, address.asString());
434 QString tmp;
435 if (hitCount == 0) {
436 setText(++c, QString());
437 } else {
438 tmp.setNum(hitCount);
439 setText(++c, tmp);
441 if (ignoreCount == 0) {
442 setText(++c, QString());
443 } else {
444 tmp.setNum(ignoreCount);
445 setText(++c, tmp);
447 if (condition.isEmpty()) {
448 setText(++c, QString());
449 } else {
450 setText(++c, condition);
455 ConditionalDlg::ConditionalDlg(QWidget* parent) :
456 QDialog(parent, "conditional", true),
457 m_conditionLabel(this, "condLabel"),
458 m_condition(this, "condition"),
459 m_ignoreLabel(this, "ignoreLabel"),
460 m_ignoreCount(this, "ignoreCount"),
461 m_buttonOK(this, "ok"),
462 m_buttonCancel(this, "cancel"),
463 m_layout(this, 10),
464 m_inputs(2, 2, 10),
465 m_buttons(4)
467 QString title = kapp->getCaption();
468 title += i18n(": Conditional breakpoint");
469 setCaption(title);
471 m_conditionLabel.setText(i18n("&Condition:"));
472 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
473 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
474 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
476 m_condition.setMinimumSize(150, 24);
477 m_condition.setMaxLength(10000);
478 m_condition.setFrame(true);
479 m_ignoreCount.setMinimumSize(150, 24);
480 m_ignoreCount.setMaxLength(10000);
481 m_ignoreCount.setFrame(true);
483 m_conditionLabel.setBuddy(&m_condition);
484 m_ignoreLabel.setBuddy(&m_ignoreCount);
486 m_buttonOK.setMinimumSize(100, 30);
487 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
488 m_buttonOK.setText(i18n("OK"));
489 m_buttonOK.setDefault(true);
491 m_buttonCancel.setMinimumSize(100, 30);
492 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
493 m_buttonCancel.setText(i18n("Cancel"));
495 m_layout.addLayout(&m_inputs);
496 m_inputs.addWidget(&m_conditionLabel, 0, 0);
497 m_inputs.addWidget(&m_condition, 0, 1);
498 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
499 m_inputs.addWidget(&m_ignoreCount, 1, 1);
500 m_inputs.setColStretch(1, 10);
501 m_layout.addLayout(&m_buttons);
502 m_layout.addStretch(10);
503 m_buttons.addStretch(10);
504 m_buttons.addWidget(&m_buttonOK);
505 m_buttons.addSpacing(40);
506 m_buttons.addWidget(&m_buttonCancel);
507 m_buttons.addStretch(10);
509 m_layout.activate();
511 m_condition.setFocus();
512 resize(400, 100);
515 ConditionalDlg::~ConditionalDlg()
519 uint ConditionalDlg::ignoreCount()
521 bool ok;
522 QString input = m_ignoreCount.text();
523 uint result = input.toUInt(&ok);
524 return ok ? result : 0;
527 void ConditionalDlg::setIgnoreCount(uint count)
529 QString text;
530 // set empty if ignore count is zero
531 if (count > 0) {
532 text.setNum(count);
534 m_ignoreCount.setText(text);