Cleanup config.h usage.
[kdbg.git] / kdbg / brkpt.cpp
blobce5ef6a8c90a5f591549bb17e088ac9a109ce863
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include <kapplication.h>
8 #include <klocale.h> /* i18n */
9 #include <kiconloader.h>
10 #include <ksimpleconfig.h>
11 #include <qdialog.h>
12 #include <qkeycode.h>
13 #include <qpainter.h>
14 #include <qlabel.h>
15 #include <qbitmap.h>
16 #include "debugger.h"
17 #include "brkpt.h"
18 #include "dbgdriver.h"
19 #include <ctype.h>
20 #include <list>
21 #include "mydebug.h"
24 class BreakpointItem : public QListViewItem, public Breakpoint
26 public:
27 BreakpointItem(QListView* list, const Breakpoint& bp);
28 void updateFrom(const Breakpoint& bp);
29 void display(); /* sets icon and visible texts */
30 bool enabled() const { return Breakpoint::enabled; }
34 BreakpointTable::BreakpointTable(QWidget* parent, const char* name) :
35 QWidget(parent, name),
36 m_debugger(0),
37 m_bpEdit(this, "bpedit"),
38 m_list(this, "bptable"),
39 m_btAddBP(this, "addbp"),
40 m_btAddWP(this, "addwp"),
41 m_btRemove(this, "remove"),
42 m_btEnaDis(this, "enadis"),
43 m_btViewCode(this, "view"),
44 m_btConditional(this, "conditional"),
45 m_layout(this, 8),
46 m_listandedit(8),
47 m_buttons(8)
49 m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
50 connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
52 initListAndIcons();
53 connect(&m_list, SIGNAL(currentChanged(QListViewItem*)), SLOT(updateUI()));
54 // double click on item is same as View code
55 connect(&m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(viewBP()));
57 // need mouse button events
58 m_list.viewport()->installEventFilter(this);
60 m_btAddBP.setText(i18n("Add &Breakpoint"));
61 m_btAddBP.setMinimumSize(m_btAddBP.sizeHint());
62 connect(&m_btAddBP, SIGNAL(clicked()), this, SLOT(addBP()));
64 m_btAddWP.setText(i18n("Add &Watchpoint"));
65 m_btAddWP.setMinimumSize(m_btAddWP.sizeHint());
66 connect(&m_btAddWP, SIGNAL(clicked()), this, SLOT(addWP()));
68 m_btRemove.setText(i18n("&Remove"));
69 m_btRemove.setMinimumSize(m_btRemove.sizeHint());
70 connect(&m_btRemove, SIGNAL(clicked()), this, SLOT(removeBP()));
72 // the Enable/Disable button changes its label
73 m_btEnaDis.setText(i18n("&Disable"));
74 // make a dummy button to get the size of the alternate label
76 QSize size = m_btEnaDis.sizeHint();
77 QPushButton dummy(this);
78 dummy.setText(i18n("&Enable"));
79 QSize sizeAlt = dummy.sizeHint();
80 if (sizeAlt.width() > size.width())
81 size.setWidth(sizeAlt.width());
82 if (sizeAlt.height() > size.height())
83 size.setHeight(sizeAlt.height());
84 m_btEnaDis.setMinimumSize(size);
86 connect(&m_btEnaDis, SIGNAL(clicked()), this, SLOT(enadisBP()));
88 m_btViewCode.setText(i18n("&View Code"));
89 m_btViewCode.setMinimumSize(m_btViewCode.sizeHint());
90 connect(&m_btViewCode, SIGNAL(clicked()), this, SLOT(viewBP()));
92 m_btConditional.setText(i18n("&Conditional..."));
93 m_btConditional.setMinimumSize(m_btConditional.sizeHint());
94 connect(&m_btConditional, SIGNAL(clicked()), this, SLOT(conditionalBP()));
96 m_layout.addLayout(&m_listandedit, 10);
97 m_layout.addLayout(&m_buttons);
98 m_listandedit.addWidget(&m_bpEdit);
99 m_listandedit.addWidget(&m_list, 10);
100 m_buttons.addWidget(&m_btAddBP);
101 m_buttons.addWidget(&m_btAddWP);
102 m_buttons.addWidget(&m_btRemove);
103 m_buttons.addWidget(&m_btEnaDis);
104 m_buttons.addWidget(&m_btViewCode);
105 m_buttons.addWidget(&m_btConditional);
106 m_buttons.addStretch(10);
108 m_layout.activate();
110 resize(350, 300);
112 m_bpEdit.setFocus();
115 BreakpointTable::~BreakpointTable()
119 void BreakpointTable::updateBreakList()
121 std::list<BreakpointItem*> deletedItems;
123 for (QListViewItem* it = m_list.firstChild(); it != 0; it = it->nextSibling()) {
124 deletedItems.push_back(static_cast<BreakpointItem*>(it));
127 // get the new list
128 for (KDebugger::BrkptROIterator bp = m_debugger->breakpointsBegin(); bp != m_debugger->breakpointsEnd(); ++bp)
130 // look up this item
131 for (std::list<BreakpointItem*>::iterator o = deletedItems.begin(); o != deletedItems.end(); ++o)
133 if ((*o)->id == bp->id) {
134 (*o)->updateFrom(*bp);
135 deletedItems.erase(o); /* don't delete */
136 goto nextItem;
139 // not in the list; add it
140 new BreakpointItem(&m_list, *bp);
141 nextItem:;
144 // delete all untouched breakpoints
145 while (!deletedItems.empty()) {
146 delete deletedItems.front();
147 deletedItems.pop_front();
151 BreakpointItem::BreakpointItem(QListView* list, const Breakpoint& bp) :
152 QListViewItem(list),
153 Breakpoint(bp)
155 display();
158 void BreakpointItem::updateFrom(const Breakpoint& bp)
160 Breakpoint::operator=(bp); /* assign new values */
161 display();
164 void BreakpointTable::addBP()
166 // set a breakpoint at the specified text
167 QString bpText = m_bpEdit.text();
168 bpText = bpText.stripWhiteSpace();
169 if (m_debugger->isReady())
171 Breakpoint* bp = new Breakpoint;
172 bp->text = bpText;
174 m_debugger->setBreakpoint(bp, false);
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 Breakpoint* bp = new Breakpoint;
185 bp->type = Breakpoint::watchpoint;
186 bp->text = wpExpr;
188 m_debugger->setBreakpoint(bp, false);
192 void BreakpointTable::removeBP()
194 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
195 if (bp != 0) {
196 m_debugger->deleteBreakpoint(bp->id);
197 // note that bp may be deleted by now
198 // (if bp was an orphaned breakpoint)
202 void BreakpointTable::enadisBP()
204 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
205 if (bp != 0) {
206 m_debugger->enableDisableBreakpoint(bp->id);
210 void BreakpointTable::viewBP()
212 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
213 if (bp == 0)
214 return;
216 if (!m_debugger->infoLine(bp->fileName, bp->lineNo, bp->address))
217 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
220 void BreakpointTable::updateUI()
222 bool enableChkpt = m_debugger->canChangeBreakpoints();
223 m_btAddBP.setEnabled(enableChkpt);
224 m_btAddWP.setEnabled(enableChkpt);
226 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
227 m_btViewCode.setEnabled(bp != 0);
229 if (bp == 0) {
230 enableChkpt = false;
231 } else {
232 if (bp->enabled()) {
233 m_btEnaDis.setText(i18n("&Disable"));
234 } else {
235 m_btEnaDis.setText(i18n("&Enable"));
238 m_btRemove.setEnabled(enableChkpt);
239 m_btEnaDis.setEnabled(enableChkpt);
240 m_btConditional.setEnabled(enableChkpt);
243 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
245 if (ev->type() == QEvent::MouseButtonPress)
247 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
248 if (mev->button() == Qt::MidButton) {
249 // enable or disable the clicked-on item
250 BreakpointItem* bp =
251 static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
252 if (bp != 0)
254 m_debugger->enableDisableBreakpoint(bp->id);
256 return true;
259 return QWidget::eventFilter(ob, ev);
262 class ConditionalDlg : public QDialog
264 public:
265 ConditionalDlg(QWidget* parent);
266 ~ConditionalDlg();
268 void setCondition(const QString& text) { m_condition.setText(text); }
269 QString condition() { return m_condition.text(); }
270 void setIgnoreCount(uint count);
271 uint ignoreCount();
273 protected:
274 QLabel m_conditionLabel;
275 QLineEdit m_condition;
276 QLabel m_ignoreLabel;
277 QLineEdit m_ignoreCount;
278 QPushButton m_buttonOK;
279 QPushButton m_buttonCancel;
280 QVBoxLayout m_layout;
281 QGridLayout m_inputs;
282 QHBoxLayout m_buttons;
285 void BreakpointTable::conditionalBP()
287 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
288 if (bp == 0)
289 return;
292 * Important: we must not keep a pointer to the Breakpoint around,
293 * since it may vanish while the modal dialog is open through other
294 * user interactions (like clicking at the breakpoint in the source
295 * window)!
297 int id = bp->id;
299 ConditionalDlg dlg(this);
300 dlg.setCondition(bp->condition);
301 dlg.setIgnoreCount(bp->ignoreCount);
303 if (dlg.exec() != QDialog::Accepted)
304 return;
306 QString conditionInput = dlg.condition();
307 int ignoreCount = dlg.ignoreCount();
308 m_debugger->conditionalBreakpoint(id, conditionInput, ignoreCount);
312 void BreakpointTable::initListAndIcons()
314 m_list.addColumn(i18n("Location"), 220);
315 m_list.addColumn(i18n("Address"), 65);
316 m_list.addColumn(i18n("Hits"), 30);
317 m_list.addColumn(i18n("Ignore"), 30);
318 m_list.addColumn(i18n("Condition"), 200);
320 m_list.setMinimumSize(200, 100);
322 m_list.setSorting(-1);
324 // add pixmaps
325 QPixmap brkena = UserIcon("brkena.xpm");
326 QPixmap brkdis = UserIcon("brkdis.xpm");
327 QPixmap watchena = UserIcon("watchena.xpm");
328 QPixmap watchdis = UserIcon("watchdis.xpm");
329 QPixmap brktmp = UserIcon("brktmp.xpm");
330 QPixmap brkcond = UserIcon("brkcond.xpm");
331 QPixmap brkorph = UserIcon("brkorph.xpm");
334 * There are 32 different pixmaps: The basic enabled or disabled
335 * breakpoint, plus an optional overlaid brktmp icon plus an optional
336 * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
337 * the same sequence for watchpoints.
339 m_icons.resize(32);
340 QPixmap canvas(16,16);
342 for (int i = 0; i < 32; i++) {
344 QPainter p(&canvas);
345 // clear canvas
346 p.fillRect(0,0, canvas.width(),canvas.height(), Qt::cyan);
347 // basic icon
348 if (i & 1) {
349 p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
350 } else {
351 p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
353 // temporary overlay
354 if (i & 2) {
355 p.drawPixmap(1,1, brktmp);
357 // conditional overlay
358 if (i & 4) {
359 p.drawPixmap(1,1, brkcond);
361 // orphan overlay
362 if (i & 16) {
363 p.drawPixmap(1,1, brkorph);
366 canvas.setMask(canvas.createHeuristicMask());
367 m_icons[i] = canvas;
371 void BreakpointItem::display()
373 BreakpointTable* lb = static_cast<BreakpointTable*>(listView()->parent());
375 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
376 int code = enabled() ? 1 : 0;
377 if (temporary)
378 code += 2;
379 if (!condition.isEmpty() || ignoreCount > 0)
380 code += 4;
381 if (type == watchpoint)
382 code += 8;
383 if (isOrphaned())
384 code += 16;
385 setPixmap(0, lb->m_icons[code]);
387 // more breakpoint info
388 if (!location.isEmpty()) {
389 setText(0, location);
390 } else if (!Breakpoint::text.isEmpty()) {
391 setText(0, Breakpoint::text);
392 } else if (!fileName.isEmpty()) {
393 // use only the file name portion
394 QString file = fileName;
395 int slash = file.findRev('/');
396 if (slash >= 0) {
397 file = file.mid(slash+1);
399 // correct zero-based line-numbers
400 setText(0, file + ":" + QString::number(lineNo+1));
401 } else {
402 setText(0, "*" + address.asString());
405 int c = 0;
406 setText(++c, address.asString());
407 QString tmp;
408 if (hitCount == 0) {
409 setText(++c, QString());
410 } else {
411 tmp.setNum(hitCount);
412 setText(++c, tmp);
414 if (ignoreCount == 0) {
415 setText(++c, QString());
416 } else {
417 tmp.setNum(ignoreCount);
418 setText(++c, tmp);
420 if (condition.isEmpty()) {
421 setText(++c, QString());
422 } else {
423 setText(++c, condition);
428 ConditionalDlg::ConditionalDlg(QWidget* parent) :
429 QDialog(parent, "conditional", true),
430 m_conditionLabel(this, "condLabel"),
431 m_condition(this, "condition"),
432 m_ignoreLabel(this, "ignoreLabel"),
433 m_ignoreCount(this, "ignoreCount"),
434 m_buttonOK(this, "ok"),
435 m_buttonCancel(this, "cancel"),
436 m_layout(this, 10),
437 m_inputs(2, 2, 10),
438 m_buttons(4)
440 QString title = kapp->caption();
441 title += i18n(": Conditional breakpoint");
442 setCaption(title);
444 m_conditionLabel.setText(i18n("&Condition:"));
445 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
446 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
447 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
449 m_condition.setMinimumSize(150, 24);
450 m_condition.setMaxLength(10000);
451 m_condition.setFrame(true);
452 m_ignoreCount.setMinimumSize(150, 24);
453 m_ignoreCount.setMaxLength(10000);
454 m_ignoreCount.setFrame(true);
456 m_conditionLabel.setBuddy(&m_condition);
457 m_ignoreLabel.setBuddy(&m_ignoreCount);
459 m_buttonOK.setMinimumSize(100, 30);
460 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
461 m_buttonOK.setText(i18n("OK"));
462 m_buttonOK.setDefault(true);
464 m_buttonCancel.setMinimumSize(100, 30);
465 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
466 m_buttonCancel.setText(i18n("Cancel"));
468 m_layout.addLayout(&m_inputs);
469 m_inputs.addWidget(&m_conditionLabel, 0, 0);
470 m_inputs.addWidget(&m_condition, 0, 1);
471 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
472 m_inputs.addWidget(&m_ignoreCount, 1, 1);
473 m_inputs.setColStretch(1, 10);
474 m_layout.addLayout(&m_buttons);
475 m_layout.addStretch(10);
476 m_buttons.addStretch(10);
477 m_buttons.addWidget(&m_buttonOK);
478 m_buttons.addSpacing(40);
479 m_buttons.addWidget(&m_buttonCancel);
480 m_buttons.addStretch(10);
482 m_layout.activate();
484 m_condition.setFocus();
485 resize(400, 100);
488 ConditionalDlg::~ConditionalDlg()
492 uint ConditionalDlg::ignoreCount()
494 bool ok;
495 QString input = m_ignoreCount.text();
496 uint result = input.toUInt(&ok);
497 return ok ? result : 0;
500 void ConditionalDlg::setIgnoreCount(uint count)
502 QString text;
503 // set empty if ignore count is zero
504 if (count > 0) {
505 text.setNum(count);
507 m_ignoreCount.setText(text);
511 #include "brkpt.moc"