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.
7 #include <kapplication.h>
8 #include <klocale.h> /* i18n */
9 #include <kiconloader.h>
10 #include <ksimpleconfig.h>
12 #include <qnamespace.h>
16 #include <Q3HBoxLayout>
17 #include <Q3GridLayout>
19 #include <QMouseEvent>
21 #include <Q3VBoxLayout>
24 #include "dbgdriver.h"
30 class BreakpointItem
: public Q3ListViewItem
, public Breakpoint
33 BreakpointItem(Q3ListView
* list
, const Breakpoint
& bp
);
34 void updateFrom(const Breakpoint
& bp
);
35 void display(); /* sets icon and visible texts */
36 bool enabled() const { return Breakpoint::enabled
; }
40 BreakpointTable::BreakpointTable(QWidget
* parent
) :
43 m_bpEdit(this, "bpedit"),
44 m_list(this, "bptable"),
45 m_btAddBP(this, "addbp"),
46 m_btAddWP(this, "addwp"),
47 m_btRemove(this, "remove"),
48 m_btEnaDis(this, "enadis"),
49 m_btViewCode(this, "view"),
50 m_btConditional(this, "conditional"),
55 m_bpEdit
.setMinimumSize(m_bpEdit
.sizeHint());
56 connect(&m_bpEdit
, SIGNAL(returnPressed()), this, SLOT(addBP()));
59 connect(&m_list
, SIGNAL(currentChanged(Q3ListViewItem
*)), SLOT(updateUI()));
60 // double click on item is same as View code
61 connect(&m_list
, SIGNAL(doubleClicked(Q3ListViewItem
*)), this, SLOT(viewBP()));
63 // need mouse button events
64 m_list
.viewport()->installEventFilter(this);
66 m_btAddBP
.setText(i18n("Add &Breakpoint"));
67 m_btAddBP
.setMinimumSize(m_btAddBP
.sizeHint());
68 connect(&m_btAddBP
, SIGNAL(clicked()), this, SLOT(addBP()));
70 m_btAddWP
.setText(i18n("Add &Watchpoint"));
71 m_btAddWP
.setMinimumSize(m_btAddWP
.sizeHint());
72 connect(&m_btAddWP
, SIGNAL(clicked()), this, SLOT(addWP()));
74 m_btRemove
.setText(i18n("&Remove"));
75 m_btRemove
.setMinimumSize(m_btRemove
.sizeHint());
76 connect(&m_btRemove
, SIGNAL(clicked()), this, SLOT(removeBP()));
78 // the Enable/Disable button changes its label
79 m_btEnaDis
.setText(i18n("&Disable"));
80 // make a dummy button to get the size of the alternate label
82 QSize size
= m_btEnaDis
.sizeHint();
83 QPushButton
dummy(this);
84 dummy
.setText(i18n("&Enable"));
85 QSize sizeAlt
= dummy
.sizeHint();
86 if (sizeAlt
.width() > size
.width())
87 size
.setWidth(sizeAlt
.width());
88 if (sizeAlt
.height() > size
.height())
89 size
.setHeight(sizeAlt
.height());
90 m_btEnaDis
.setMinimumSize(size
);
92 connect(&m_btEnaDis
, SIGNAL(clicked()), this, SLOT(enadisBP()));
94 m_btViewCode
.setText(i18n("&View Code"));
95 m_btViewCode
.setMinimumSize(m_btViewCode
.sizeHint());
96 connect(&m_btViewCode
, SIGNAL(clicked()), this, SLOT(viewBP()));
98 m_btConditional
.setText(i18n("&Conditional..."));
99 m_btConditional
.setMinimumSize(m_btConditional
.sizeHint());
100 connect(&m_btConditional
, SIGNAL(clicked()), this, SLOT(conditionalBP()));
102 m_layout
.addLayout(&m_listandedit
, 10);
103 m_layout
.addLayout(&m_buttons
);
104 m_listandedit
.addWidget(&m_bpEdit
);
105 m_listandedit
.addWidget(&m_list
, 10);
106 m_buttons
.addWidget(&m_btAddBP
);
107 m_buttons
.addWidget(&m_btAddWP
);
108 m_buttons
.addWidget(&m_btRemove
);
109 m_buttons
.addWidget(&m_btEnaDis
);
110 m_buttons
.addWidget(&m_btViewCode
);
111 m_buttons
.addWidget(&m_btConditional
);
112 m_buttons
.addStretch(10);
121 BreakpointTable::~BreakpointTable()
125 void BreakpointTable::updateBreakList()
127 std::list
<BreakpointItem
*> deletedItems
;
129 for (Q3ListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
130 deletedItems
.push_back(static_cast<BreakpointItem
*>(it
));
134 for (KDebugger::BrkptROIterator bp
= m_debugger
->breakpointsBegin(); bp
!= m_debugger
->breakpointsEnd(); ++bp
)
137 for (std::list
<BreakpointItem
*>::iterator o
= deletedItems
.begin(); o
!= deletedItems
.end(); ++o
)
139 if ((*o
)->id
== bp
->id
) {
140 (*o
)->updateFrom(*bp
);
141 deletedItems
.erase(o
); /* don't delete */
145 // not in the list; add it
146 new BreakpointItem(&m_list
, *bp
);
150 // delete all untouched breakpoints
151 while (!deletedItems
.empty()) {
152 delete deletedItems
.front();
153 deletedItems
.pop_front();
157 BreakpointItem::BreakpointItem(Q3ListView
* list
, const Breakpoint
& bp
) :
158 Q3ListViewItem(list
),
164 void BreakpointItem::updateFrom(const Breakpoint
& bp
)
166 Breakpoint::operator=(bp
); /* assign new values */
170 void BreakpointTable::addBP()
172 // set a breakpoint at the specified text
173 QString bpText
= m_bpEdit
.text();
174 bpText
= bpText
.stripWhiteSpace();
175 if (m_debugger
->isReady())
177 Breakpoint
* bp
= new Breakpoint
;
180 m_debugger
->setBreakpoint(bp
, false);
184 void BreakpointTable::addWP()
186 // set a watchpoint for the specified expression
187 QString wpExpr
= m_bpEdit
.text();
188 wpExpr
= wpExpr
.stripWhiteSpace();
189 if (m_debugger
->isReady()) {
190 Breakpoint
* bp
= new Breakpoint
;
191 bp
->type
= Breakpoint::watchpoint
;
194 m_debugger
->setBreakpoint(bp
, false);
198 void BreakpointTable::removeBP()
200 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
202 m_debugger
->deleteBreakpoint(bp
->id
);
203 // note that bp may be deleted by now
204 // (if bp was an orphaned breakpoint)
208 void BreakpointTable::enadisBP()
210 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
212 m_debugger
->enableDisableBreakpoint(bp
->id
);
216 void BreakpointTable::viewBP()
218 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
222 if (!m_debugger
->infoLine(bp
->fileName
, bp
->lineNo
, bp
->address
))
223 emit
activateFileLine(bp
->fileName
, bp
->lineNo
, bp
->address
);
226 void BreakpointTable::updateUI()
228 bool enableChkpt
= m_debugger
->canChangeBreakpoints();
229 m_btAddBP
.setEnabled(enableChkpt
);
230 m_btAddWP
.setEnabled(enableChkpt
);
232 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
233 m_btViewCode
.setEnabled(bp
!= 0);
239 m_btEnaDis
.setText(i18n("&Disable"));
241 m_btEnaDis
.setText(i18n("&Enable"));
244 m_btRemove
.setEnabled(enableChkpt
);
245 m_btEnaDis
.setEnabled(enableChkpt
);
246 m_btConditional
.setEnabled(enableChkpt
);
249 bool BreakpointTable::eventFilter(QObject
* ob
, QEvent
* ev
)
251 if (ev
->type() == QEvent::MouseButtonPress
)
253 QMouseEvent
* mev
= static_cast<QMouseEvent
*>(ev
);
254 if (mev
->button() == Qt::MidButton
) {
255 // enable or disable the clicked-on item
257 static_cast<BreakpointItem
*>(m_list
.itemAt(mev
->pos()));
260 m_debugger
->enableDisableBreakpoint(bp
->id
);
265 return QWidget::eventFilter(ob
, ev
);
268 class ConditionalDlg
: public QDialog
271 ConditionalDlg(QWidget
* parent
);
274 void setCondition(const QString
& text
) { m_condition
.setText(text
); }
275 QString
condition() { return m_condition
.text(); }
276 void setIgnoreCount(uint count
);
280 QLabel m_conditionLabel
;
281 QLineEdit m_condition
;
282 QLabel m_ignoreLabel
;
283 QLineEdit m_ignoreCount
;
284 QPushButton m_buttonOK
;
285 QPushButton m_buttonCancel
;
286 Q3VBoxLayout m_layout
;
287 Q3GridLayout m_inputs
;
288 Q3HBoxLayout m_buttons
;
291 void BreakpointTable::conditionalBP()
293 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
298 * Important: we must not keep a pointer to the Breakpoint around,
299 * since it may vanish while the modal dialog is open through other
300 * user interactions (like clicking at the breakpoint in the source
305 ConditionalDlg
dlg(this);
306 dlg
.setCondition(bp
->condition
);
307 dlg
.setIgnoreCount(bp
->ignoreCount
);
309 if (dlg
.exec() != QDialog::Accepted
)
312 QString conditionInput
= dlg
.condition();
313 int ignoreCount
= dlg
.ignoreCount();
314 m_debugger
->conditionalBreakpoint(id
, conditionInput
, ignoreCount
);
318 void BreakpointTable::initListAndIcons()
320 m_list
.addColumn(i18n("Location"), 220);
321 m_list
.addColumn(i18n("Address"), 65);
322 m_list
.addColumn(i18n("Hits"), 30);
323 m_list
.addColumn(i18n("Ignore"), 30);
324 m_list
.addColumn(i18n("Condition"), 200);
326 m_list
.setMinimumSize(200, 100);
328 m_list
.setSorting(-1);
331 QPixmap brkena
= UserIcon("brkena.xpm");
332 QPixmap brkdis
= UserIcon("brkdis.xpm");
333 QPixmap watchena
= UserIcon("watchena.xpm");
334 QPixmap watchdis
= UserIcon("watchdis.xpm");
335 QPixmap brktmp
= UserIcon("brktmp.xpm");
336 QPixmap brkcond
= UserIcon("brkcond.xpm");
337 QPixmap brkorph
= UserIcon("brkorph.xpm");
340 * There are 32 different pixmaps: The basic enabled or disabled
341 * breakpoint, plus an optional overlaid brktmp icon plus an optional
342 * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
343 * the same sequence for watchpoints.
346 QPixmap
canvas(16,16);
348 for (int i
= 0; i
< 32; i
++) {
352 p
.fillRect(0,0, canvas
.width(),canvas
.height(), Qt::cyan
);
355 p
.drawPixmap(1,1, (i
& 8) ? watchena
: brkena
);
357 p
.drawPixmap(1,1, (i
& 8) ? watchdis
: brkdis
);
361 p
.drawPixmap(1,1, brktmp
);
363 // conditional overlay
365 p
.drawPixmap(1,1, brkcond
);
369 p
.drawPixmap(1,1, brkorph
);
372 canvas
.setMask(canvas
.createHeuristicMask());
377 void BreakpointItem::display()
379 BreakpointTable
* lb
= static_cast<BreakpointTable
*>(listView()->parent());
381 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
382 int code
= enabled() ? 1 : 0;
385 if (!condition
.isEmpty() || ignoreCount
> 0)
387 if (type
== watchpoint
)
391 setPixmap(0, lb
->m_icons
[code
]);
393 // more breakpoint info
394 if (!location
.isEmpty()) {
395 setText(0, location
);
396 } else if (!Breakpoint::text
.isEmpty()) {
397 setText(0, Breakpoint::text
);
398 } else if (!fileName
.isEmpty()) {
399 // use only the file name portion
400 QString file
= fileName
;
401 int slash
= file
.findRev('/');
403 file
= file
.mid(slash
+1);
405 // correct zero-based line-numbers
406 setText(0, file
+ ":" + QString::number(lineNo
+1));
408 setText(0, "*" + address
.asString());
412 setText(++c
, address
.asString());
415 setText(++c
, QString());
417 tmp
.setNum(hitCount
);
420 if (ignoreCount
== 0) {
421 setText(++c
, QString());
423 tmp
.setNum(ignoreCount
);
426 if (condition
.isEmpty()) {
427 setText(++c
, QString());
429 setText(++c
, condition
);
434 ConditionalDlg::ConditionalDlg(QWidget
* parent
) :
435 QDialog(parent
, "conditional", true),
436 m_conditionLabel(this, "condLabel"),
437 m_condition(this, "condition"),
438 m_ignoreLabel(this, "ignoreLabel"),
439 m_ignoreCount(this, "ignoreCount"),
440 m_buttonOK(this, "ok"),
441 m_buttonCancel(this, "cancel"),
446 QString title
= kapp
->caption();
447 title
+= i18n(": Conditional breakpoint");
450 m_conditionLabel
.setText(i18n("&Condition:"));
451 m_conditionLabel
.setMinimumSize(m_conditionLabel
.sizeHint());
452 m_ignoreLabel
.setText(i18n("Ignore &next hits:"));
453 m_ignoreLabel
.setMinimumSize(m_ignoreLabel
.sizeHint());
455 m_condition
.setMinimumSize(150, 24);
456 m_condition
.setMaxLength(10000);
457 m_condition
.setFrame(true);
458 m_ignoreCount
.setMinimumSize(150, 24);
459 m_ignoreCount
.setMaxLength(10000);
460 m_ignoreCount
.setFrame(true);
462 m_conditionLabel
.setBuddy(&m_condition
);
463 m_ignoreLabel
.setBuddy(&m_ignoreCount
);
465 m_buttonOK
.setMinimumSize(100, 30);
466 connect(&m_buttonOK
, SIGNAL(clicked()), SLOT(accept()));
467 m_buttonOK
.setText(i18n("OK"));
468 m_buttonOK
.setDefault(true);
470 m_buttonCancel
.setMinimumSize(100, 30);
471 connect(&m_buttonCancel
, SIGNAL(clicked()), SLOT(reject()));
472 m_buttonCancel
.setText(i18n("Cancel"));
474 m_layout
.addLayout(&m_inputs
);
475 m_inputs
.addWidget(&m_conditionLabel
, 0, 0);
476 m_inputs
.addWidget(&m_condition
, 0, 1);
477 m_inputs
.addWidget(&m_ignoreLabel
, 1, 0);
478 m_inputs
.addWidget(&m_ignoreCount
, 1, 1);
479 m_inputs
.setColStretch(1, 10);
480 m_layout
.addLayout(&m_buttons
);
481 m_layout
.addStretch(10);
482 m_buttons
.addStretch(10);
483 m_buttons
.addWidget(&m_buttonOK
);
484 m_buttons
.addSpacing(40);
485 m_buttons
.addWidget(&m_buttonCancel
);
486 m_buttons
.addStretch(10);
490 m_condition
.setFocus();
494 ConditionalDlg::~ConditionalDlg()
498 uint
ConditionalDlg::ignoreCount()
501 QString input
= m_ignoreCount
.text();
502 uint result
= input
.toUInt(&ok
);
503 return ok
? result
: 0;
506 void ConditionalDlg::setIgnoreCount(uint count
)
509 // set empty if ignore count is zero
513 m_ignoreCount
.setText(text
);