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 */
37 BreakpointTable::BreakpointTable(QWidget
* parent
, const char* name
) :
38 QWidget(parent
, name
),
40 m_bpEdit(this, "bpedit"),
41 m_list(this, "bptable"),
43 m_btRemove(this, "remove"),
44 m_btEnaDis(this, "enadis"),
45 m_btViewCode(this, "view"),
46 m_btConditional(this, "conditional"),
51 m_bpEdit
.setMinimumSize(m_bpEdit
.sizeHint());
52 connect(&m_bpEdit
, SIGNAL(returnPressed()), this, SLOT(addBP()));
55 connect(&m_list
, SIGNAL(currentChanged(QListViewItem
*)), SLOT(updateUI()));
56 // double click on item is same as View code
57 connect(&m_list
, SIGNAL(doubleClicked(QListViewItem
*)), this, SLOT(viewBP()));
59 // need mouse button events
60 m_list
.viewport()->installEventFilter(this);
62 m_btAdd
.setText(i18n("&Add"));
63 m_btAdd
.setMinimumSize(m_btAdd
.sizeHint());
64 connect(&m_btAdd
, SIGNAL(clicked()), this, SLOT(addBP()));
66 m_btRemove
.setText(i18n("&Remove"));
67 m_btRemove
.setMinimumSize(m_btRemove
.sizeHint());
68 connect(&m_btRemove
, SIGNAL(clicked()), this, SLOT(removeBP()));
70 // the Enable/Disable button changes its label
71 m_btEnaDis
.setText(i18n("&Disable"));
72 // make a dummy button to get the size of the alternate label
74 QSize size
= m_btEnaDis
.sizeHint();
75 QPushButton
dummy(this);
76 dummy
.setText(i18n("&Enable"));
77 QSize sizeAlt
= dummy
.sizeHint();
78 if (sizeAlt
.width() > size
.width())
79 size
.setWidth(sizeAlt
.width());
80 if (sizeAlt
.height() > size
.height())
81 size
.setHeight(sizeAlt
.height());
82 m_btEnaDis
.setMinimumSize(size
);
84 connect(&m_btEnaDis
, SIGNAL(clicked()), this, SLOT(enadisBP()));
86 m_btViewCode
.setText(i18n("&View Code"));
87 m_btViewCode
.setMinimumSize(m_btViewCode
.sizeHint());
88 connect(&m_btViewCode
, SIGNAL(clicked()), this, SLOT(viewBP()));
90 m_btConditional
.setText(i18n("&Conditional..."));
91 m_btConditional
.setMinimumSize(m_btConditional
.sizeHint());
92 connect(&m_btConditional
, SIGNAL(clicked()), this, SLOT(conditionalBP()));
94 m_layout
.addLayout(&m_listandedit
, 10);
95 m_layout
.addLayout(&m_buttons
);
96 m_listandedit
.addWidget(&m_bpEdit
);
97 m_listandedit
.addWidget(&m_list
, 10);
98 m_buttons
.addWidget(&m_btAdd
);
99 m_buttons
.addWidget(&m_btRemove
);
100 m_buttons
.addWidget(&m_btEnaDis
);
101 m_buttons
.addWidget(&m_btViewCode
);
102 m_buttons
.addWidget(&m_btConditional
);
103 m_buttons
.addStretch(10);
112 BreakpointTable::~BreakpointTable()
116 void BreakpointTable::updateBreakList()
118 QList
<BreakpointItem
> deletedItems
;
120 for (QListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
121 deletedItems
.append(static_cast<BreakpointItem
*>(it
));
125 for (int i
= m_debugger
->numBreakpoints()-1; i
>= 0; i
--) {
126 const Breakpoint
* bp
= m_debugger
->breakpoint(i
);
128 for (BreakpointItem
* oldbp
= deletedItems
.first(); oldbp
!= 0;
129 oldbp
= deletedItems
.next())
131 if (oldbp
->id
== bp
->id
) {
132 oldbp
->updateFrom(*bp
);
133 deletedItems
.take(); /* don't delete */
137 // not in the list; add it
138 new BreakpointItem(&m_list
, *bp
);
142 // delete all untouched breakpoints
143 deletedItems
.setAutoDelete(true);
146 BreakpointItem::BreakpointItem(QListView
* list
, const Breakpoint
& bp
) :
153 void BreakpointItem::updateFrom(const Breakpoint
& bp
)
155 Breakpoint::operator=(bp
); /* assign new values */
159 void BreakpointTable::addBP()
161 // set a breakpoint at the specified text
162 QString bpText
= m_bpEdit
.text();
163 bpText
= bpText
.stripWhiteSpace();
164 if (m_debugger
->isReady()) {
165 m_debugger
->driver()->executeCmd(DCbreaktext
, bpText
);
166 // clear text if successfully set
167 m_bpEdit
.setText("");
171 void BreakpointTable::removeBP()
173 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
177 m_debugger
->driver()->executeCmd(DCdelete
, bp
->id
);
180 void BreakpointTable::enadisBP()
182 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
186 DbgCommand cmd
= bp
->enabled
? DCdisable
: DCenable
;
187 m_debugger
->driver()->executeCmd(cmd
, bp
->id
);
190 void BreakpointTable::viewBP()
192 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
196 emit
activateFileLine(bp
->fileName
, bp
->lineNo
, bp
->address
);
199 void BreakpointTable::updateUI()
201 bool enableChkpt
= m_debugger
->canChangeBreakpoints();
202 m_btAdd
.setEnabled(enableChkpt
);
204 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
205 m_btViewCode
.setEnabled(bp
!= 0);
211 m_btEnaDis
.setText(i18n("&Disable"));
213 m_btEnaDis
.setText(i18n("&Enable"));
216 m_btRemove
.setEnabled(enableChkpt
);
217 m_btEnaDis
.setEnabled(enableChkpt
);
218 m_btConditional
.setEnabled(enableChkpt
);
222 # define MOUSEPRESS Event_MouseButtonPress
224 # define MOUSEPRESS QEvent::MouseButtonPress
227 bool BreakpointTable::eventFilter(QObject
* ob
, QEvent
* ev
)
229 if (ev
->type() == MOUSEPRESS
)
231 QMouseEvent
* mev
= static_cast<QMouseEvent
*>(ev
);
232 if (mev
->button() == MidButton
) {
233 // enable or disable the clicked-on item
235 static_cast<BreakpointItem
*>(m_list
.itemAt(mev
->pos()));
236 if (bp
!= 0 && m_debugger
->canChangeBreakpoints())
238 DbgCommand cmd
= bp
->enabled
? DCdisable
: DCenable
;
239 m_debugger
->driver()->executeCmd(cmd
, bp
->id
);
244 return QWidget::eventFilter(ob
, ev
);
247 class ConditionalDlg
: public QDialog
250 ConditionalDlg(QWidget
* parent
);
253 void setCondition(const char* text
) { m_condition
.setText(text
); }
254 const char* condition() { return m_condition
.text(); }
255 void setIgnoreCount(uint count
);
259 QLabel m_conditionLabel
;
260 QLineEdit m_condition
;
261 QLabel m_ignoreLabel
;
262 QLineEdit m_ignoreCount
;
263 QPushButton m_buttonOK
;
264 QPushButton m_buttonCancel
;
265 QVBoxLayout m_layout
;
266 QGridLayout m_inputs
;
267 QHBoxLayout m_buttons
;
270 void BreakpointTable::conditionalBP()
272 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_list
.currentItem());
277 * Important: we must not keep a pointer to the Breakpoint around,
278 * since it may vanish while the modal dialog is open through other
279 * user interactions (like clicking at the breakpoint in the source
284 ConditionalDlg
dlg(this);
285 dlg
.setCondition(bp
->condition
);
286 dlg
.setIgnoreCount(bp
->ignoreCount
);
288 if (dlg
.exec() != QDialog::Accepted
)
291 QString conditionInput
= dlg
.condition();
292 int ignoreCount
= dlg
.ignoreCount();
293 updateBreakpointCondition(id
, conditionInput
, ignoreCount
);
296 void BreakpointTable::updateBreakpointCondition(int id
,
297 const QString
& condition
,
300 BreakpointItem
* bp
= itemByBreakId(id
);
302 return; /* breakpoint no longer exists */
304 bool changed
= false;
306 if (bp
->condition
!= condition
) {
308 m_debugger
->driver()->executeCmd(DCcondition
, condition
, bp
->id
);
309 bp
->condition
= condition
;
312 if (bp
->ignoreCount
!= ignoreCount
) {
313 // change ignore count
314 m_debugger
->driver()->executeCmd(DCignore
, bp
->id
, ignoreCount
);
319 m_debugger
->driver()->queueCmd(DCinfobreak
, DebuggerDriver::QMoverride
);
324 BreakpointItem
* BreakpointTable::itemByBreakId(int id
)
326 for (QListViewItem
* it
= m_list
.firstChild(); it
!= 0; it
= it
->nextSibling()) {
327 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(it
);
336 void BreakpointTable::initListAndIcons()
338 m_list
.addColumn(i18n("Location"), 220);
339 m_list
.addColumn(i18n("Address"), 65);
340 m_list
.addColumn(i18n("Hits"), 30);
341 m_list
.addColumn(i18n("Ignore"), 30);
342 m_list
.addColumn(i18n("Condition"), 200);
344 m_list
.setMinimumSize(200, 100);
345 setFocusPolicy(QWidget::StrongFocus
);
347 m_list
.setSorting(-1);
351 KIconLoader
* loader
= kapp
->getIconLoader();
352 QPixmap brkena
= loader
->loadIcon("brkena.xpm");
353 QPixmap brkdis
= loader
->loadIcon("brkdis.xpm");
354 QPixmap brktmp
= loader
->loadIcon("brktmp.xpm");
355 QPixmap brkcond
= loader
->loadIcon("brkcond.xpm");
357 QPixmap brkena
= BarIcon("brkena.xpm");
358 QPixmap brkdis
= BarIcon("brkdis.xpm");
359 QPixmap brktmp
= BarIcon("brktmp.xpm");
360 QPixmap brkcond
= BarIcon("brkcond.xpm");
363 * There are 8 different pixmaps: The basic enabled or disabled
364 * breakpoint, plus an optional overlaid brktmp icon plus an optional
365 * overlaid brkcond icon.
368 QPixmap
canvas(16,16);
370 for (int i
= 0; i
< 8; i
++) {
374 p
.fillRect(0,0, canvas
.width(),canvas
.height(), cyan
);
377 p
.drawPixmap(1,1, brkena
);
379 p
.drawPixmap(1,1, brkdis
);
383 p
.drawPixmap(1,1, brktmp
);
385 // conditional overlay
387 p
.drawPixmap(1,1, brkcond
);
390 canvas
.setMask(canvas
.createHeuristicMask());
395 void BreakpointItem::display()
397 BreakpointTable
* lb
= static_cast<BreakpointTable
*>(listView()->parent());
399 /* breakpoint icon code; keep order the same as in BreakpointTable::initListAndIcons */
400 int code
= enabled
? 1 : 0;
403 if (!condition
.isEmpty() || ignoreCount
> 0)
405 setPixmap(0, lb
->m_icons
[code
]);
407 // more breakpoint info
408 setText(0, location
);
410 setText(++c
, address
.asString());
413 setText(++c
, QString());
415 tmp
.setNum(hitCount
);
418 if (ignoreCount
== 0) {
419 setText(++c
, QString());
421 tmp
.setNum(ignoreCount
);
424 if (condition
.isEmpty()) {
425 setText(++c
, QString());
427 setText(++c
, condition
);
432 ConditionalDlg::ConditionalDlg(QWidget
* parent
) :
433 QDialog(parent
, "conditional", true),
434 m_conditionLabel(this, "condLabel"),
435 m_condition(this, "condition"),
436 m_ignoreLabel(this, "ignoreLabel"),
437 m_ignoreCount(this, "ignoreCount"),
438 m_buttonOK(this, "ok"),
439 m_buttonCancel(this, "cancel"),
444 QString title
= kapp
->getCaption();
445 title
+= i18n(": Conditional breakpoint");
448 m_conditionLabel
.setText(i18n("&Condition:"));
449 m_conditionLabel
.setMinimumSize(m_conditionLabel
.sizeHint());
450 m_ignoreLabel
.setText(i18n("Ignore &next hits:"));
451 m_ignoreLabel
.setMinimumSize(m_ignoreLabel
.sizeHint());
453 m_condition
.setMinimumSize(150, 24);
454 m_condition
.setMaxLength(10000);
455 m_condition
.setFrame(true);
456 m_ignoreCount
.setMinimumSize(150, 24);
457 m_ignoreCount
.setMaxLength(10000);
458 m_ignoreCount
.setFrame(true);
460 m_conditionLabel
.setBuddy(&m_condition
);
461 m_ignoreLabel
.setBuddy(&m_ignoreCount
);
463 m_buttonOK
.setMinimumSize(100, 30);
464 connect(&m_buttonOK
, SIGNAL(clicked()), SLOT(accept()));
465 m_buttonOK
.setText(i18n("OK"));
466 m_buttonOK
.setDefault(true);
468 m_buttonCancel
.setMinimumSize(100, 30);
469 connect(&m_buttonCancel
, SIGNAL(clicked()), SLOT(reject()));
470 m_buttonCancel
.setText(i18n("Cancel"));
472 m_layout
.addLayout(&m_inputs
);
473 m_inputs
.addWidget(&m_conditionLabel
, 0, 0);
474 m_inputs
.addWidget(&m_condition
, 0, 1);
475 m_inputs
.addWidget(&m_ignoreLabel
, 1, 0);
476 m_inputs
.addWidget(&m_ignoreCount
, 1, 1);
477 m_inputs
.setColStretch(1, 10);
478 m_layout
.addLayout(&m_buttons
);
479 m_layout
.addStretch(10);
480 m_buttons
.addStretch(10);
481 m_buttons
.addWidget(&m_buttonOK
);
482 m_buttons
.addSpacing(40);
483 m_buttons
.addWidget(&m_buttonCancel
);
484 m_buttons
.addStretch(10);
488 m_condition
.setFocus();
492 ConditionalDlg::~ConditionalDlg()
496 uint
ConditionalDlg::ignoreCount()
499 QString input
= m_ignoreCount
.text();
500 uint result
= input
.toUInt(&ok
);
501 return ok
? result
: 0;
504 void ConditionalDlg::setIgnoreCount(uint count
)
507 // set empty if ignore count is zero
511 m_ignoreCount
.setText(text
);