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.
8 #include <klocale.h> /* i18n */
9 #include <kiconloader.h>
10 #include <ksimpleconfig.h>
16 #include <Q3GridLayout>
17 #include <Q3VBoxLayout>
18 #include <Q3HBoxLayout>
20 #include <QMouseEvent>
23 #include "dbgdriver.h"
29 class BreakpointItem
: public QTreeWidgetItem
, public Breakpoint
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
) :
44 connect(m_ui
.bpEdit
, SIGNAL(returnPressed()),
45 this, SLOT(on_btAddBP_clicked()));
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
)));
73 for (KDebugger::BrkptROIterator bp
= m_debugger
->breakpointsBegin(); bp
!= m_debugger
->breakpointsEnd(); ++bp
)
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 */
84 // not in the list; add it
85 new BreakpointItem(m_ui
.bpList
,*bp
);
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
),
103 void BreakpointItem::updateFrom(const Breakpoint
& bp
)
105 Breakpoint::operator=(bp
); /* assign new values */
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
;
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
;
133 m_debugger
->setBreakpoint(bp
, false);
137 void BreakpointTable::on_btRemove_clicked()
139 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_ui
.bpList
->currentItem());
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());
151 m_debugger
->enableDisableBreakpoint(bp
->id
);
155 void BreakpointTable::on_btViewCode_clicked()
157 BreakpointItem
* bp
= static_cast<BreakpointItem
*>(m_ui
.bpList
->currentItem());
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);
178 m_ui
.btEnaDis
->setText(i18n("&Disable"));
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
196 static_cast<BreakpointItem
*>(m_ui
.bpList
->itemAt(mev
->pos()));
199 m_debugger
->enableDisableBreakpoint(bp
->id
);
204 return QWidget::eventFilter(ob
, ev
);
207 class ConditionalDlg
: public QDialog
210 ConditionalDlg(QWidget
* parent
);
213 void setCondition(const QString
& text
) { m_condition
.setText(text
); }
214 QString
condition() { return m_condition
.text(); }
215 void setIgnoreCount(uint count
);
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());
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
244 ConditionalDlg
dlg(this);
245 dlg
.setCondition(bp
->condition
);
246 dlg
.setIgnoreCount(bp
->ignoreCount
);
248 if (dlg
.exec() != QDialog::Accepted
)
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);
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.
281 QPixmap
canvas(16,16);
283 for (int i
= 0; i
< 32; i
++) {
287 p
.fillRect(0,0, canvas
.width(),canvas
.height(), Qt::cyan
);
290 p
.drawPixmap(1,1, (i
& 8) ? watchena
: brkena
);
292 p
.drawPixmap(1,1, (i
& 8) ? watchdis
: brkdis
);
296 p
.drawPixmap(1,1, brktmp
);
298 // conditional overlay
300 p
.drawPixmap(1,1, brkcond
);
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;
320 if (!condition
.isEmpty() || ignoreCount
> 0)
322 if (Breakpoint::type
== watchpoint
)
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('/');
338 file
= file
.mid(slash
+1);
340 // correct zero-based line-numbers
341 setText(0, file
+ ":" + QString::number(lineNo
+1));
343 setText(0, "*" + address
.asString());
347 setText(++c
, address
.asString());
350 setText(++c
, QString());
352 tmp
.setNum(hitCount
);
355 if (ignoreCount
== 0) {
356 setText(++c
, QString());
358 tmp
.setNum(ignoreCount
);
361 if (condition
.isEmpty()) {
362 setText(++c
, QString());
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"),
381 QString title
= KGlobal::caption();
382 title
+= i18n(": Conditional breakpoint");
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);
425 m_condition
.setFocus();
429 ConditionalDlg::~ConditionalDlg()
433 uint
ConditionalDlg::ignoreCount()
436 QString input
= m_ignoreCount
.text();
437 uint result
= input
.toUInt(&ok
);
438 return ok
? result
: 0;
441 void ConditionalDlg::setIgnoreCount(uint count
)
444 // set empty if ignore count is zero
448 m_ignoreCount
.setText(text
);