3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <kapp.h> /* i18n */
8 #include <klocale.h> /* i18n */
10 #include <kiconloader.h>
11 #include <ksimpleconfig.h>
19 #include "dbgdriver.h"
28 class BreakpointItem
: public QListViewItem
, public Breakpoint
31 BreakpointItem(QListView
* list
, const Breakpoint
& bp
);
32 void updateFrom(const Breakpoint
& bp
);
33 void display(); /* sets icon and visible texts */
34 bool enabled() const { return Breakpoint::enabled
; }
38 BreakpointTable::BreakpointTable(QWidget
* parent
, const char* name
) :
39 QWidget(parent
, name
),
41 m_bpEdit(this, "bpedit"),
42 m_list(this, "bptable"),
43 m_btAddBP(this, "addbp"),
44 m_btAddWP(this, "addwp"),
45 m_btRemove(this, "remove"),
46 m_btEnaDis(this, "enadis"),
47 m_btViewCode(this, "view"),
48 m_btConditional(this, "conditional"),
53 m_bpEdit
.setMinimumSize(m_bpEdit
.sizeHint());
54 connect(&m_bpEdit
, SIGNAL(returnPressed()), this, SLOT(addBP()));
57 connect(&m_list
, SIGNAL(currentChanged(QListViewItem
*)), SLOT(updateUI()));
58 // double click on item is same as View code
59 connect(&m_list
, SIGNAL(doubleClicked(QListViewItem
*)), 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);
119 BreakpointTable::~BreakpointTable()
123 void BreakpointTable::updateBreakList()
125 QList
<BreakpointItem
> deletedItems
;
127 for (QListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
128 deletedItems
.append(static_cast<BreakpointItem
*>(it
));
132 for (int i
= m_debugger
->numBreakpoints()-1; i
>= 0; i
--) {
133 const Breakpoint
* bp
= m_debugger
->breakpoint(i
);
135 for (BreakpointItem
* oldbp
= deletedItems
.first(); oldbp
!= 0;
136 oldbp
= deletedItems
.next())
138 if (oldbp
->id
== bp
->id
) {
139 oldbp
->updateFrom(*bp
);
140 deletedItems
.take(); /* don't delete */
144 // not in the list; add it
145 new BreakpointItem(&m_list
, *bp
);
149 // delete all untouched breakpoints
150 deletedItems
.setAutoDelete(true);
153 BreakpointItem::BreakpointItem(QListView
* list
, const Breakpoint
& bp
) :
160 void BreakpointItem::updateFrom(const Breakpoint
& bp
)
162 Breakpoint::operator=(bp
); /* assign new values */
166 void BreakpointTable::addBP()
168 // set a breakpoint at the specified text
169 QString bpText
= m_bpEdit
.text();
170 bpText
= bpText
.stripWhiteSpace();
171 if (m_debugger
->isReady()) {
172 m_debugger
->driver()->executeCmd(DCbreaktext
, bpText
);
173 // clear text if successfully set
174 m_bpEdit
.setText("");
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 m_debugger
->driver()->executeCmd(DCwatchpoint
, wpExpr
);
188 void BreakpointTable::removeBP()
190 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
194 m_debugger
->driver()->executeCmd(DCdelete
, bp
->id
);
197 void BreakpointTable::enadisBP()
199 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
203 DbgCommand cmd
= bp
->enabled() ? DCdisable
: DCenable
;
204 m_debugger
->driver()->executeCmd(cmd
, bp
->id
);
207 void BreakpointTable::viewBP()
209 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
213 emit
activateFileLine(bp
->fileName
, bp
->lineNo
, bp
->address
);
216 void BreakpointTable::updateUI()
218 bool enableChkpt
= m_debugger
->canChangeBreakpoints();
219 m_btAddBP
.setEnabled(enableChkpt
);
220 m_btAddWP
.setEnabled(enableChkpt
);
222 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
223 m_btViewCode
.setEnabled(bp
!= 0);
229 m_btEnaDis
.setText(i18n("&Disable"));
231 m_btEnaDis
.setText(i18n("&Enable"));
234 m_btRemove
.setEnabled(enableChkpt
);
235 m_btEnaDis
.setEnabled(enableChkpt
);
236 m_btConditional
.setEnabled(enableChkpt
);
240 # define MOUSEPRESS Event_MouseButtonPress
242 # define MOUSEPRESS QEvent::MouseButtonPress
245 bool BreakpointTable::eventFilter(QObject
* ob
, QEvent
* ev
)
247 if (ev
->type() == MOUSEPRESS
)
249 QMouseEvent
* mev
= static_cast<QMouseEvent
*>(ev
);
250 if (mev
->button() == MidButton
) {
251 // enable or disable the clicked-on item
253 static_cast<BreakpointItem
*>(m_list
.itemAt(mev
->pos()));
254 if (bp
!= 0 && m_debugger
->canChangeBreakpoints())
256 DbgCommand cmd
= bp
->enabled() ? DCdisable
: DCenable
;
257 m_debugger
->driver()->executeCmd(cmd
, bp
->id
);
262 return QWidget::eventFilter(ob
, ev
);
265 class ConditionalDlg
: public QDialog
268 ConditionalDlg(QWidget
* parent
);
271 void setCondition(const char* text
) { m_condition
.setText(text
); }
272 const char* condition() { return m_condition
.text(); }
273 void setIgnoreCount(uint count
);
277 QLabel m_conditionLabel
;
278 QLineEdit m_condition
;
279 QLabel m_ignoreLabel
;
280 QLineEdit m_ignoreCount
;
281 QPushButton m_buttonOK
;
282 QPushButton m_buttonCancel
;
283 QVBoxLayout m_layout
;
284 QGridLayout m_inputs
;
285 QHBoxLayout m_buttons
;
288 void BreakpointTable::conditionalBP()
290 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
295 * Important: we must not keep a pointer to the Breakpoint around,
296 * since it may vanish while the modal dialog is open through other
297 * user interactions (like clicking at the breakpoint in the source
302 ConditionalDlg
dlg(this);
303 dlg
.setCondition(bp
->condition
);
304 dlg
.setIgnoreCount(bp
->ignoreCount
);
306 if (dlg
.exec() != QDialog::Accepted
)
309 QString conditionInput
= dlg
.condition();
310 int ignoreCount
= dlg
.ignoreCount();
311 updateBreakpointCondition(id
, conditionInput
, ignoreCount
);
314 void BreakpointTable::updateBreakpointCondition(int id
,
315 const QString
& condition
,
318 BreakpointItem
* bp
= itemByBreakId(id
);
320 return; /* breakpoint no longer exists */
322 bool changed
= false;
324 if (bp
->condition
!= condition
) {
326 m_debugger
->driver()->executeCmd(DCcondition
, condition
, bp
->id
);
327 bp
->condition
= condition
;
330 if (bp
->ignoreCount
!= ignoreCount
) {
331 // change ignore count
332 m_debugger
->driver()->executeCmd(DCignore
, bp
->id
, ignoreCount
);
337 m_debugger
->driver()->queueCmd(DCinfobreak
, DebuggerDriver::QMoverride
);
342 BreakpointItem
* BreakpointTable::itemByBreakId(int id
)
344 for (QListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
345 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(it
);
354 void BreakpointTable::initListAndIcons()
356 m_list
.addColumn(i18n("Location"), 220);
357 m_list
.addColumn(i18n("Address"), 65);
358 m_list
.addColumn(i18n("Hits"), 30);
359 m_list
.addColumn(i18n("Ignore"), 30);
360 m_list
.addColumn(i18n("Condition"), 200);
362 m_list
.setMinimumSize(200, 100);
364 m_list
.setSorting(-1);
368 KIconLoader
* loader
= kapp
->getIconLoader();
369 QPixmap brkena
= loader
->loadIcon("brkena.xpm");
370 QPixmap brkdis
= loader
->loadIcon("brkdis.xpm");
371 QPixmap watchena
= loader
->loadIcon("watchena.xpm");
372 QPixmap watchdis
= loader
->loadIcon("watchdis.xpm");
373 QPixmap brktmp
= loader
->loadIcon("brktmp.xpm");
374 QPixmap brkcond
= loader
->loadIcon("brkcond.xpm");
376 QPixmap brkena
= BarIcon("brkena.xpm");
377 QPixmap brkdis
= BarIcon("brkdis.xpm");
378 QPixmap watchena
= BarIcon("watchena.xpm");
379 QPixmap watchdis
= BarIcon("watchdis.xpm");
380 QPixmap brktmp
= BarIcon("brktmp.xpm");
381 QPixmap brkcond
= BarIcon("brkcond.xpm");
384 * There are 16 different pixmaps: The basic enabled or disabled
385 * breakpoint, plus an optional overlaid brktmp icon plus an optional
386 * overlaid brkcond icon. Then the same sequence for watchpoints.
389 QPixmap
canvas(16,16);
391 for (int i
= 0; i
< 16; i
++) {
395 p
.fillRect(0,0, canvas
.width(),canvas
.height(), cyan
);
398 p
.drawPixmap(1,1, (i
& 8) ? watchena
: brkena
);
400 p
.drawPixmap(1,1, (i
& 8) ? watchdis
: brkdis
);
404 p
.drawPixmap(1,1, brktmp
);
406 // conditional overlay
408 p
.drawPixmap(1,1, brkcond
);
411 canvas
.setMask(canvas
.createHeuristicMask());
416 void BreakpointItem::display()
418 BreakpointTable
* lb
= static_cast<BreakpointTable
*>(listView()->parent());
420 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
421 int code
= enabled() ? 1 : 0;
424 if (!condition
.isEmpty() || ignoreCount
> 0)
426 if (type
== watchpoint
)
428 setPixmap(0, lb
->m_icons
[code
]);
430 // more breakpoint info
431 setText(0, location
);
433 setText(++c
, address
.asString());
436 setText(++c
, QString());
438 tmp
.setNum(hitCount
);
441 if (ignoreCount
== 0) {
442 setText(++c
, QString());
444 tmp
.setNum(ignoreCount
);
447 if (condition
.isEmpty()) {
448 setText(++c
, QString());
450 setText(++c
, condition
);
455 ConditionalDlg::ConditionalDlg(QWidget
* parent
) :
456 QDialog(parent
, "conditional", true),
457 m_conditionLabel(this, "condLabel"),
458 m_condition(this, "condition"),
459 m_ignoreLabel(this, "ignoreLabel"),
460 m_ignoreCount(this, "ignoreCount"),
461 m_buttonOK(this, "ok"),
462 m_buttonCancel(this, "cancel"),
467 QString title
= kapp
->getCaption();
468 title
+= i18n(": Conditional breakpoint");
471 m_conditionLabel
.setText(i18n("&Condition:"));
472 m_conditionLabel
.setMinimumSize(m_conditionLabel
.sizeHint());
473 m_ignoreLabel
.setText(i18n("Ignore &next hits:"));
474 m_ignoreLabel
.setMinimumSize(m_ignoreLabel
.sizeHint());
476 m_condition
.setMinimumSize(150, 24);
477 m_condition
.setMaxLength(10000);
478 m_condition
.setFrame(true);
479 m_ignoreCount
.setMinimumSize(150, 24);
480 m_ignoreCount
.setMaxLength(10000);
481 m_ignoreCount
.setFrame(true);
483 m_conditionLabel
.setBuddy(&m_condition
);
484 m_ignoreLabel
.setBuddy(&m_ignoreCount
);
486 m_buttonOK
.setMinimumSize(100, 30);
487 connect(&m_buttonOK
, SIGNAL(clicked()), SLOT(accept()));
488 m_buttonOK
.setText(i18n("OK"));
489 m_buttonOK
.setDefault(true);
491 m_buttonCancel
.setMinimumSize(100, 30);
492 connect(&m_buttonCancel
, SIGNAL(clicked()), SLOT(reject()));
493 m_buttonCancel
.setText(i18n("Cancel"));
495 m_layout
.addLayout(&m_inputs
);
496 m_inputs
.addWidget(&m_conditionLabel
, 0, 0);
497 m_inputs
.addWidget(&m_condition
, 0, 1);
498 m_inputs
.addWidget(&m_ignoreLabel
, 1, 0);
499 m_inputs
.addWidget(&m_ignoreCount
, 1, 1);
500 m_inputs
.setColStretch(1, 10);
501 m_layout
.addLayout(&m_buttons
);
502 m_layout
.addStretch(10);
503 m_buttons
.addStretch(10);
504 m_buttons
.addWidget(&m_buttonOK
);
505 m_buttons
.addSpacing(40);
506 m_buttons
.addWidget(&m_buttonCancel
);
507 m_buttons
.addStretch(10);
511 m_condition
.setFocus();
515 ConditionalDlg::~ConditionalDlg()
519 uint
ConditionalDlg::ignoreCount()
522 QString input
= m_ignoreCount
.text();
523 uint result
= input
.toUInt(&ok
);
524 return ok
? result
: 0;
527 void ConditionalDlg::setIgnoreCount(uint count
)
530 // set empty if ignore count is zero
534 m_ignoreCount
.setText(text
);