breakwindow.cpp 35.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
Eike Ziller's avatar
Eike Ziller committed
13 14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
hjk's avatar
hjk committed
25 26
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
#include "breakwindow.h"
Arvid Ephraim Picciani's avatar
Arvid Ephraim Picciani committed
32
#include "breakhandler.h"
33
#include "debuggerengine.h"
34
#include "debuggeractions.h"
35
#include "debuggercore.h"
con's avatar
con committed
36

37
#include <coreplugin/mainwindow.h>
38
#include <utils/checkablemessagebox.h>
39
#include <utils/pathchooser.h>
40
#include <utils/qtcassert.h>
41
#include <utils/savedaction.h>
42

43 44 45 46 47 48
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QGroupBox>
49
#include <QKeyEvent>
50 51
#include <QLabel>
#include <QLineEdit>
52
#include <QMenu>
53 54
#include <QSpinBox>
#include <QTextEdit>
con's avatar
con committed
55

56 57
namespace Debugger {
namespace Internal {
con's avatar
con committed
58

59 60 61 62 63 64 65
class SmallTextEdit : public QTextEdit
{
public:
    explicit SmallTextEdit(QWidget *parent) : QTextEdit(parent) {}
    QSize sizeHint() const { return QSize(QTextEdit::sizeHint().width(), 100); }
    QSize minimumSizeHint() const { return sizeHint(); }
};
66

67 68
///////////////////////////////////////////////////////////////////////
//
69 70 71 72 73
// BreakpointDialog: Show a dialog for editing breakpoints. Shows controls
// for the file-and-line, function and address parameters depending on the
// breakpoint type. The controls not applicable to the current type
// (say function name for file-and-line) are disabled and cleared out.
// However,the values are saved and restored once the respective mode
74
// is again chosen, which is done using m_savedParameters and
75
// setters/getters taking the parts mask enumeration parameter.
76 77 78
//
///////////////////////////////////////////////////////////////////////

79
class BreakpointDialog : public QDialog
80 81 82
{
    Q_OBJECT
public:
83
    explicit BreakpointDialog(BreakpointModelId id, QWidget *parent = 0);
84
    bool showDialog(BreakpointParameters *data, BreakpointParts *parts);
85

hjk's avatar
hjk committed
86
    void setParameters(const BreakpointParameters &data);
87 88
    BreakpointParameters parameters() const;

89
public slots:
90
    void typeChanged(int index);
91 92

private:
93 94
    void setPartsEnabled(unsigned partsMask);
    void clearOtherParts(unsigned partsMask);
hjk's avatar
hjk committed
95 96
    void getParts(unsigned partsMask, BreakpointParameters *data) const;
    void setParts(unsigned partsMask, const BreakpointParameters &data);
97

98 99
    void setType(BreakpointType type);
    BreakpointType type() const;
100

101
    unsigned m_enabledParts;
102 103
    BreakpointParameters m_savedParameters;
    BreakpointType m_previousType;
104
    bool m_firstTypeChange;
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

    QLabel *m_labelType;
    QComboBox *m_comboBoxType;
    QLabel *m_labelFileName;
    Utils::PathChooser *m_pathChooserFileName;
    QLabel *m_labelLineNumber;
    QLineEdit *m_lineEditLineNumber;
    QLabel *m_labelEnabled;
    QCheckBox *m_checkBoxEnabled;
    QLabel *m_labelAddress;
    QLineEdit *m_lineEditAddress;
    QLabel *m_labelExpression;
    QLineEdit *m_lineEditExpression;
    QLabel *m_labelFunction;
    QLineEdit *m_lineEditFunction;
    QLabel *m_labelTracepoint;
    QCheckBox *m_checkBoxTracepoint;
122 123
    QLabel *m_labelOneShot;
    QCheckBox *m_checkBoxOneShot;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    QLabel *m_labelUseFullPath;
    QLabel *m_labelModule;
    QLineEdit *m_lineEditModule;
    QLabel *m_labelCommands;
    QTextEdit *m_textEditCommands;
    QComboBox *m_comboBoxPathUsage;
    QLabel *m_labelMessage;
    QLineEdit *m_lineEditMessage;
    QLabel *m_labelCondition;
    QLineEdit *m_lineEditCondition;
    QLabel *m_labelIgnoreCount;
    QSpinBox *m_spinBoxIgnoreCount;
    QLabel *m_labelThreadSpec;
    QLineEdit *m_lineEditThreadSpec;
    QDialogButtonBox *m_buttonBox;
139 140
};

141
BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
142
    : QDialog(parent), m_enabledParts(~0), m_previousType(UnknownBreakpointType),
143
      m_firstTypeChange(true)
144
{
145
    setWindowTitle(tr("Edit Breakpoint Properties"));
146 147 148

    QGroupBox *groupBoxBasic = new QGroupBox(tr("Basic"), this);

hjk's avatar
hjk committed
149
    // Match BreakpointType (omitting unknown type).
150
    QStringList types;
151 152
    types << tr("File name and line number")
          << tr("Function name")
153
          << tr("Break on memory address")
154 155
          << tr("Break when C++ exception is thrown")
          << tr("Break when C++ exception is caught")
156
          << tr("Break when function \"main\" starts")
157 158 159
          << tr("Break when a new process is forked")
          << tr("Break when a new process is executed")
          << tr("Break when a system call is executed")
160
          << tr("Break on data access at fixed address")
161
          << tr("Break on data access at address given by expression")
162
          << tr("Break on QML signal emit")
163
          << tr("Break when JavaScript exception is thrown");
164 165
    // We don't list UnknownBreakpointType, so 1 less:
    QTC_CHECK(types.size() + 1 == LastBreakpointType);
166 167 168 169 170 171 172
    m_comboBoxType = new QComboBox(groupBoxBasic);
    m_comboBoxType->setMaxVisibleItems(20);
    m_comboBoxType->addItems(types);
    m_labelType = new QLabel(tr("Breakpoint &type:"), groupBoxBasic);
    m_labelType->setBuddy(m_comboBoxType);

    m_pathChooserFileName = new Utils::PathChooser(groupBoxBasic);
173
    m_pathChooserFileName->setHistoryCompleter(QLatin1String("Debugger.Breakpoint.File.History"));
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    m_pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
    m_labelFileName = new QLabel(tr("&File name:"), groupBoxBasic);
    m_labelFileName->setBuddy(m_pathChooserFileName);

    m_lineEditLineNumber = new QLineEdit(groupBoxBasic);
    m_labelLineNumber = new QLabel(tr("&Line number:"), groupBoxBasic);
    m_labelLineNumber->setBuddy(m_lineEditLineNumber);

    m_checkBoxEnabled = new QCheckBox(groupBoxBasic);
    m_labelEnabled = new QLabel(tr("&Enabled:"), groupBoxBasic);
    m_labelEnabled->setBuddy(m_checkBoxEnabled);

    m_lineEditAddress = new QLineEdit(groupBoxBasic);
    m_labelAddress = new QLabel(tr("&Address:"), groupBoxBasic);
    m_labelAddress->setBuddy(m_lineEditAddress);

    m_lineEditExpression = new QLineEdit(groupBoxBasic);
    m_labelExpression = new QLabel(tr("&Expression:"), groupBoxBasic);
    m_labelExpression->setBuddy(m_lineEditExpression);

    m_lineEditFunction = new QLineEdit(groupBoxBasic);
    m_labelFunction = new QLabel(tr("Fun&ction:"), groupBoxBasic);
    m_labelFunction->setBuddy(m_lineEditFunction);

    QGroupBox *groupBoxAdvanced = new QGroupBox(tr("Advanced"), this);

    m_checkBoxTracepoint = new QCheckBox(groupBoxAdvanced);
    m_labelTracepoint = new QLabel(tr("T&racepoint only:"), groupBoxAdvanced);
    m_labelTracepoint->setBuddy(m_checkBoxTracepoint);

204 205 206 207
    m_checkBoxOneShot = new QCheckBox(groupBoxAdvanced);
    m_labelOneShot = new QLabel(tr("&One shot only:"), groupBoxAdvanced);
    m_labelOneShot->setBuddy(m_checkBoxOneShot);

208
    const QString pathToolTip =
209 210 211 212 213 214 215 216 217 218
        tr("<html><head/><body><p>Determines how the path is specified "
                "when setting breakpoints:</p><ul>"
           "<li><i>Use Engine Default</i>: Preferred setting of the "
                "debugger engine.</li>"
           "<li><i>Use Full Path</i>: Pass full path, avoiding ambiguities "
                "should files of the same name exist in several modules. "
                "This is the engine default for CDB and LLDB.</li>"
           "<li><i>Use File Name</i>: Pass the file name only. This is "
                "useful when using a source tree whose location does "
                "not match the one used when building the modules. "
Jarek Kobus's avatar
Jarek Kobus committed
219
                "It is the engine default for GDB as using full paths can "
220 221
                "be slow with this engine.</li>"
           "</ul></body></html>");
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    m_comboBoxPathUsage = new QComboBox(groupBoxAdvanced);
    m_comboBoxPathUsage->addItem(tr("Use Engine Default"));
    m_comboBoxPathUsage->addItem(tr("Use Full Path"));
    m_comboBoxPathUsage->addItem(tr("Use File Name"));
    m_comboBoxPathUsage->setToolTip(pathToolTip);
    m_labelUseFullPath = new QLabel(tr("Pat&h:"), groupBoxAdvanced);
    m_labelUseFullPath->setBuddy(m_comboBoxPathUsage);
    m_labelUseFullPath->setToolTip(pathToolTip);

    const QString moduleToolTip =
        tr("Specifying the module (base name of the library or executable)\n"
           "for function or file type breakpoints can significantly speed up\n"
           "debugger start-up times (CDB, LLDB).");
    m_lineEditModule = new QLineEdit(groupBoxAdvanced);
    m_lineEditModule->setToolTip(moduleToolTip);
    m_labelModule = new QLabel(tr("&Module:"), groupBoxAdvanced);
    m_labelModule->setBuddy(m_lineEditModule);
    m_labelModule->setToolTip(moduleToolTip);

    const QString commandsToolTip =
        tr("Debugger commands to be executed when the breakpoint is hit.\n"
           "This feature is only available for GDB.");
    m_textEditCommands = new SmallTextEdit(groupBoxAdvanced);
    m_textEditCommands->setToolTip(commandsToolTip);
    m_labelCommands = new QLabel(tr("&Commands:"), groupBoxAdvanced);
    m_labelCommands->setBuddy(m_textEditCommands);
    m_labelCommands->setToolTip(commandsToolTip);

    m_lineEditMessage = new QLineEdit(groupBoxAdvanced);
    m_labelMessage = new QLabel(tr("&Message:"), groupBoxAdvanced);
    m_labelMessage->setBuddy(m_lineEditMessage);

    m_lineEditCondition = new QLineEdit(groupBoxAdvanced);
    m_labelCondition = new QLabel(tr("C&ondition:"), groupBoxAdvanced);
    m_labelCondition->setBuddy(m_lineEditCondition);

    m_spinBoxIgnoreCount = new QSpinBox(groupBoxAdvanced);
    m_spinBoxIgnoreCount->setMinimum(0);
    m_spinBoxIgnoreCount->setMaximum(2147483647);
    m_labelIgnoreCount = new QLabel(tr("&Ignore count:"), groupBoxAdvanced);
    m_labelIgnoreCount->setBuddy(m_spinBoxIgnoreCount);

    m_lineEditThreadSpec = new QLineEdit(groupBoxAdvanced);
    m_labelThreadSpec = new QLabel(tr("&Thread specification:"), groupBoxAdvanced);
    m_labelThreadSpec->setBuddy(m_lineEditThreadSpec);

    m_buttonBox = new QDialogButtonBox(this);
    m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);

    if (id.isValid()) {
        if (DebuggerEngine *engine = breakHandler()->engine(id)) {
            if (!engine->hasCapability(BreakConditionCapability))
                m_enabledParts &= ~ConditionPart;
            if (!engine->hasCapability(BreakModuleCapability))
                m_enabledParts &= ~ModulePart;
            if (!engine->hasCapability(TracePointCapability))
                m_enabledParts &= ~TracePointPart;
        }
    }

    QFormLayout *basicLayout = new QFormLayout(groupBoxBasic);
    basicLayout->addRow(m_labelType, m_comboBoxType);
    basicLayout->addRow(m_labelFileName, m_pathChooserFileName);
    basicLayout->addRow(m_labelLineNumber, m_lineEditLineNumber);
    basicLayout->addRow(m_labelEnabled, m_checkBoxEnabled);
    basicLayout->addRow(m_labelAddress, m_lineEditAddress);
    basicLayout->addRow(m_labelExpression, m_lineEditExpression);
    basicLayout->addRow(m_labelFunction, m_lineEditFunction);
290
    basicLayout->addRow(m_labelOneShot, m_checkBoxOneShot);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

    QFormLayout *advancedLeftLayout = new QFormLayout();
    advancedLeftLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
    advancedLeftLayout->addRow(m_labelCondition, m_lineEditCondition);
    advancedLeftLayout->addRow(m_labelIgnoreCount, m_spinBoxIgnoreCount);
    advancedLeftLayout->addRow(m_labelThreadSpec, m_lineEditThreadSpec);
    advancedLeftLayout->addRow(m_labelUseFullPath, m_comboBoxPathUsage);
    advancedLeftLayout->addRow(m_labelModule, m_lineEditModule);

    QFormLayout *advancedRightLayout = new QFormLayout();
    advancedRightLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
    advancedRightLayout->addRow(m_labelCommands, m_textEditCommands);
    advancedRightLayout->addRow(m_labelTracepoint, m_checkBoxTracepoint);
    advancedRightLayout->addRow(m_labelMessage, m_lineEditMessage);

    QHBoxLayout *horizontalLayout = new QHBoxLayout(groupBoxAdvanced);
    horizontalLayout->addLayout(advancedLeftLayout);
    horizontalLayout->addSpacing(15);
    horizontalLayout->addLayout(advancedRightLayout);

    QVBoxLayout *verticalLayout = new QVBoxLayout(this);
    verticalLayout->addWidget(groupBoxBasic);
    verticalLayout->addSpacing(10);
    verticalLayout->addWidget(groupBoxAdvanced);
    verticalLayout->addSpacing(10);
    verticalLayout->addWidget(m_buttonBox);
    verticalLayout->setStretchFactor(groupBoxAdvanced, 10);

    connect(m_comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
    connect(m_buttonBox, SIGNAL(accepted()), SLOT(accept()));
    connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject()));
322 323
}

324 325
void BreakpointDialog::setType(BreakpointType type)
{
hjk's avatar
hjk committed
326
    const int comboIndex = type - 1; // Skip UnknownType.
327 328
    if (comboIndex != m_comboBoxType->currentIndex() || m_firstTypeChange) {
        m_comboBoxType->setCurrentIndex(comboIndex);
329
        typeChanged(comboIndex);
330
        m_firstTypeChange = false;
331 332 333 334
    }
}

BreakpointType BreakpointDialog::type() const
335
{
336
    const int type = m_comboBoxType->currentIndex() + 1; // Skip unknown type.
337 338 339
    return static_cast<BreakpointType>(type);
}

hjk's avatar
hjk committed
340
void BreakpointDialog::setParameters(const BreakpointParameters &data)
341
{
hjk's avatar
hjk committed
342 343 344
    m_savedParameters = data;
    setType(data.type);
    setParts(AllParts, data);
345
}
346

347 348
BreakpointParameters BreakpointDialog::parameters() const
{
hjk's avatar
hjk committed
349 350 351
    BreakpointParameters data(type());
    getParts(AllParts, &data);
    return data;
352 353
}

354
void BreakpointDialog::setPartsEnabled(unsigned partsMask)
355
{
356
    partsMask &= m_enabledParts;
357 358 359 360 361 362 363 364 365 366
    m_labelFileName->setEnabled(partsMask & FileAndLinePart);
    m_pathChooserFileName->setEnabled(partsMask & FileAndLinePart);
    m_labelLineNumber->setEnabled(partsMask & FileAndLinePart);
    m_lineEditLineNumber->setEnabled(partsMask & FileAndLinePart);
    m_labelUseFullPath->setEnabled(partsMask & FileAndLinePart);
    m_comboBoxPathUsage->setEnabled(partsMask & FileAndLinePart);

    m_labelFunction->setEnabled(partsMask & FunctionPart);
    m_lineEditFunction->setEnabled(partsMask & FunctionPart);

367 368 369
    m_labelOneShot->setEnabled(partsMask & OneShotPart);
    m_checkBoxOneShot->setEnabled(partsMask & OneShotPart);

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    m_labelAddress->setEnabled(partsMask & AddressPart);
    m_lineEditAddress->setEnabled(partsMask & AddressPart);
    m_labelExpression->setEnabled(partsMask & ExpressionPart);
    m_lineEditExpression->setEnabled(partsMask & ExpressionPart);

    m_labelCondition->setEnabled(partsMask & ConditionPart);
    m_lineEditCondition->setEnabled(partsMask & ConditionPart);
    m_labelIgnoreCount->setEnabled(partsMask & IgnoreCountPart);
    m_spinBoxIgnoreCount->setEnabled(partsMask & IgnoreCountPart);
    m_labelThreadSpec->setEnabled(partsMask & ThreadSpecPart);
    m_lineEditThreadSpec->setEnabled(partsMask & ThreadSpecPart);

    m_labelModule->setEnabled(partsMask & ModulePart);
    m_lineEditModule->setEnabled(partsMask & ModulePart);

    m_labelTracepoint->setEnabled(partsMask & TracePointPart);
    m_checkBoxTracepoint->setEnabled(partsMask & TracePointPart);

    m_labelCommands->setEnabled(partsMask & TracePointPart);
    m_textEditCommands->setEnabled(partsMask & TracePointPart);

    m_labelMessage->setEnabled(partsMask & TracePointPart);
    m_lineEditMessage->setEnabled(partsMask & TracePointPart);
393 394
}

395
void BreakpointDialog::clearOtherParts(unsigned partsMask)
396
{
397 398
    const unsigned invertedPartsMask = ~partsMask;
    if (invertedPartsMask & FileAndLinePart) {
399 400 401
        m_pathChooserFileName->setPath(QString());
        m_lineEditLineNumber->clear();
        m_comboBoxPathUsage->setCurrentIndex(BreakpointPathUsageEngineDefault);
402 403
    }

404
    if (invertedPartsMask & FunctionPart)
405
        m_lineEditFunction->clear();
406

407
    if (invertedPartsMask & AddressPart)
408
        m_lineEditAddress->clear();
409
    if (invertedPartsMask & ExpressionPart)
410
        m_lineEditExpression->clear();
411

412
    if (invertedPartsMask & ConditionPart)
413
        m_lineEditCondition->clear();
414
    if (invertedPartsMask & IgnoreCountPart)
415
        m_spinBoxIgnoreCount->clear();
416
    if (invertedPartsMask & ThreadSpecPart)
417
        m_lineEditThreadSpec->clear();
418
    if (invertedPartsMask & ModulePart)
419
        m_lineEditModule->clear();
420

421 422
    if (partsMask & OneShotPart)
        m_checkBoxOneShot->setChecked(false);
423
    if (invertedPartsMask & TracePointPart) {
424 425 426
        m_checkBoxTracepoint->setChecked(false);
        m_textEditCommands->clear();
        m_lineEditMessage->clear();
427
    }
428 429
}

hjk's avatar
hjk committed
430
void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data) const
431
{
432
    data->enabled = m_checkBoxEnabled->isChecked();
433

434
    if (partsMask & FileAndLinePart) {
435 436 437
        data->lineNumber = m_lineEditLineNumber->text().toInt();
        data->pathUsage = static_cast<BreakpointPathUsage>(m_comboBoxPathUsage->currentIndex());
        data->fileName = m_pathChooserFileName->path();
438 439
    }
    if (partsMask & FunctionPart)
440
        data->functionName = m_lineEditFunction->text();
441 442

    if (partsMask & AddressPart)
443
        data->address = m_lineEditAddress->text().toULongLong(0, 0);
444
    if (partsMask & ExpressionPart)
445
        data->expression = m_lineEditExpression->text();
446

447
    if (partsMask & ConditionPart)
448
        data->condition = m_lineEditCondition->text().toUtf8();
449
    if (partsMask & IgnoreCountPart)
450
        data->ignoreCount = m_spinBoxIgnoreCount->text().toInt();
451
    if (partsMask & ThreadSpecPart)
452
        data->threadSpec =
453
            BreakHandler::threadSpecFromDisplay(m_lineEditThreadSpec->text());
454
    if (partsMask & ModulePart)
455
        data->module = m_lineEditModule->text();
456

457 458
    if (partsMask & OneShotPart)
        data->oneShot = m_checkBoxOneShot->isChecked();
459
    if (partsMask & TracePointPart) {
460 461 462
        data->tracepoint = m_checkBoxTracepoint->isChecked();
        data->command = m_textEditCommands->toPlainText().trimmed();
        data->message = m_lineEditMessage->text();
463
    }
464 465
}

hjk's avatar
hjk committed
466
void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
467
{
468 469 470 471
    m_checkBoxEnabled->setChecked(data.enabled);
    m_comboBoxPathUsage->setCurrentIndex(data.pathUsage);
    m_textEditCommands->setPlainText(data.command);
    m_lineEditMessage->setText(data.message);
472

473
    if (mask & FileAndLinePart) {
474 475
        m_pathChooserFileName->setPath(data.fileName);
        m_lineEditLineNumber->setText(QString::number(data.lineNumber));
476 477 478
    }

    if (mask & FunctionPart)
479
        m_lineEditFunction->setText(data.functionName);
480 481

    if (mask & AddressPart) {
hjk's avatar
hjk committed
482
        if (data.address) {
483
            m_lineEditAddress->setText(
484
                QString::fromLatin1("0x%1").arg(data.address, 0, 16));
485
        } else {
486
            m_lineEditAddress->clear();
487 488
        }
    }
489

490
    if (mask & ExpressionPart) {
491
        if (!data.expression.isEmpty())
492
            m_lineEditExpression->setText(data.expression);
493
        else
494
            m_lineEditExpression->clear();
495 496
    }

497
    if (mask & ConditionPart)
498
        m_lineEditCondition->setText(QString::fromUtf8(data.condition));
499
    if (mask & IgnoreCountPart)
500
        m_spinBoxIgnoreCount->setValue(data.ignoreCount);
501
    if (mask & ThreadSpecPart)
502
        m_lineEditThreadSpec->
503
            setText(BreakHandler::displayFromThreadSpec(data.threadSpec));
504
    if (mask & ModulePart)
505
        m_lineEditModule->setText(data.module);
506

507 508
    if (mask & OneShotPart)
        m_checkBoxOneShot->setChecked(data.oneShot);
509
    if (mask & TracePointPart)
510
        m_checkBoxTracepoint->setChecked(data.tracepoint);
511 512
}

513
void BreakpointDialog::typeChanged(int)
514
{
515 516 517
    BreakpointType previousType = m_previousType;
    const BreakpointType newType = type();
    m_previousType = newType;
hjk's avatar
hjk committed
518
    // Save current state.
519
    switch (previousType) {
520 521
    case UnknownBreakpointType:
    case LastBreakpointType:
522 523
        break;
    case BreakpointByFileAndLine:
524
        getParts(FileAndLinePart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters);
525 526
        break;
    case BreakpointByFunction:
527
        getParts(FunctionPart|ModulePart|AllConditionParts|TracePointPart, &m_savedParameters);
528 529 530 531
        break;
    case BreakpointAtThrow:
    case BreakpointAtCatch:
    case BreakpointAtMain:
532 533
    case BreakpointAtFork:
    case BreakpointAtExec:
534
    //case BreakpointAtVFork:
535
    case BreakpointAtSysCall:
536
    case BreakpointAtJavaScriptThrow:
537 538
        break;
    case BreakpointByAddress:
539
    case WatchpointAtAddress:
540
        getParts(AddressPart|AllConditionParts|TracePointPart, &m_savedParameters);
541
        break;
542 543 544
    case WatchpointAtExpression:
        getParts(ExpressionPart|AllConditionParts|TracePointPart, &m_savedParameters);
        break;
545
    case BreakpointOnQmlSignalEmit:
546
        getParts(FunctionPart, &m_savedParameters);
547 548
    }

hjk's avatar
hjk committed
549 550
    // Enable and set up new state from saved values.
    switch (newType) {
551 552
    case UnknownBreakpointType:
    case LastBreakpointType:
553 554
        break;
    case BreakpointByFileAndLine:
555 556 557
        setParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters);
        setPartsEnabled(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart);
        clearOtherParts(FileAndLinePart|AllConditionParts|ModulePart|TracePointPart);
558 559
        break;
    case BreakpointByFunction:
560 561 562
        setParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart, m_savedParameters);
        setPartsEnabled(FunctionPart|AllConditionParts|ModulePart|TracePointPart);
        clearOtherParts(FunctionPart|AllConditionParts|ModulePart|TracePointPart);
563 564 565
        break;
    case BreakpointAtThrow:
    case BreakpointAtCatch:
566 567
    case BreakpointAtFork:
    case BreakpointAtExec:
568
    //case BreakpointAtVFork:
569
    case BreakpointAtSysCall:
570 571
        clearOtherParts(AllConditionParts|ModulePart|TracePointPart);
        setPartsEnabled(AllConditionParts|TracePointPart);
572
        break;
573 574 575 576
    case BreakpointAtJavaScriptThrow:
        clearOtherParts(AllParts);
        setPartsEnabled(0);
        break;
577
    case BreakpointAtMain:
578
        m_lineEditFunction->setText(QLatin1String("main")); // Just for display
579 580
        clearOtherParts(0);
        setPartsEnabled(0);
581 582
        break;
    case BreakpointByAddress:
583
    case WatchpointAtAddress:
584
        setParts(AddressPart|AllConditionParts|TracePointPart, m_savedParameters);
585
        setPartsEnabled(AddressPart|AllConditionParts|TracePointPart);
586
        clearOtherParts(AddressPart|AllConditionParts|TracePointPart);
587
        break;
588 589
    case WatchpointAtExpression:
        setParts(ExpressionPart|AllConditionParts|TracePointPart, m_savedParameters);
590
        setPartsEnabled(ExpressionPart|AllConditionParts|TracePointPart);
591 592
        clearOtherParts(ExpressionPart|AllConditionParts|TracePointPart);
        break;
593
    case BreakpointOnQmlSignalEmit:
594 595 596
        setParts(FunctionPart, m_savedParameters);
        setPartsEnabled(FunctionPart);
        clearOtherParts(FunctionPart);
597
    }
598 599
}

600 601
bool BreakpointDialog::showDialog(BreakpointParameters *data,
    BreakpointParts *parts)
602
{
hjk's avatar
hjk committed
603
    setParameters(*data);
604 605 606 607 608
    if (exec() != QDialog::Accepted)
        return false;

    // Check if changed.
    const BreakpointParameters newParameters = parameters();
609 610
    *parts = data->differencesTo(newParameters);
    if (!*parts)
611 612
        return false;

hjk's avatar
hjk committed
613 614
    *data = newParameters;
    return true;
615 616
}

617
// Dialog allowing changing properties of multiple breakpoints at a time.
618 619
class MultiBreakPointsDialog : public QDialog
{
620
    Q_OBJECT
621

622
public:
623
    MultiBreakPointsDialog(QWidget *parent = 0);
624

625 626
    QString condition() const { return m_lineEditCondition->text(); }
    int ignoreCount() const { return m_spinBoxIgnoreCount->value(); }
627
    int threadSpec() const
628
       { return BreakHandler::threadSpecFromDisplay(m_lineEditThreadSpec->text()); }
629

630 631
    void setCondition(const QString &c) { m_lineEditCondition->setText(c); }
    void setIgnoreCount(int i) { m_spinBoxIgnoreCount->setValue(i); }
632
    void setThreadSpec(int t)
633
        { return m_lineEditThreadSpec->setText(BreakHandler::displayFromThreadSpec(t)); }
634 635

private:
636 637 638 639
    QLineEdit *m_lineEditCondition;
    QSpinBox *m_spinBoxIgnoreCount;
    QLineEdit *m_lineEditThreadSpec;
    QDialogButtonBox *m_buttonBox;
640 641
};

642
MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) :
643 644 645 646
    QDialog(parent)
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    setWindowTitle(tr("Edit Breakpoint Properties"));
647 648 649 650 651 652 653 654 655 656 657

    m_lineEditCondition = new QLineEdit(this);
    m_spinBoxIgnoreCount = new QSpinBox(this);
    m_spinBoxIgnoreCount->setMinimum(0);
    m_spinBoxIgnoreCount->setMaximum(2147483647);
    m_lineEditThreadSpec = new QLineEdit(this);

    m_buttonBox = new QDialogButtonBox(this);
    m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);

    QFormLayout *formLayout = new QFormLayout;
hjk's avatar
hjk committed
658
    if (currentEngine()->hasCapability(BreakConditionCapability))
659 660 661 662 663 664 665 666 667 668
        formLayout->addRow(tr("&Condition:"), m_lineEditCondition);
    formLayout->addRow(tr("&Ignore count:"), m_spinBoxIgnoreCount);
    formLayout->addRow(tr("&Thread specification:"), m_lineEditThreadSpec);

    QVBoxLayout *verticalLayout = new QVBoxLayout(this);
    verticalLayout->addLayout(formLayout);
    verticalLayout->addWidget(m_buttonBox);

    QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
669
}
670

671 672 673 674 675 676
///////////////////////////////////////////////////////////////////////
//
// BreakWindow
//
///////////////////////////////////////////////////////////////////////

677
BreakTreeView::BreakTreeView()
con's avatar
con committed
678
{
679
    setWindowIcon(QIcon(QLatin1String(":/debugger/images/debugger_breakpoints.png")));
hjk's avatar
hjk committed
680
    setSelectionMode(QAbstractItemView::ExtendedSelection);
hjk's avatar
hjk committed
681
    connect(action(UseAddressInBreakpointsView),
682
        SIGNAL(toggled(bool)), SLOT(showAddressColumn(bool)));
683 684
}

hjk's avatar
hjk committed
685
void BreakTreeView::showAddressColumn(bool on)
686
{
hjk's avatar
hjk committed
687
    setColumnHidden(7, !on);
con's avatar
con committed
688 689
}

hjk's avatar
hjk committed
690
void BreakTreeView::keyPressEvent(QKeyEvent *ev)
con's avatar
con committed
691
{
692
    if (ev->key() == Qt::Key_Delete) {
hjk's avatar
hjk committed
693
        QItemSelectionModel *sm = selectionModel();
694 695 696
        QTC_ASSERT(sm, return);
        QModelIndexList si = sm->selectedIndexes();
        if (si.isEmpty())
hjk's avatar
hjk committed
697
            si.append(currentIndex());
698
        const BreakpointModelIds ids = breakHandler()->findBreakpointsByIndex(si);
hjk's avatar
hjk committed
699
        int row = qMin(model()->rowCount() - ids.size() - 1, currentIndex().row());
700
        deleteBreakpoints(ids);
hjk's avatar
hjk committed
701
        setCurrentIndex(si.at(0).sibling(row, 0));
702 703 704 705 706 707 708 709 710 711 712 713
    } else if (ev->key() == Qt::Key_Space) {
        QItemSelectionModel *sm = selectionModel();
        QTC_ASSERT(sm, return);
        const QModelIndexList selectedIds = sm->selectedIndexes();
        if (!selectedIds.isEmpty()) {
            BreakHandler *handler = breakHandler();
            const BreakpointModelIds validIds = handler->findBreakpointsByIndex(selectedIds);
            const bool isEnabled = validIds.isEmpty() || handler->isEnabled(validIds.at(0));
            setBreakpointsEnabled(validIds, !isEnabled);
            foreach (const QModelIndex &id, selectedIds)
                update(id);
        }
714
    }
715
    BaseTreeView::keyPressEvent(ev);
con's avatar
con committed
716 717
}

hjk's avatar
hjk committed
718
void BreakTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
719 720
{
    QModelIndex indexUnderMouse = indexAt(ev->pos());
721 722 723 724 725 726 727
    if (indexUnderMouse.isValid()) {
        if (indexUnderMouse.column() >= 4) {
            BreakpointModelId id = breakHandler()->findBreakpointByIndex(indexUnderMouse);
            editBreakpoints(BreakpointModelIds() << id);
        }
    } else {
        addBreakpoint();
728
    }
729
    BaseTreeView::mouseDoubleClickEvent(ev);
730 731
}

hjk's avatar
hjk committed
732
void BreakTreeView::contextMenuEvent(QContextMenuEvent *ev)
con's avatar
con committed
733 734
{
    QMenu menu;
hjk's avatar
hjk committed
735 736 737 738 739 740
    QItemSelectionModel *sm = selectionModel();
    QTC_ASSERT(sm, return);
    QModelIndexList selectedIndices = sm->selectedIndexes();
    QModelIndex indexUnderMouse = indexAt(ev->pos());
    if (selectedIndices.isEmpty() && indexUnderMouse.isValid())
        selectedIndices.append(indexUnderMouse);
741 742

    BreakHandler *handler = breakHandler();
743 744 745 746
    BreakpointModelIds selectedIds;
    foreach (BreakpointModelId id, handler->findBreakpointsByIndex(selectedIndices))
        if (id.isMajor())
            selectedIds.append(id);
747

748
    const int rowCount = model()->rowCount();
749
    QAction *deleteAction = new QAction(tr("Delete Breakpoint"), &menu);
750
    deleteAction->setEnabled(!selectedIds.empty());
751

752
    QAction *deleteAllAction = new QAction(tr("Delete All Breakpoints"), &menu);
753
    deleteAllAction->setEnabled(model()->rowCount() > 0);
754

755
    // Delete by file: Find indices of breakpoints of the same file.
756
    QAction *deleteByFileAction = 0;
757
    BreakpointModelIds breakpointsInFile;
hjk's avatar
hjk committed
758 759
    if (indexUnderMouse.isValid()) {
        const QModelIndex index = indexUnderMouse.sibling(indexUnderMouse.row(), 2);
760
        const QString file = index.data().toString();
761
        if (!file.isEmpty()) {
hjk's avatar
hjk committed
762
            for (int i = 0; i != rowCount; ++i)
763 764 765
                if (index.data().toString() == file)
                    breakpointsInFile.append(handler->findBreakpointByIndex(index));
            if (breakpointsInFile.size() > 1) {
766 767
                deleteByFileAction =
                    new QAction(tr("Delete Breakpoints of \"%1\"").arg(file), &menu);
768 769 770 771 772
                deleteByFileAction->setEnabled(true);
            }
        }
    }
    if (!deleteByFileAction) {
773
        deleteByFileAction = new QAction(tr("Delete Breakpoints of File"), &menu);
774 775
        deleteByFileAction->setEnabled(false);
    }
776

777 778
    QAction *editBreakpointAction =
        new QAction(tr("Edit Breakpoint..."), &menu);
779
    editBreakpointAction->setEnabled(!selectedIds.isEmpty());
780

781 782
    int threadId = 0;
    // FIXME BP: m_engine->threadsHandler()->currentThreadId();
783 784 785 786
    QString associateTitle = threadId == -1
        ?  tr("Associate Breakpoint With All Threads")
        :  tr("Associate Breakpoint With Thread %1").arg(threadId);
    QAction *associateBreakpointAction = new QAction(associateTitle, &menu);
787
    associateBreakpointAction->setEnabled(!selectedIds.isEmpty());
788

789 790
    QAction *synchronizeAction =
        new QAction(tr("Synchronize Breakpoints"), &menu);
791
    synchronizeAction->setEnabled(Internal::hasSnapshots());
792

793
    bool enabled = selectedIds.isEmpty() || handler->isEnabled(selectedIds.at(0));
hjk's avatar
hjk committed
794

795
    const QString str5 = selectedIds.size() > 1
796 797 798 799 800 801
        ? enabled
            ? tr("Disable Selected Breakpoints")
            : tr("Enable Selected Breakpoints")
        : enabled
            ? tr("Disable Breakpoint")
            : tr("Enable Breakpoint");
802
    QAction *toggleEnabledAction = new QAction(str5, &menu);
803
    toggleEnabledAction->setEnabled(!selectedIds.isEmpty());
804

805
    QAction *addBreakpointAction =
806
        new QAction(tr("Add Breakpoint..."), this);
807

808
    menu.addAction(addBreakpointAction);
809
    menu.addAction(deleteAction);
810
    menu.addAction(editBreakpointAction);
811
    menu.addAction(associateBreakpointAction);
812 813 814
    menu.addAction(toggleEnabledAction);
    menu.addSeparator();
    menu.addAction(deleteAllAction);
hjk's avatar
hjk committed
815
    //menu.addAction(deleteByFileAction);
816
    menu.addSeparator();
817
    menu.addAction(synchronizeAction);
818
    menu.addSeparator();
hjk's avatar
hjk committed
819 820 821
    menu.addAction(action(UseToolTipsInBreakpointsView));
    if (currentEngine()->hasCapability(MemoryAddressCapability))
        menu.addAction(action(UseAddressInBreakpointsView));
822
    menu.addSeparator();
hjk's avatar
hjk committed
823
    menu.addAction(action(SettingsDialog));
con's avatar
con committed
824 825 826

    QAction *act = menu.exec(ev->globalPos());

827 828 829
    if (act == deleteAction)
        deleteBreakpoints(selectedIds);
    else if (act == deleteAllAction)
830
        deleteAllBreakpoints();
831 832
    else if (act == deleteByFileAction)
        deleteBreakpoints(breakpointsInFile);
833
    else if (act == editBreakpointAction)
834
        editBreakpoints(selectedIds);
835
    else if (act == associateBreakpointAction)
836
        associateBreakpoint(selectedIds, threadId);
837
    else if (act == synchronizeAction)
hjk's avatar
hjk committed
838
        ; //synchronizeBreakpoints();
839
    else if (act == toggleEnabledAction)
840
        setBreakpointsEnabled(selectedIds, !enabled);
841 842
    else if (act == addBreakpointAction)
        addBreakpoint();
843 844
}

hjk's avatar
hjk committed
845
void BreakTreeView::setBreakpointsEnabled(const BreakpointModelIds &ids, bool enabled)
846
{
hjk's avatar
hjk committed
847
    BreakHandler *handler = breakHandler();
848
    foreach (const BreakpointModelId id, ids)
849
        handler->setEnabled(id, enabled);
850 851
}

852 853
void BreakTreeView::deleteAllBreakpoints()
{
854
    if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::dialogParent(),
855
           tr("Remove All Breakpoints"),
856
           tr("Are you sure you want to remove all breakpoints "
857
              "from all files in the current session?"),
858 859
           Core::ICore::settings(),
           QLatin1String("RemoveAllBreakpoints")) == QDialogButtonBox::Yes)
860 861 8