Move layout code in breakpoint widget to a QtDesigner UI file.
[kdbg.git] / kdbg / brkpt.cpp
blob816c95a2c693f5796d3e1573c801373d3501a97a
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 <QPixmap>
16 #include <Q3GridLayout>
17 #include <Q3VBoxLayout>
18 #include <Q3HBoxLayout>
20 #include <QMouseEvent>
21 #include "debugger.h"
22 #include "brkpt.h"
23 #include "dbgdriver.h"
24 #include <ctype.h>
25 #include <list>
26 #include "mydebug.h"
29 class BreakpointItem : public QTreeWidgetItem, public Breakpoint
31 public:
32 BreakpointItem(QTreeWidget* list, const Breakpoint& bp);
33 void updateFrom(const Breakpoint& bp);
34 void display(); /* sets icon and visible texts */
35 bool enabled() const { return Breakpoint::enabled; }
39 BreakpointTable::BreakpointTable(QWidget* parent) :
40 QWidget(parent),
41 m_debugger(0)
43 m_ui.setupUi(this);
44 connect(m_ui.bpEdit, SIGNAL(returnPressed()),
45 this, SLOT(on_btAddBP_clicked()));
47 initListAndIcons();
49 connect(m_ui.bpList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
50 this, SLOT(updateUI()));
51 // double click on item is same as View code
52 connect(m_ui.bpList,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
53 this, SLOT(on_btViewCode_clicked()));
55 // need mouse button events
56 m_ui.bpList->viewport()->installEventFilter(this);
59 BreakpointTable::~BreakpointTable()
63 void BreakpointTable::updateBreakList()
65 std::list<BreakpointItem*> deletedItems;
67 for (int i = 0 ; i < m_ui.bpList->topLevelItemCount(); i++)
69 deletedItems.push_back(static_cast<BreakpointItem*>(m_ui.bpList->topLevelItem(i)));
72 // get the new list
73 for (KDebugger::BrkptROIterator bp = m_debugger->breakpointsBegin(); bp != m_debugger->breakpointsEnd(); ++bp)
75 // look up this item
76 for (std::list<BreakpointItem*>::iterator o = deletedItems.begin(); o != deletedItems.end(); ++o)
78 if ((*o)->id == bp->id) {
79 (*o)->updateFrom(*bp);
80 deletedItems.erase(o); /* don't delete */
81 goto nextItem;
84 // not in the list; add it
85 new BreakpointItem(m_ui.bpList,*bp);
86 nextItem:;
89 // delete all untouched breakpoints
90 while (!deletedItems.empty()) {
91 delete deletedItems.front();
92 deletedItems.pop_front();
96 BreakpointItem::BreakpointItem(QTreeWidget* list, const Breakpoint& bp) :
97 QTreeWidgetItem(list),
98 Breakpoint(bp)
100 display();
103 void BreakpointItem::updateFrom(const Breakpoint& bp)
105 Breakpoint::operator=(bp); /* assign new values */
106 display();
109 void BreakpointTable::on_btAddBP_clicked()
111 // set a breakpoint at the specified text
112 QString bpText = m_ui.bpEdit->text();
113 bpText = bpText.stripWhiteSpace();
114 if (m_debugger->isReady())
116 Breakpoint* bp = new Breakpoint;
117 bp->text = bpText;
119 m_debugger->setBreakpoint(bp, false);
123 void BreakpointTable::on_btAddWP_clicked()
125 // set a watchpoint for the specified expression
126 QString wpExpr = m_ui.bpEdit->text();
127 wpExpr = wpExpr.stripWhiteSpace();
128 if (m_debugger->isReady()) {
129 Breakpoint* bp = new Breakpoint;
130 bp->type = Breakpoint::watchpoint;
131 bp->text = wpExpr;
133 m_debugger->setBreakpoint(bp, false);
137 void BreakpointTable::on_btRemove_clicked()
139 BreakpointItem* bp = static_cast<BreakpointItem*>(m_ui.bpList->currentItem());
140 if (bp != 0) {
141 m_debugger->deleteBreakpoint(bp->id);
142 // note that bp may be deleted by now
143 // (if bp was an orphaned breakpoint)
147 void BreakpointTable::on_btEnaDis_clicked()
149 BreakpointItem* bp = static_cast<BreakpointItem*>(m_ui.bpList->currentItem());
150 if (bp != 0) {
151 m_debugger->enableDisableBreakpoint(bp->id);
155 void BreakpointTable::on_btViewCode_clicked()
157 BreakpointItem* bp = static_cast<BreakpointItem*>(m_ui.bpList->currentItem());
158 if (bp == 0)
159 return;
161 if (!m_debugger->infoLine(bp->fileName, bp->lineNo, bp->address))
162 emit activateFileLine(bp->fileName, bp->lineNo, bp->address);
165 void BreakpointTable::updateUI()
167 bool enableChkpt = m_debugger->canChangeBreakpoints();
168 m_ui.btAddBP->setEnabled(enableChkpt);
169 m_ui.btAddWP->setEnabled(enableChkpt);
171 BreakpointItem* bp = static_cast<BreakpointItem*>(m_ui.bpList->currentItem());
172 m_ui.btViewCode->setEnabled(bp != 0);
174 if (bp == 0) {
175 enableChkpt = false;
176 } else {
177 if (bp->enabled()) {
178 m_ui.btEnaDis->setText(i18n("&Disable"));
179 } else {
180 m_ui.btEnaDis->setText(i18n("&Enable"));
183 m_ui.btRemove->setEnabled(enableChkpt);
184 m_ui.btEnaDis->setEnabled(enableChkpt);
185 m_ui.btConditional->setEnabled(enableChkpt);
188 bool BreakpointTable::eventFilter(QObject* ob, QEvent* ev)
190 if (ev->type() == QEvent::MouseButtonPress)
192 QMouseEvent* mev = static_cast<QMouseEvent*>(ev);
193 if (mev->button() == Qt::MidButton) {
194 // enable or disable the clicked-on item
195 BreakpointItem* bp =
196 static_cast<BreakpointItem*>(m_ui.bpList->itemAt(mev->pos()));
197 if (bp != 0)
199 m_debugger->enableDisableBreakpoint(bp->id);
201 return true;
204 return QWidget::eventFilter(ob, ev);
207 class ConditionalDlg : public QDialog
209 public:
210 ConditionalDlg(QWidget* parent);
211 ~ConditionalDlg();
213 void setCondition(const QString& text) { m_condition.setText(text); }
214 QString condition() { return m_condition.text(); }
215 void setIgnoreCount(uint count);
216 uint ignoreCount();
218 protected:
219 QLabel m_conditionLabel;
220 QLineEdit m_condition;
221 QLabel m_ignoreLabel;
222 QLineEdit m_ignoreCount;
223 QPushButton m_buttonOK;
224 QPushButton m_buttonCancel;
225 Q3VBoxLayout m_layout;
226 Q3GridLayout m_inputs;
227 Q3HBoxLayout m_buttons;
230 void BreakpointTable::on_btConditional_clicked()
232 BreakpointItem* bp = static_cast<BreakpointItem*>(m_ui.bpList->currentItem());
233 if (bp == 0)
234 return;
237 * Important: we must not keep a pointer to the Breakpoint around,
238 * since it may vanish while the modal dialog is open through other
239 * user interactions (like clicking at the breakpoint in the source
240 * window)!
242 int id = bp->id;
244 ConditionalDlg dlg(this);
245 dlg.setCondition(bp->condition);
246 dlg.setIgnoreCount(bp->ignoreCount);
248 if (dlg.exec() != QDialog::Accepted)
249 return;
251 QString conditionInput = dlg.condition();
252 int ignoreCount = dlg.ignoreCount();
253 m_debugger->conditionalBreakpoint(id, conditionInput, ignoreCount);
257 void BreakpointTable::initListAndIcons()
259 m_ui.bpList->setColumnWidth(0, 220);
260 m_ui.bpList->setColumnWidth(1, 65);
261 m_ui.bpList->setColumnWidth(2, 30);
262 m_ui.bpList->setColumnWidth(3, 30);
263 m_ui.bpList->setColumnWidth(4, 200);
265 // add pixmaps
266 QPixmap brkena = UserIcon("brkena.xpm");
267 QPixmap brkdis = UserIcon("brkdis.xpm");
268 QPixmap watchena = UserIcon("watchena.xpm");
269 QPixmap watchdis = UserIcon("watchdis.xpm");
270 QPixmap brktmp = UserIcon("brktmp.xpm");
271 QPixmap brkcond = UserIcon("brkcond.xpm");
272 QPixmap brkorph = UserIcon("brkorph.xpm");
275 * There are 32 different pixmaps: The basic enabled or disabled
276 * breakpoint, plus an optional overlaid brktmp icon plus an optional
277 * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
278 * the same sequence for watchpoints.
280 m_icons.resize(32);
281 QPixmap canvas(16,16);
283 for (int i = 0; i < 32; i++) {
285 QPainter p(&canvas);
286 // clear canvas
287 p.fillRect(0,0, canvas.width(),canvas.height(), Qt::cyan);
288 // basic icon
289 if (i & 1) {
290 p.drawPixmap(1,1, (i & 8) ? watchena : brkena);
291 } else {
292 p.drawPixmap(1,1, (i & 8) ? watchdis : brkdis);
294 // temporary overlay
295 if (i & 2) {
296 p.drawPixmap(1,1, brktmp);
298 // conditional overlay
299 if (i & 4) {
300 p.drawPixmap(1,1, brkcond);
302 // orphan overlay
303 if (i & 16) {
304 p.drawPixmap(1,1, brkorph);
307 canvas.setMask(canvas.createHeuristicMask());
308 m_icons[i] = QIcon(canvas);
312 void BreakpointItem::display()
314 BreakpointTable* lb = static_cast<BreakpointTable*>(treeWidget()->parent());
316 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
317 int code = enabled() ? 1 : 0;
318 if (temporary)
319 code += 2;
320 if (!condition.isEmpty() || ignoreCount > 0)
321 code += 4;
322 if (Breakpoint::type == watchpoint)
323 code += 8;
324 if (isOrphaned())
325 code += 16;
326 setIcon(0, lb->m_icons[code]);
328 // more breakpoint info
329 if (!location.isEmpty()) {
330 setText(0, location);
331 } else if (!Breakpoint::text.isEmpty()) {
332 setText(0, Breakpoint::text);
333 } else if (!fileName.isEmpty()) {
334 // use only the file name portion
335 QString file = fileName;
336 int slash = file.findRev('/');
337 if (slash >= 0) {
338 file = file.mid(slash+1);
340 // correct zero-based line-numbers
341 setText(0, file + ":" + QString::number(lineNo+1));
342 } else {
343 setText(0, "*" + address.asString());
346 int c = 0;
347 setText(++c, address.asString());
348 QString tmp;
349 if (hitCount == 0) {
350 setText(++c, QString());
351 } else {
352 tmp.setNum(hitCount);
353 setText(++c, tmp);
355 if (ignoreCount == 0) {
356 setText(++c, QString());
357 } else {
358 tmp.setNum(ignoreCount);
359 setText(++c, tmp);
361 if (condition.isEmpty()) {
362 setText(++c, QString());
363 } else {
364 setText(++c, condition);
369 ConditionalDlg::ConditionalDlg(QWidget* parent) :
370 QDialog(parent, "conditional", true),
371 m_conditionLabel(this, "condLabel"),
372 m_condition(this, "condition"),
373 m_ignoreLabel(this, "ignoreLabel"),
374 m_ignoreCount(this, "ignoreCount"),
375 m_buttonOK(this, "ok"),
376 m_buttonCancel(this, "cancel"),
377 m_layout(this, 10),
378 m_inputs(2, 2, 10),
379 m_buttons(4)
381 QString title = KGlobal::caption();
382 title += i18n(": Conditional breakpoint");
383 setCaption(title);
385 m_conditionLabel.setText(i18n("&Condition:"));
386 m_conditionLabel.setMinimumSize(m_conditionLabel.sizeHint());
387 m_ignoreLabel.setText(i18n("Ignore &next hits:"));
388 m_ignoreLabel.setMinimumSize(m_ignoreLabel.sizeHint());
390 m_condition.setMinimumSize(150, 24);
391 m_condition.setMaxLength(10000);
392 m_condition.setFrame(true);
393 m_ignoreCount.setMinimumSize(150, 24);
394 m_ignoreCount.setMaxLength(10000);
395 m_ignoreCount.setFrame(true);
397 m_conditionLabel.setBuddy(&m_condition);
398 m_ignoreLabel.setBuddy(&m_ignoreCount);
400 m_buttonOK.setMinimumSize(100, 30);
401 connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
402 m_buttonOK.setText(i18n("OK"));
403 m_buttonOK.setDefault(true);
405 m_buttonCancel.setMinimumSize(100, 30);
406 connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
407 m_buttonCancel.setText(i18n("Cancel"));
409 m_layout.addLayout(&m_inputs);
410 m_inputs.addWidget(&m_conditionLabel, 0, 0);
411 m_inputs.addWidget(&m_condition, 0, 1);
412 m_inputs.addWidget(&m_ignoreLabel, 1, 0);
413 m_inputs.addWidget(&m_ignoreCount, 1, 1);
414 m_inputs.setColStretch(1, 10);
415 m_layout.addLayout(&m_buttons);
416 m_layout.addStretch(10);
417 m_buttons.addStretch(10);
418 m_buttons.addWidget(&m_buttonOK);
419 m_buttons.addSpacing(40);
420 m_buttons.addWidget(&m_buttonCancel);
421 m_buttons.addStretch(10);
423 m_layout.activate();
425 m_condition.setFocus();
426 resize(400, 100);
429 ConditionalDlg::~ConditionalDlg()
433 uint ConditionalDlg::ignoreCount()
435 bool ok;
436 QString input = m_ignoreCount.text();
437 uint result = input.toUInt(&ok);
438 return ok ? result : 0;
441 void ConditionalDlg::setIgnoreCount(uint count)
443 QString text;
444 // set empty if ignore count is zero
445 if (count > 0) {
446 text.setNum(count);
448 m_ignoreCount.setText(text);
452 #include "brkpt.moc"