1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "breakwindow.h"
35 #include "breakhandler.h"
37 #include "debuggeractions.h"
38 #include "debuggercore.h"
39 #include "ui_breakpoint.h"
40 #include "ui_breakcondition.h"
42 #include <utils/pathchooser.h>
43 #include <utils/qtcassert.h>
44 #include <utils/savedaction.h>
46 #include <QtCore/QDebug>
48 #include <QtGui/QAction>
49 #include <QtGui/QIntValidator>
50 #include <QtGui/QKeyEvent>
51 #include <QtGui/QMenu>
57 ///////////////////////////////////////////////////////////////////////
59 // BreakpointDialog: Show a dialog for editing breakpoints. Shows controls
60 // for the file-and-line, function and address parameters depending on the
61 // breakpoint type. The controls not applicable to the current type
62 // (say function name for file-and-line) are disabled and cleared out.
63 // However,the values are saved and restored once the respective mode
64 // is again choosen, which is done using m_savedParameters and
65 // setters/getters taking the parts mask enumeration parameter.
67 ///////////////////////////////////////////////////////////////////////
69 class BreakpointDialog : public QDialog
73 explicit BreakpointDialog(QWidget *parent);
74 bool showDialog(BreakpointParameters *data);
76 void setParameters(const BreakpointParameters &data);
77 BreakpointParameters parameters() const;
80 void typeChanged(int index);
84 FileAndLinePart = 0x1,
88 AllParts = FileAndLinePart|FunctionPart|AddressPart|ConditionPart
91 void setPartsEnabled(unsigned partsMask);
92 void clearOtherParts(unsigned partsMask);
93 void getParts(unsigned partsMask, BreakpointParameters *data) const;
94 void setParts(unsigned partsMask, const BreakpointParameters &data);
96 void setType(BreakpointType type);
97 BreakpointType type() const;
99 Ui::BreakpointDialog m_ui;
100 BreakpointParameters m_savedParameters;
101 BreakpointType m_previousType;
104 BreakpointDialog::BreakpointDialog(QWidget *parent)
105 : QDialog(parent), m_previousType(UnknownType)
107 // Match BreakpointType (omitting unknown type).
110 types << tr("File and Line Number") << tr("Function Name") << tr("Address")
111 << tr("throw") << tr("catch") << tr("Function \"main()\"")
112 << tr("Address (Watchpoint)");
113 QTC_ASSERT(types.size() == Watchpoint, return; )
114 m_ui.comboBoxType->addItems(types);
115 m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
116 connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
117 m_ui.lineEditIgnoreCount->setValidator(
118 new QIntValidator(0, 2147483647, m_ui.lineEditIgnoreCount));
121 void BreakpointDialog::setType(BreakpointType type)
123 const int comboIndex = type - 1; // Skip UnknownType.
124 if (comboIndex != m_ui.comboBoxType->currentIndex()) {
125 m_ui.comboBoxType->setCurrentIndex(comboIndex);
126 typeChanged(comboIndex);
130 BreakpointType BreakpointDialog::type() const
132 const int type = m_ui.comboBoxType->currentIndex() + 1; // Skip unknown type.
133 return static_cast<BreakpointType>(type);
136 void BreakpointDialog::setParameters(const BreakpointParameters &data)
138 m_savedParameters = data;
140 setParts(AllParts, data);
143 BreakpointParameters BreakpointDialog::parameters() const
145 BreakpointParameters data(type());
146 getParts(AllParts, &data);
150 void BreakpointDialog::setPartsEnabled(unsigned partsMask)
152 m_ui.labelFileName->setEnabled(partsMask & FileAndLinePart);
153 m_ui.pathChooserFileName->setEnabled(partsMask & FileAndLinePart);
154 m_ui.labelLineNumber->setEnabled(partsMask & FileAndLinePart);
155 m_ui.lineEditLineNumber->setEnabled(partsMask & FileAndLinePart);
156 m_ui.labelUseFullPath->setEnabled(partsMask & FileAndLinePart);
157 m_ui.checkBoxUseFullPath->setEnabled(partsMask & FileAndLinePart);
159 m_ui.labelFunction->setEnabled(partsMask & FunctionPart);
160 m_ui.lineEditFunction->setEnabled(partsMask & FunctionPart);
162 m_ui.labelAddress->setEnabled(partsMask & AddressPart);
163 m_ui.lineEditAddress->setEnabled(partsMask & AddressPart);
165 m_ui.labelCondition->setEnabled(partsMask & ConditionPart);
166 m_ui.labelIgnoreCount->setEnabled(partsMask & ConditionPart);
167 m_ui.labelThreadSpec->setEnabled(partsMask & ConditionPart);
168 m_ui.lineEditCondition->setEnabled(partsMask & ConditionPart);
169 m_ui.lineEditIgnoreCount->setEnabled(partsMask & ConditionPart);
170 m_ui.lineEditThreadSpec->setEnabled(partsMask & ConditionPart);
173 void BreakpointDialog::clearOtherParts(unsigned partsMask)
175 partsMask = ~partsMask;
176 if (partsMask & FileAndLinePart) {
177 m_ui.pathChooserFileName->setPath(QString());
178 m_ui.lineEditLineNumber->clear();
179 m_ui.checkBoxUseFullPath->setChecked(false);
182 if (partsMask & FunctionPart)
183 m_ui.lineEditFunction->clear();
185 if (partsMask & AddressPart)
186 m_ui.lineEditAddress->clear();
188 if (partsMask & ConditionPart) {
189 m_ui.lineEditCondition->setText(QString());
190 m_ui.lineEditIgnoreCount->setText(QString());
191 m_ui.lineEditThreadSpec->setText(QString());
195 void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data) const
197 data->enabled = m_ui.checkBoxEnabled->isChecked();
198 data->tracepoint = m_ui.checkBoxTracepoint->isChecked();
200 if (partsMask & FileAndLinePart) {
201 data->lineNumber = m_ui.lineEditLineNumber->text().toInt();
202 data->useFullPath = m_ui.checkBoxUseFullPath->isChecked();
203 data->fileName = m_ui.pathChooserFileName->path();
205 if (partsMask & FunctionPart)
206 data->functionName = m_ui.lineEditFunction->text();
208 if (partsMask & AddressPart)
209 data->address = m_ui.lineEditAddress->text().toULongLong(0, 0);
211 if (partsMask & ConditionPart) {
212 data->condition = m_ui.lineEditCondition->text().toUtf8();
213 data->ignoreCount = m_ui.lineEditIgnoreCount->text().toInt();
215 BreakHandler::threadSpecFromDisplay(m_ui.lineEditThreadSpec->text());
219 void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
221 m_ui.checkBoxEnabled->setChecked(data.enabled);
222 m_ui.checkBoxUseFullPath->setChecked(data.useFullPath);
224 if (mask & FileAndLinePart) {
225 m_ui.pathChooserFileName->setPath(data.fileName);
226 m_ui.lineEditLineNumber->setText(QString::number(data.lineNumber));
227 m_ui.checkBoxTracepoint->setChecked(data.tracepoint);
230 if (mask & FunctionPart)
231 m_ui.lineEditFunction->setText(data.functionName);
233 if (mask & AddressPart) {
235 m_ui.lineEditAddress->setText(
236 QString::fromAscii("0x%1").arg(data.address, 0, 16));
238 m_ui.lineEditAddress->clear();
242 if (mask & ConditionPart) {
243 m_ui.lineEditCondition->setText(QString::fromUtf8(data.condition));
244 m_ui.lineEditIgnoreCount->setText(QString::number(data.ignoreCount));
245 m_ui.lineEditThreadSpec->
246 setText(BreakHandler::displayFromThreadSpec(data.threadSpec));
250 void BreakpointDialog::typeChanged(int)
252 BreakpointType previousType = m_previousType;
253 const BreakpointType newType = type();
254 m_previousType = newType;
255 // Save current state.
256 switch(previousType) {
259 case BreakpointByFileAndLine:
260 getParts(FileAndLinePart, &m_savedParameters);
262 case BreakpointByFunction:
263 getParts(FunctionPart, &m_savedParameters);
265 case BreakpointAtThrow:
266 case BreakpointAtCatch:
267 case BreakpointAtMain:
269 case BreakpointByAddress:
271 getParts(AddressPart, &m_savedParameters);
275 // Enable and set up new state from saved values.
279 case BreakpointByFileAndLine:
280 setParts(FileAndLinePart|ConditionPart, m_savedParameters);
281 setPartsEnabled(FileAndLinePart|ConditionPart);
282 clearOtherParts(FileAndLinePart|ConditionPart);
284 case BreakpointByFunction:
285 setParts(FunctionPart|ConditionPart, m_savedParameters);
286 setPartsEnabled(FunctionPart|ConditionPart);
287 clearOtherParts(FunctionPart|ConditionPart);
289 case BreakpointAtThrow:
290 case BreakpointAtCatch:
291 clearOtherParts(ConditionPart);
292 setPartsEnabled(ConditionPart);
294 case BreakpointAtMain:
295 m_ui.lineEditFunction->setText(QLatin1String("main")); // Just for display
299 case BreakpointByAddress:
301 setParts(AddressPart|ConditionPart, m_savedParameters);
302 setPartsEnabled(AddressPart|ConditionPart);
303 clearOtherParts(AddressPart|ConditionPart);
308 bool BreakpointDialog::showDialog(BreakpointParameters *data)
310 setParameters(*data);
311 if (exec() != QDialog::Accepted)
315 const BreakpointParameters newParameters = parameters();
316 if (data->equals(newParameters))
319 *data = newParameters;
324 ///////////////////////////////////////////////////////////////////////
328 ///////////////////////////////////////////////////////////////////////
330 BreakWindow::BreakWindow(QWidget *parent)
333 m_alwaysResizeColumnsToContents = false;
335 QAction *act = debuggerCore()->action(UseAlternatingRowColors);
336 setFrameStyle(QFrame::NoFrame);
337 setAttribute(Qt::WA_MacShowFocusRect, false);
338 setWindowTitle(tr("Breakpoints"));
339 setWindowIcon(QIcon(QLatin1String(":/debugger/images/debugger_breakpoints.png")));
340 setAlternatingRowColors(act->isChecked());
341 setRootIsDecorated(false);
342 setIconSize(QSize(10, 10));
343 setSelectionMode(QAbstractItemView::ExtendedSelection);
345 connect(this, SIGNAL(activated(QModelIndex)),
346 SLOT(rowActivated(QModelIndex)));
347 connect(act, SIGNAL(toggled(bool)),
348 SLOT(setAlternatingRowColorsHelper(bool)));
349 connect(debuggerCore()->action(UseAddressInBreakpointsView),
350 SIGNAL(toggled(bool)),
351 SLOT(showAddressColumn(bool)));
354 void BreakWindow::showAddressColumn(bool on)
356 setColumnHidden(7, !on);
359 void BreakWindow::keyPressEvent(QKeyEvent *ev)
361 if (ev->key() == Qt::Key_Delete) {
362 QItemSelectionModel *sm = selectionModel();
363 QTC_ASSERT(sm, return);
364 QModelIndexList si = sm->selectedIndexes();
366 si.append(currentIndex());
367 const BreakpointIds ids = breakHandler()->findBreakpointsByIndex(si);
368 int row = qMin(model()->rowCount() - ids.size() - 1, currentIndex().row());
369 deleteBreakpoints(ids);
370 setCurrentIndex(si.at(0).sibling(row, 0));
372 QTreeView::keyPressEvent(ev);
375 void BreakWindow::resizeEvent(QResizeEvent *ev)
377 QTreeView::resizeEvent(ev);
380 void BreakWindow::mouseDoubleClickEvent(QMouseEvent *ev)
382 QModelIndex indexUnderMouse = indexAt(ev->pos());
383 if (indexUnderMouse.isValid() && indexUnderMouse.column() >= 4) {
384 BreakpointId id = breakHandler()->findBreakpointByIndex(indexUnderMouse);
385 editBreakpoints(BreakpointIds() << id);
387 QTreeView::mouseDoubleClickEvent(ev);
390 void BreakWindow::setModel(QAbstractItemModel *model)
392 QTreeView::setModel(model);
393 resizeColumnToContents(0); // Number
394 resizeColumnToContents(3); // Line
395 resizeColumnToContents(6); // Ignore count
398 void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
401 QItemSelectionModel *sm = selectionModel();
402 QTC_ASSERT(sm, return);
403 QModelIndexList selectedIndices = sm->selectedIndexes();
404 QModelIndex indexUnderMouse = indexAt(ev->pos());
405 if (selectedIndices.isEmpty() && indexUnderMouse.isValid())
406 selectedIndices.append(indexUnderMouse);
408 BreakHandler *handler = breakHandler();
409 BreakpointIds selectedIds = handler->findBreakpointsByIndex(selectedIndices);
411 const int rowCount = model()->rowCount();
412 const unsigned engineCapabilities = BreakOnThrowAndCatchCapability;
413 // FIXME BP: model()->data(QModelIndex(), EngineCapabilitiesRole).toUInt();
415 QAction *deleteAction = new QAction(tr("Delete Breakpoint"), &menu);
416 deleteAction->setEnabled(!selectedIds.isEmpty());
418 QAction *deleteAllAction = new QAction(tr("Delete All Breakpoints"), &menu);
419 deleteAllAction->setEnabled(model()->rowCount() > 0);
421 // Delete by file: Find indices of breakpoints of the same file.
422 QAction *deleteByFileAction = 0;
423 BreakpointIds breakpointsInFile;
424 if (indexUnderMouse.isValid()) {
425 const QModelIndex index = indexUnderMouse.sibling(indexUnderMouse.row(), 2);
426 const QString file = index.data().toString();
427 if (!file.isEmpty()) {
428 for (int i = 0; i < rowCount; i++)
429 if (index.data().toString() == file)
430 breakpointsInFile.append(handler->findBreakpointByIndex(index));
431 if (breakpointsInFile.size() > 1) {
433 new QAction(tr("Delete Breakpoints of \"%1\"").arg(file), &menu);
434 deleteByFileAction->setEnabled(true);
438 if (!deleteByFileAction) {
439 deleteByFileAction = new QAction(tr("Delete Breakpoints of File"), &menu);
440 deleteByFileAction->setEnabled(false);
443 QAction *adjustColumnAction =
444 new QAction(tr("Adjust Column Widths to Contents"), &menu);
446 QAction *alwaysAdjustAction =
447 new QAction(tr("Always Adjust Column Widths to Contents"), &menu);
449 alwaysAdjustAction->setCheckable(true);
450 alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
452 QAction *editBreakpointAction =
453 new QAction(tr("Edit Breakpoint..."), &menu);
454 editBreakpointAction->setEnabled(!selectedIds.isEmpty());
457 // FIXME BP: m_engine->threadsHandler()->currentThreadId();
458 QString associateTitle = threadId == -1
459 ? tr("Associate Breakpoint With All Threads")
460 : tr("Associate Breakpoint With Thread %1").arg(threadId);
461 QAction *associateBreakpointAction = new QAction(associateTitle, &menu);
462 associateBreakpointAction->setEnabled(!selectedIds.isEmpty());
464 QAction *synchronizeAction =
465 new QAction(tr("Synchronize Breakpoints"), &menu);
466 synchronizeAction->setEnabled(debuggerCore()->hasSnapshots());
468 bool enabled = selectedIds.isEmpty() || handler->isEnabled(selectedIds.at(0));
470 const QString str5 = selectedIds.size() > 1
472 ? tr("Disable Selected Breakpoints")
473 : tr("Enable Selected Breakpoints")
475 ? tr("Disable Breakpoint")
476 : tr("Enable Breakpoint");
477 QAction *toggleEnabledAction = new QAction(str5, &menu);
478 toggleEnabledAction->setEnabled(!selectedIds.isEmpty());
480 QAction *addBreakpointAction =
481 new QAction(tr("Add Breakpoint..."), this);
482 QAction *breakAtThrowAction =
483 new QAction(tr("Set Breakpoint at \"throw\""), this);
484 QAction *breakAtCatchAction =
485 new QAction(tr("Set Breakpoint at \"catch\""), this);
487 menu.addAction(addBreakpointAction);
488 menu.addAction(deleteAction);
489 menu.addAction(editBreakpointAction);
490 menu.addAction(associateBreakpointAction);
491 menu.addAction(toggleEnabledAction);
493 menu.addAction(deleteAllAction);
494 //menu.addAction(deleteByFileAction);
496 menu.addAction(synchronizeAction);
497 if (engineCapabilities & BreakOnThrowAndCatchCapability) {
499 menu.addAction(breakAtThrowAction);
500 menu.addAction(breakAtCatchAction);
503 menu.addAction(debuggerCore()->action(UseToolTipsInBreakpointsView));
504 menu.addAction(debuggerCore()->action(UseAddressInBreakpointsView));
505 menu.addAction(adjustColumnAction);
506 menu.addAction(alwaysAdjustAction);
508 menu.addAction(debuggerCore()->action(SettingsDialog));
510 QAction *act = menu.exec(ev->globalPos());
512 if (act == deleteAction)
513 deleteBreakpoints(selectedIds);
514 else if (act == deleteAllAction)
515 deleteBreakpoints(handler->allBreakpointIds());
516 else if (act == deleteByFileAction)
517 deleteBreakpoints(breakpointsInFile);
518 else if (act == adjustColumnAction)
519 resizeColumnsToContents();
520 else if (act == alwaysAdjustAction)
521 setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
522 else if (act == editBreakpointAction)
523 editBreakpoints(selectedIds);
524 else if (act == associateBreakpointAction)
525 associateBreakpoint(selectedIds, threadId);
526 else if (act == synchronizeAction)
527 ; //synchronizeBreakpoints();
528 else if (act == toggleEnabledAction)
529 setBreakpointsEnabled(selectedIds, !enabled);
530 else if (act == addBreakpointAction)
532 else if (act == breakAtThrowAction)
533 handler->appendBreakpoint(BreakpointParameters(BreakpointAtThrow));
534 else if (act == breakAtCatchAction)
535 handler->appendBreakpoint(BreakpointParameters(BreakpointAtCatch));
538 void BreakWindow::setBreakpointsEnabled(const BreakpointIds &ids, bool enabled)
540 BreakHandler *handler = breakHandler();
541 foreach (const BreakpointId id, ids)
542 handler->setEnabled(id, enabled);
545 void BreakWindow::deleteBreakpoints(const BreakpointIds &ids)
547 BreakHandler *handler = breakHandler();
548 foreach (const BreakpointId id, ids)
549 handler->removeBreakpoint(id);
552 void BreakWindow::editBreakpoint(BreakpointId id, QWidget *parent)
554 BreakpointDialog dialog(parent);
555 BreakpointParameters data = breakHandler()->breakpointData(id);
556 if (dialog.showDialog(&data))
557 breakHandler()->setBreakpointData(id, data);
560 void BreakWindow::addBreakpoint()
562 BreakpointParameters data(BreakpointByFileAndLine);
563 BreakpointDialog dialog(this);
564 if (dialog.showDialog(&data))
565 breakHandler()->appendBreakpoint(data);
568 void BreakWindow::editBreakpoints(const BreakpointIds &ids)
570 QTC_ASSERT(!ids.isEmpty(), return);
572 const BreakpointId id = ids.at(0);
574 if (ids.size() == 1) {
575 editBreakpoint(id, this);
579 // This allows to change properties of multiple breakpoints at a time.
581 Ui::BreakCondition ui;
583 dlg.setWindowTitle(tr("Edit Breakpoint Properties"));
584 ui.lineEditIgnoreCount->setValidator(
585 new QIntValidator(0, 2147483647, ui.lineEditIgnoreCount));
587 BreakHandler *handler = breakHandler();
588 const QString oldCondition = QString::fromLatin1(handler->condition(id));
589 const QString oldIgnoreCount = QString::number(handler->ignoreCount(id));
590 const QString oldThreadSpec =
591 BreakHandler::displayFromThreadSpec(handler->threadSpec(id));
593 ui.lineEditCondition->setText(oldCondition);
594 ui.lineEditIgnoreCount->setText(oldIgnoreCount);
595 ui.lineEditThreadSpec->setText(oldThreadSpec);
597 if (dlg.exec() == QDialog::Rejected)
600 const QString newCondition = ui.lineEditCondition->text();
601 const QString newIgnoreCount = ui.lineEditIgnoreCount->text();
602 const QString newThreadSpec = ui.lineEditThreadSpec->text();
604 if (newCondition == oldCondition && newIgnoreCount == oldIgnoreCount
605 && newThreadSpec == oldThreadSpec)
608 foreach (const BreakpointId id, ids) {
609 handler->setCondition(id, newCondition.toLatin1());
610 handler->setIgnoreCount(id, newIgnoreCount.toInt());
611 handler->setThreadSpec(id,
612 BreakHandler::threadSpecFromDisplay(newThreadSpec));
616 void BreakWindow::associateBreakpoint(const BreakpointIds &ids, int threadId)
618 BreakHandler *handler = breakHandler();
619 foreach (const BreakpointId id, ids)
620 handler->setThreadSpec(id, threadId);
623 void BreakWindow::resizeColumnsToContents()
625 for (int i = model()->columnCount(); --i >= 0; )
626 resizeColumnToContents(i);
629 void BreakWindow::setAlwaysResizeColumnsToContents(bool on)
631 m_alwaysResizeColumnsToContents = on;
632 QHeaderView::ResizeMode mode = on
633 ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
634 for (int i = model()->columnCount(); --i >= 0; )
635 header()->setResizeMode(i, mode);
638 void BreakWindow::rowActivated(const QModelIndex &index)
640 breakHandler()->gotoLocation(breakHandler()->findBreakpointByIndex(index));
643 } // namespace Internal
644 } // namespace Debugger
646 #include "breakwindow.moc"