3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <kapp.h> /* i18n */
7 #include <klocale.h> /* i18n */
8 #include <kiconloader.h>
9 #include <ksimpleconfig.h>
17 #include "dbgdriver.h"
25 class BreakpointItem
: public QListViewItem
, public Breakpoint
28 BreakpointItem(QListView
* 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
, const char* name
) :
36 QWidget(parent
, name
),
38 m_bpEdit(this, "bpedit"),
39 m_list(this, "bptable"),
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"),
50 m_bpEdit
.setMinimumSize(m_bpEdit
.sizeHint());
51 connect(&m_bpEdit
, SIGNAL(returnPressed()), this, SLOT(addBP()));
54 connect(&m_list
, SIGNAL(currentChanged(QListViewItem
*)), SLOT(updateUI()));
55 // double click on item is same as View code
56 connect(&m_list
, SIGNAL(doubleClicked(QListViewItem
*)), this, SLOT(viewBP()));
58 // need mouse button events
59 m_list
.viewport()->installEventFilter(this);
61 m_btAddBP
.setText(i18n("Add &Breakpoint"));
62 m_btAddBP
.setMinimumSize(m_btAddBP
.sizeHint());
63 connect(&m_btAddBP
, SIGNAL(clicked()), this, SLOT(addBP()));
65 m_btAddWP
.setText(i18n("Add &Watchpoint"));
66 m_btAddWP
.setMinimumSize(m_btAddWP
.sizeHint());
67 connect(&m_btAddWP
, SIGNAL(clicked()), this, SLOT(addWP()));
69 m_btRemove
.setText(i18n("&Remove"));
70 m_btRemove
.setMinimumSize(m_btRemove
.sizeHint());
71 connect(&m_btRemove
, SIGNAL(clicked()), this, SLOT(removeBP()));
73 // the Enable/Disable button changes its label
74 m_btEnaDis
.setText(i18n("&Disable"));
75 // make a dummy button to get the size of the alternate label
77 QSize size
= m_btEnaDis
.sizeHint();
78 QPushButton
dummy(this);
79 dummy
.setText(i18n("&Enable"));
80 QSize sizeAlt
= dummy
.sizeHint();
81 if (sizeAlt
.width() > size
.width())
82 size
.setWidth(sizeAlt
.width());
83 if (sizeAlt
.height() > size
.height())
84 size
.setHeight(sizeAlt
.height());
85 m_btEnaDis
.setMinimumSize(size
);
87 connect(&m_btEnaDis
, SIGNAL(clicked()), this, SLOT(enadisBP()));
89 m_btViewCode
.setText(i18n("&View Code"));
90 m_btViewCode
.setMinimumSize(m_btViewCode
.sizeHint());
91 connect(&m_btViewCode
, SIGNAL(clicked()), this, SLOT(viewBP()));
93 m_btConditional
.setText(i18n("&Conditional..."));
94 m_btConditional
.setMinimumSize(m_btConditional
.sizeHint());
95 connect(&m_btConditional
, SIGNAL(clicked()), this, SLOT(conditionalBP()));
97 m_layout
.addLayout(&m_listandedit
, 10);
98 m_layout
.addLayout(&m_buttons
);
99 m_listandedit
.addWidget(&m_bpEdit
);
100 m_listandedit
.addWidget(&m_list
, 10);
101 m_buttons
.addWidget(&m_btAddBP
);
102 m_buttons
.addWidget(&m_btAddWP
);
103 m_buttons
.addWidget(&m_btRemove
);
104 m_buttons
.addWidget(&m_btEnaDis
);
105 m_buttons
.addWidget(&m_btViewCode
);
106 m_buttons
.addWidget(&m_btConditional
);
107 m_buttons
.addStretch(10);
116 BreakpointTable::~BreakpointTable()
120 void BreakpointTable::updateBreakList()
122 QList
<BreakpointItem
> deletedItems
;
124 for (QListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
125 deletedItems
.append(static_cast<BreakpointItem
*>(it
));
129 for (int i
= m_debugger
->numBreakpoints()-1; i
>= 0; i
--) {
130 const Breakpoint
* bp
= m_debugger
->breakpoint(i
);
132 for (BreakpointItem
* oldbp
= deletedItems
.first(); oldbp
!= 0;
133 oldbp
= deletedItems
.next())
135 if (oldbp
->id
== bp
->id
) {
136 oldbp
->updateFrom(*bp
);
137 deletedItems
.take(); /* don't delete */
141 // not in the list; add it
142 new BreakpointItem(&m_list
, *bp
);
146 // delete all untouched breakpoints
147 deletedItems
.setAutoDelete(true);
150 BreakpointItem::BreakpointItem(QListView
* list
, const Breakpoint
& bp
) :
157 void BreakpointItem::updateFrom(const Breakpoint
& bp
)
159 Breakpoint::operator=(bp
); /* assign new values */
163 void BreakpointTable::addBP()
165 // set a breakpoint at the specified text
166 QString bpText
= m_bpEdit
.text();
167 bpText
= bpText
.stripWhiteSpace();
168 if (m_debugger
->isReady())
170 Breakpoint
* bp
= new Breakpoint
;
173 m_debugger
->setBreakpoint(bp
, false);
177 void BreakpointTable::addWP()
179 // set a watchpoint for the specified expression
180 QString wpExpr
= m_bpEdit
.text();
181 wpExpr
= wpExpr
.stripWhiteSpace();
182 if (m_debugger
->isReady()) {
183 Breakpoint
* bp
= new Breakpoint
;
184 bp
->type
= Breakpoint::watchpoint
;
187 m_debugger
->setBreakpoint(bp
, false);
191 void BreakpointTable::removeBP()
193 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
197 Breakpoint
* brk
= m_debugger
->breakpointById(bp
->id
);
199 m_debugger
->deleteBreakpoint(brk
);
200 // note that both brk and bp may be deleted by now
201 // (if bp was an orphaned breakpoint)
205 void BreakpointTable::enadisBP()
207 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
211 Breakpoint
* brk
= m_debugger
->breakpointById(bp
->id
);
213 m_debugger
->enableDisableBreakpoint(brk
);
217 void BreakpointTable::viewBP()
219 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
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() == MidButton
) {
255 // enable or disable the clicked-on item
257 static_cast<BreakpointItem
*>(m_list
.itemAt(mev
->pos()));
260 Breakpoint
* brk
= m_debugger
->breakpointById(bp
->id
);
262 m_debugger
->enableDisableBreakpoint(brk
);
268 return QWidget::eventFilter(ob
, ev
);
271 class ConditionalDlg
: public QDialog
274 ConditionalDlg(QWidget
* parent
);
277 void setCondition(const char* text
) { m_condition
.setText(text
); }
278 const char* condition() { return m_condition
.text(); }
279 void setIgnoreCount(uint count
);
283 QLabel m_conditionLabel
;
284 QLineEdit m_condition
;
285 QLabel m_ignoreLabel
;
286 QLineEdit m_ignoreCount
;
287 QPushButton m_buttonOK
;
288 QPushButton m_buttonCancel
;
289 QVBoxLayout m_layout
;
290 QGridLayout m_inputs
;
291 QHBoxLayout m_buttons
;
294 void BreakpointTable::conditionalBP()
296 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
301 * Important: we must not keep a pointer to the Breakpoint around,
302 * since it may vanish while the modal dialog is open through other
303 * user interactions (like clicking at the breakpoint in the source
308 ConditionalDlg
dlg(this);
309 dlg
.setCondition(bp
->condition
);
310 dlg
.setIgnoreCount(bp
->ignoreCount
);
312 if (dlg
.exec() != QDialog::Accepted
)
315 QString conditionInput
= dlg
.condition();
316 int ignoreCount
= dlg
.ignoreCount();
317 updateBreakpointCondition(id
, conditionInput
, ignoreCount
);
320 void BreakpointTable::updateBreakpointCondition(int id
,
321 const QString
& condition
,
324 Breakpoint
* brk
= m_debugger
->breakpointById(id
);
326 m_debugger
->conditionalBreakpoint(brk
, condition
, ignoreCount
);
331 void BreakpointTable::initListAndIcons()
333 m_list
.addColumn(i18n("Location"), 220);
334 m_list
.addColumn(i18n("Address"), 65);
335 m_list
.addColumn(i18n("Hits"), 30);
336 m_list
.addColumn(i18n("Ignore"), 30);
337 m_list
.addColumn(i18n("Condition"), 200);
339 m_list
.setMinimumSize(200, 100);
341 m_list
.setSorting(-1);
344 QPixmap brkena
= UserIcon("brkena.xpm");
345 QPixmap brkdis
= UserIcon("brkdis.xpm");
346 QPixmap watchena
= UserIcon("watchena.xpm");
347 QPixmap watchdis
= UserIcon("watchdis.xpm");
348 QPixmap brktmp
= UserIcon("brktmp.xpm");
349 QPixmap brkcond
= UserIcon("brkcond.xpm");
350 QPixmap brkorph
= UserIcon("brkorph.xpm");
353 * There are 32 different pixmaps: The basic enabled or disabled
354 * breakpoint, plus an optional overlaid brktmp icon plus an optional
355 * overlaid brkcond icon, plus an optional overlaid brkorph icon. Then
356 * the same sequence for watchpoints.
359 QPixmap
canvas(16,16);
361 for (int i
= 0; i
< 32; i
++) {
365 p
.fillRect(0,0, canvas
.width(),canvas
.height(), cyan
);
368 p
.drawPixmap(1,1, (i
& 8) ? watchena
: brkena
);
370 p
.drawPixmap(1,1, (i
& 8) ? watchdis
: brkdis
);
374 p
.drawPixmap(1,1, brktmp
);
376 // conditional overlay
378 p
.drawPixmap(1,1, brkcond
);
382 p
.drawPixmap(1,1, brkorph
);
385 canvas
.setMask(canvas
.createHeuristicMask());
390 void BreakpointItem::display()
392 BreakpointTable
* lb
= static_cast<BreakpointTable
*>(listView()->parent());
394 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
395 int code
= enabled() ? 1 : 0;
398 if (!condition
.isEmpty() || ignoreCount
> 0)
400 if (type
== watchpoint
)
404 setPixmap(0, lb
->m_icons
[code
]);
406 // more breakpoint info
407 if (!location
.isEmpty()) {
408 setText(0, location
);
409 } else if (!Breakpoint::text
.isEmpty()) {
410 setText(0, Breakpoint::text
);
411 } else if (!fileName
.isEmpty()) {
412 // use only the file name portion
413 QString file
= fileName
;
414 int slash
= file
.findRev('/');
416 file
= file
.mid(slash
+1);
418 // correct zero-based line-numbers
419 setText(0, file
+ ":" + QString::number(lineNo
+1));
421 setText(0, "*" + address
.asString());
425 setText(++c
, address
.asString());
428 setText(++c
, QString());
430 tmp
.setNum(hitCount
);
433 if (ignoreCount
== 0) {
434 setText(++c
, QString());
436 tmp
.setNum(ignoreCount
);
439 if (condition
.isEmpty()) {
440 setText(++c
, QString());
442 setText(++c
, condition
);
447 ConditionalDlg::ConditionalDlg(QWidget
* parent
) :
448 QDialog(parent
, "conditional", true),
449 m_conditionLabel(this, "condLabel"),
450 m_condition(this, "condition"),
451 m_ignoreLabel(this, "ignoreLabel"),
452 m_ignoreCount(this, "ignoreCount"),
453 m_buttonOK(this, "ok"),
454 m_buttonCancel(this, "cancel"),
459 QString title
= kapp
->caption();
460 title
+= i18n(": Conditional breakpoint");
463 m_conditionLabel
.setText(i18n("&Condition:"));
464 m_conditionLabel
.setMinimumSize(m_conditionLabel
.sizeHint());
465 m_ignoreLabel
.setText(i18n("Ignore &next hits:"));
466 m_ignoreLabel
.setMinimumSize(m_ignoreLabel
.sizeHint());
468 m_condition
.setMinimumSize(150, 24);
469 m_condition
.setMaxLength(10000);
470 m_condition
.setFrame(true);
471 m_ignoreCount
.setMinimumSize(150, 24);
472 m_ignoreCount
.setMaxLength(10000);
473 m_ignoreCount
.setFrame(true);
475 m_conditionLabel
.setBuddy(&m_condition
);
476 m_ignoreLabel
.setBuddy(&m_ignoreCount
);
478 m_buttonOK
.setMinimumSize(100, 30);
479 connect(&m_buttonOK
, SIGNAL(clicked()), SLOT(accept()));
480 m_buttonOK
.setText(i18n("OK"));
481 m_buttonOK
.setDefault(true);
483 m_buttonCancel
.setMinimumSize(100, 30);
484 connect(&m_buttonCancel
, SIGNAL(clicked()), SLOT(reject()));
485 m_buttonCancel
.setText(i18n("Cancel"));
487 m_layout
.addLayout(&m_inputs
);
488 m_inputs
.addWidget(&m_conditionLabel
, 0, 0);
489 m_inputs
.addWidget(&m_condition
, 0, 1);
490 m_inputs
.addWidget(&m_ignoreLabel
, 1, 0);
491 m_inputs
.addWidget(&m_ignoreCount
, 1, 1);
492 m_inputs
.setColStretch(1, 10);
493 m_layout
.addLayout(&m_buttons
);
494 m_layout
.addStretch(10);
495 m_buttons
.addStretch(10);
496 m_buttons
.addWidget(&m_buttonOK
);
497 m_buttons
.addSpacing(40);
498 m_buttons
.addWidget(&m_buttonCancel
);
499 m_buttons
.addStretch(10);
503 m_condition
.setFocus();
507 ConditionalDlg::~ConditionalDlg()
511 uint
ConditionalDlg::ignoreCount()
514 QString input
= m_ignoreCount
.text();
515 uint result
= input
.toUInt(&ok
);
516 return ok
? result
: 0;
519 void ConditionalDlg::setIgnoreCount(uint count
)
522 // set empty if ignore count is zero
526 m_ignoreCount
.setText(text
);