Convert deprecated Q3ListWidget in breakpoint window to newer QTreeWidget.
[kdbg.git] / kdbg / brkpt.cpp
blob41d44e061e52fa46761c191d9524a3ce594ba518
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 <kglobal.h>
8 #include <klocale.h> /* i18n */
9 #include <kiconloader.h>
10 #include <ksimpleconfig.h>
11 #include <QDialog>
12 #include <QPainter>
13 #include <QLabel>
14 #include <QBitmap>
15 #include <Q3GridLayout>
16 #include <QMouseEvent>
17 #include "debugger.h"
18 #include "brkpt.h"
19 #include "dbgdriver.h"
20 #include <ctype.h>
21 #include <list>
22 #include "mydebug.h"
25 class BreakpointItem : public QTreeWidgetItem, public Breakpoint
27 public:
28 BreakpointItem(QTreeWidget* list, const Breakpoint& bp);
29 void updateFrom(const Breakpoint& bp);
30 void display(); /* sets icon and visible texts */
31 bool enabled() const { return Breakpoint::enabled; }
35 BreakpointTable::BreakpointTable(QWidget* parent) :
36 QWidget(parent),
37 m_debugger(0),
38 m_bpEdit(this, "bpedit"),
39 m_list(this),
40 m_btAddBP(this, "addbp"),
41 m_btAddWP(this, "addwp"),
42 m_btRemove(this, "remove"),
43 m_btEnaDis(this, "enadis"),
44 m_btViewCode(this, "view"),
45 m_btConditional(this, "conditional"),
46 m_layout(this, 8),
47 m_listandedit(8),
48 m_buttons(8)
50 m_bpEdit.setMinimumSize(m_bpEdit.sizeHint());
51 connect(&m_bpEdit, SIGNAL(returnPressed()), this, SLOT(addBP()));
53 initListAndIcons();
55 m_list.setRootIsDecorated(false);
57 connect(&m_list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(updateUI()));
58 // double click on item is same as View code
59 connect(&m_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), 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 std::list<BreakpointItem*> deletedItems;
127 for (int i = 0 ; i < m_list.topLevelItemCount(); i++)
129 deletedItems.push_back(static_cast<BreakpointItem*>(m_list.topLevelItem(i)));
132 // get the new list
133 for (KDebugger::BrkptROIterator bp = m_debugger->breakpointsBegin(); bp != m_debugger->breakpointsEnd(); ++bp)
135 // look up this item
136 for (std::list<BreakpointItem*>::iterator o = deletedItems.begin(); o != deletedItems.end(); ++o)
138 if ((*o)->id == bp->id) {
139 (*o)->updateFrom(*bp);
140 deletedItems.erase(o); /* 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 while (!deletedItems.empty()) {
151 delete deletedItems.front();
152 deletedItems.pop_front();
156 BreakpointItem::BreakpointItem(QTreeWidget* list, const Breakpoint& bp) :
157 QTreeWidgetItem(list),
158 Breakpoint(bp)
160 display();
163 void BreakpointItem::updateFrom(const Breakpoint& bp)
165 Breakpoint::operator=(bp); /* assign new values */
166 display();
169 void BreakpointTable::addBP()
171 // set a breakpoint at the specified text
172 QString bpText = m_bpEdit.text();
173 bpText = bpText.stripWhiteSpace();
174 if (m_debugger->isReady())
176 Breakpoint* bp = new Breakpoint;
177 bp->text = bpText;
179 m_debugger->setBreakpoint(bp, false);
183 void BreakpointTable::addWP()
185 // set a watchpoint for the specified expression
186 QString wpExpr = m_bpEdit.text();
187 wpExpr = wpExpr.stripWhiteSpace();
188 if (m_debugger->isReady()) {
189 Breakpoint* bp = new Breakpoint;
190 bp->type = Breakpoint::watchpoint;
191 bp->text = wpExpr;
193 m_debugger->setBreakpoint(bp, false);
197 void BreakpointTable::removeBP()
199 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
200 if (bp != 0) {
201 m_debugger->deleteBreakpoint(bp->id);
202 // note that bp may be deleted by now
203 // (if bp was an orphaned breakpoint)
207 void BreakpointTable::enadisBP()
209 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
210 if (bp != 0) {
211 m_debugger->enableDisableBreakpoint(bp->id);
215 void BreakpointTable::viewBP()
217 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
218 if (bp == 0)
219 return;
221 if (!m_debugger->infoLine(bp->fileName, bp->lineNo, bp->address))
222 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
225 void BreakpointTable::updateUI()
227 bool enableChkpt = m_debugger->canChangeBreakpoints();
228 m_btAddBP.setEnabled(enableChkpt);
229 m_btAddWP.setEnabled(enableChkpt);
231 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
232 m_btViewCode.setEnabled(bp != 0);
234 if (bp == 0) {
235 enableChkpt = false;
236 } else {
237 if (bp->enabled()) {
238 m_btEnaDis.setText(i18n("&Disable"));
239 } else {
240 m_btEnaDis.setText(i18n("&Enable"));
243 m_btRemove.setEnabled(enableChkpt);
244 m_btEnaDis.setEnabled(enableChkpt);
245 m_btConditional.setEnabled(enableChkpt);
248 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
250 if (ev->type() == QEvent::MouseButtonPress)
252 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
253 if (mev->button() == Qt::MidButton) {
254 // enable or disable the clicked-on item
255 BreakpointItem* bp =
256 static_cast<BreakpointItem*>(m_list.itemAt(mev->pos()));
257 if (bp != 0)
259 m_debugger->enableDisableBreakpoint(bp->id);
261 return true;
264 return QWidget::eventFilter(ob, ev);
267 class ConditionalDlg : public QDialog
269 public:
270 ConditionalDlg(QWidget* parent);
271 ~ConditionalDlg();
273 void setCondition(const QString& text) { m_condition.setText(text); }
274 QString condition() { return m_condition.text(); }
275 void setIgnoreCount(uint count);
276 uint ignoreCount();
278 protected:
279 QLabel m_conditionLabel;
280 QLineEdit m_condition;
281 QLabel m_ignoreLabel;
282 QLineEdit m_ignoreCount;
283 QPushButton m_buttonOK;
284 QPushButton m_buttonCancel;
285 Q3VBoxLayout m_layout;
286 Q3GridLayout m_inputs;
287 Q3HBoxLayout m_buttons;
290 void BreakpointTable::conditionalBP()
292 BreakpointItem* bp = static_cast<BreakpointItem*>(m_list.currentItem());
293 if (bp == 0)
294 return;
297 * Important: we must not keep a pointer to the Breakpoint around,
298 * since it may vanish while the modal dialog is open through other
299 * user interactions (like clicking at the breakpoint in the source
300 * window)!
302 int id = bp->id;
304 ConditionalDlg dlg(this);
305 dlg.setCondition(bp->condition);
306 dlg.setIgnoreCount(bp->ignoreCount);
308 if (dlg.exec() != QDialog::Accepted)
309 return;
311 QString conditionInput = dlg.condition();
312 int ignoreCount = dlg.ignoreCount();
313 m_debugger->conditionalBreakpoint(id, conditionInput, ignoreCount);
317 void BreakpointTable::initListAndIcons()
319 m_list.setHeaderLabels(
320 QStringList()
321 << i18n("Location")
322 << i18n("Address")
323 << i18n("Hits")
324 << i18n("Ignore")
325 << i18n("Condition"));
326 m_list.setColumnWidth(0, 220);
327 m_list.setColumnWidth(1, 65);
328 m_list.setColumnWidth(2, 30);
329 m_list.setColumnWidth(3, 30);
330 m_list.setColumnWidth(4, 200);
332 m_list.setMinimumSize(200, 100);
334 m_list.setSortingEnabled(false);
336 // add pixmaps
337 QPixmap brkena = UserIcon("brkena.xpm");
338 QPixmap brkdis = UserIcon("brkdis.xpm");
339 QPixmap watchena = UserIcon("watchena.xpm");
340 QPixmap watchdis = UserIcon("watchdis.xpm");
341 QPixmap brktmp = UserIcon("brktmp.xpm");
342 QPixmap brkcond = UserIcon("brkcond.xpm");
343 QPixmap brkorph = UserIcon("brkorph.xpm");
346 * There are 32 different pixmaps: The basic enabled or disabled
347 * breakpoint, plus an optional overlaid brktmp icon plus an optional
348 * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
349 * the same sequence for watchpoints.
351 m_icons.resize(32);
352 QPixmap canvas(16,16);
354 for (int i = 0; i < 32; i++) {
356 QPainter p(&canvas);
357 // clear canvas
358 p.fillRect(0,0, canvas.width(),canvas.height(), Qt::cyan);
359 // basic icon
360 if (i & 1) {
361 p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
362 } else {
363 p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
365 // temporary overlay
366 if (i & 2) {
367 p.drawPixmap(1,1, brktmp);
369 // conditional overlay
370 if (i & 4) {
371 p.drawPixmap(1,1, brkcond);
373 // orphan overlay
374 if (i & 16) {
375 p.drawPixmap(1,1, brkorph);
378 canvas.setMask(canvas.createHeuristicMask());
379 m_icons[i] = canvas;
383 void BreakpointItem::display()
385 BreakpointTable* lb = static_cast<BreakpointTable*>(treeWidget()->parent());
387 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
388 int code = enabled() ? 1 : 0;
389 if (temporary)
390 code += 2;
391 if (!condition.isEmpty() || ignoreCount > 0)
392 code += 4;
393 if (Breakpoint::type == watchpoint)
394 code += 8;
395 if (isOrphaned())
396 code += 16;
397 setIcon(0, QIcon(lb->m_icons[code]));
399 // more breakpoint info
400 if (!location.isEmpty()) {
401 setText(0, location);
402 } else if (!Breakpoint::text.isEmpty()) {
403 setText(0, Breakpoint::text);
404 } else if (!fileName.isEmpty()) {
405 // use only the file name portion
406 QString file = fileName;
407 int slash = file.findRev('/');
408 if (slash >= 0) {
409 file = file.mid(slash+1);
411 // correct zero-based line-numbers
412 setText(0, file + ":" + QString::number(lineNo+1));
413 } else {
414 setText(0, "*" + address.asString());
417 int c = 0;
418 setText(++c, address.asString());
419 QString tmp;
420 if (hitCount == 0) {
421 setText(++c, QString());
422 } else {
423 tmp.setNum(hitCount);
424 setText(++c, tmp);
426 if (ignoreCount == 0) {
427 setText(++c, QString());
428 } else {
429 tmp.setNum(ignoreCount);
430 setText(++c, tmp);
432 if (condition.isEmpty()) {
433 setText(++c, QString());
434 } else {
435 setText(++c, condition);
440 ConditionalDlg::ConditionalDlg(QWidget* parent) :
441 QDialog(parent, "conditional", true),
442 m_conditionLabel(this, "condLabel"),
443 m_condition(this, "condition"),
444 m_ignoreLabel(this, "ignoreLabel"),
445 m_ignoreCount(this, "ignoreCount"),
446 m_buttonOK(this, "ok"),
447 m_buttonCancel(this, "cancel"),
448 m_layout(this, 10),
449 m_inputs(2, 2, 10),
450 m_buttons(4)
452 QString title = KGlobal::caption();
453 title += i18n(": Conditional breakpoint");
454 setCaption(title);
456 m_conditionLabel.setText(i18n("&Condition:"));
457 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
458 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
459 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
461 m_condition.setMinimumSize(150, 24);
462 m_condition.setMaxLength(10000);
463 m_condition.setFrame(true);
464 m_ignoreCount.setMinimumSize(150, 24);
465 m_ignoreCount.setMaxLength(10000);
466 m_ignoreCount.setFrame(true);
468 m_conditionLabel.setBuddy(&m_condition);
469 m_ignoreLabel.setBuddy(&m_ignoreCount);
471 m_buttonOK.setMinimumSize(100, 30);
472 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
473 m_buttonOK.setText(i18n("OK"));
474 m_buttonOK.setDefault(true);
476 m_buttonCancel.setMinimumSize(100, 30);
477 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
478 m_buttonCancel.setText(i18n("Cancel"));
480 m_layout.addLayout(&m_inputs);
481 m_inputs.addWidget(&m_conditionLabel, 0, 0);
482 m_inputs.addWidget(&m_condition, 0, 1);
483 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
484 m_inputs.addWidget(&m_ignoreCount, 1, 1);
485 m_inputs.setColStretch(1, 10);
486 m_layout.addLayout(&m_buttons);
487 m_layout.addStretch(10);
488 m_buttons.addStretch(10);
489 m_buttons.addWidget(&m_buttonOK);
490 m_buttons.addSpacing(40);
491 m_buttons.addWidget(&m_buttonCancel);
492 m_buttons.addStretch(10);
494 m_layout.activate();
496 m_condition.setFocus();
497 resize(400, 100);
500 ConditionalDlg::~ConditionalDlg()
504 uint ConditionalDlg::ignoreCount()
506 bool ok;
507 QString input = m_ignoreCount.text();
508 uint result = input.toUInt(&ok);
509 return ok ? result : 0;
512 void ConditionalDlg::setIgnoreCount(uint count)
514 QString text;
515 // set empty if ignore count is zero
516 if (count > 0) {
517 text.setNum(count);
519 m_ignoreCount.setText(text);
523 #include "brkpt.moc"