diff --git a/src/plugins/android/androidanalyzesupport.cpp b/src/plugins/android/androidanalyzesupport.cpp index 352a5f16bd442b9f9e5fc3dfd7264074a4427ee1..820e9ab00de01b1ad88b77352793b7db69a80dc7 100644 --- a/src/plugins/android/androidanalyzesupport.cpp +++ b/src/plugins/android/androidanalyzesupport.cpp @@ -39,7 +39,7 @@ #include <QDir> #include <QTcpServer> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Android { @@ -48,7 +48,7 @@ namespace Internal { RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(AndroidRunConfiguration *runConfig, Core::Id runMode) { - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, runMode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, runMode); QTC_ASSERT(runControl, return 0); AnalyzerConnection connection; if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { diff --git a/src/plugins/android/androidanalyzesupport.h b/src/plugins/android/androidanalyzesupport.h index ba4416a2d4409142af63a2087596f8db1f108247..e272688a271aacc622498ce13be715239c5f3950 100644 --- a/src/plugins/android/androidanalyzesupport.h +++ b/src/plugins/android/androidanalyzesupport.h @@ -29,7 +29,7 @@ #include "androidrunconfiguration.h" #include <qmldebug/qmloutputparser.h> -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace ProjectExplorer { class RunControl; } namespace Android { @@ -43,7 +43,7 @@ class AndroidAnalyzeSupport : public QObject public: AndroidAnalyzeSupport(AndroidRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl); + Debugger::AnalyzerRunControl *runControl); static ProjectExplorer::RunControl *createAnalyzeRunControl(AndroidRunConfiguration *runConfig, Core::Id runMode); diff --git a/src/plugins/baremetal/baremetalruncontrolfactory.cpp b/src/plugins/baremetal/baremetalruncontrolfactory.cpp index 0221fab3ad44782e070dc6950f6d389b2f897ca4..b9b49286db3a22da677c80f2e6a3bac83cfa8c56 100644 --- a/src/plugins/baremetal/baremetalruncontrolfactory.cpp +++ b/src/plugins/baremetal/baremetalruncontrolfactory.cpp @@ -50,7 +50,6 @@ #include <QApplication> -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h index ecb5e8e94e48a3bd3cfec7daa04c8f0d724e0b23..708b5137f59bdfe1d5967b326a3f6c5f81dc1c01 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h @@ -44,8 +44,8 @@ public: QString message; QString extendedMessage; - Analyzer::DiagnosticLocation location; - QList<Analyzer::DiagnosticLocation> ranges; + Debugger::DiagnosticLocation location; + QList<Debugger::DiagnosticLocation> ranges; int depth; }; @@ -59,7 +59,7 @@ public: QString type; QString issueContextKind; QString issueContext; - Analyzer::DiagnosticLocation location; + Debugger::DiagnosticLocation location; QList<ExplainingStep> explainingSteps; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp index fa0625891a3197b46fe5b5e69cc10cc5cc188fdb..49b904a812c6a9e99b704ea45ed8050aaa22559e 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp @@ -168,7 +168,7 @@ static QString createExplainingStepToolTipString(const ExplainingStep &step) return html; } -static QString createLocationString(const Analyzer::DiagnosticLocation &location) +static QString createLocationString(const Debugger::DiagnosticLocation &location) { const QString filePath = location.filePath; const QString lineNumber = QString::number(location.line); @@ -224,10 +224,10 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag) appendChild(new ExplainingStepItem(s)); } -QVariant locationData(int role, const Analyzer::DiagnosticLocation &location) +QVariant locationData(int role, const Debugger::DiagnosticLocation &location) { switch (role) { - case Analyzer::DetailedErrorView::LocationRole: + case Debugger::DetailedErrorView::LocationRole: return QVariant::fromValue(location); case Qt::ToolTipRole: return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath); @@ -238,12 +238,12 @@ QVariant locationData(int role, const Analyzer::DiagnosticLocation &location) QVariant DiagnosticItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return locationData(role, m_diagnostic.location); // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: + case Debugger::DetailedErrorView::FullTextRole: return fullText(m_diagnostic); case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole: return QVariant::fromValue(m_diagnostic); @@ -262,12 +262,12 @@ ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step QVariant ExplainingStepItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return locationData(role, m_step.location); // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: + case Debugger::DetailedErrorView::FullTextRole: return fullText(static_cast<DiagnosticItem *>(parent())->diagnostic()); case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole: return QVariant::fromValue(static_cast<DiagnosticItem *>(parent())->diagnostic()); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h index 437e83ce4029ce9e4ff696303cd6629e55932663..e8a30f34efe681b5ff889dafeb2b4f0d81a76352 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h @@ -52,7 +52,7 @@ public: QList<Diagnostic> diagnostics() const; enum ItemRole { - DiagnosticRole = Analyzer::DetailedErrorView::FullTextRole + 1 + DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1 }; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp index 69fb87a3bb5f2f68b8653da3b56d336fabfe8cbe..fdd3a7aef592263e15552b7b76c403f979962505 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp @@ -36,13 +36,13 @@ #include <QAction> #include <QDebug> -using namespace Analyzer; +using namespace Debugger; namespace ClangStaticAnalyzer { namespace Internal { ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent) - : Analyzer::DetailedErrorView(parent) + : Debugger::DetailedErrorView(parent) { m_suppressAction = new QAction(tr("Suppress this diagnostic"), this); connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); }); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h index 0d5016fd7c48f3f5c0257064666f34ab0c1df7aa..55ba24642cfba34818ba6db0e8f8e07268a7abdc 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h @@ -31,7 +31,7 @@ namespace ClangStaticAnalyzer { namespace Internal { -class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView +class ClangStaticAnalyzerDiagnosticView : public Debugger::DetailedErrorView { Q_OBJECT diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp index dd0727864fc0a3814cf334e9898c334f080aafd5..f66ce2a545b6a0886cff199134050882f7b9abc0 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp @@ -55,8 +55,8 @@ private: void readDiagnosticsDict(); QList<ExplainingStep> readPathArray(); ExplainingStep readPathDict(); - Analyzer::DiagnosticLocation readLocationDict(bool elementIsRead = false); - QList<Analyzer::DiagnosticLocation> readRangesArray(); + Debugger::DiagnosticLocation readLocationDict(bool elementIsRead = false); + QList<Debugger::DiagnosticLocation> readRangesArray(); QString readString(); QStringList readStringArray(); @@ -284,9 +284,9 @@ ExplainingStep ClangStaticAnalyzerLogFileReader::readPathDict() return explainingStep; } -Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead) +Debugger::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead) { - Analyzer::DiagnosticLocation location; + Debugger::DiagnosticLocation location; if (elementIsRead) { QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"), return location); @@ -317,14 +317,14 @@ Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict( if (lineOk && columnOk && fileIndexOk) { QTC_ASSERT(fileIndex < m_referencedFiles.size(), return location); - location = Analyzer::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column); + location = Debugger::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column); } return location; } -QList<Analyzer::DiagnosticLocation> ClangStaticAnalyzerLogFileReader::readRangesArray() +QList<Debugger::DiagnosticLocation> ClangStaticAnalyzerLogFileReader::readRangesArray() { - QList<Analyzer::DiagnosticLocation> result; + QList<Debugger::DiagnosticLocation> result; // It's an array of arrays... QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"), diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 28146c0acdd4afba7dd9d10a68a3bcc59c305358..0ab5c15e0000f62920453b66c5f7c25ce1f01f94 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -53,7 +53,7 @@ #include <QtPlugin> -using namespace Analyzer; +using namespace Debugger; namespace ClangStaticAnalyzer { namespace Internal { @@ -122,36 +122,10 @@ bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString panelFactory->setSimpleCreateWidgetFunction<ProjectSettingsWidget>(QIcon()); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); - auto tool = m_analyzerTool = new ClangStaticAnalyzerTool(this); + m_analyzerTool = new ClangStaticAnalyzerTool(this); addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool)); addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage); - AnalyzerManager::registerToolbar(ClangStaticAnalyzerPerspectiveId, tool->createWidgets()); - - auto runControlCreator = [tool](ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id runMode) { - return tool->createRunControl(runConfiguration, runMode); - }; - - const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project " - "to find bugs."); - - AnalyzerManager::registerPerspective(ClangStaticAnalyzerPerspectiveId, { - { ClangStaticAnalyzerDockId, Core::Id(), Perspective::SplitVertical } - }); - - ActionDescription desc; - desc.setText(tr("Clang Static Analyzer")); - desc.setToolTip(toolTip); - desc.setRunMode(Constants::CLANGSTATICANALYZER_RUN_MODE); - desc.setPerspectiveId(ClangStaticAnalyzerPerspectiveId); - desc.setRunControlCreator(runControlCreator); - desc.setCustomToolStarter([tool](ProjectExplorer::RunConfiguration *rc) { - tool->startTool(rc); - }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(ClangStaticAnalyzerActionId, desc); - return true; } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 5d4c1e3194d70b72d75a5a55a21d1085d4e94398..b8bc63d267b5f192fa6bd6e453e40908747e8dcb 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -304,12 +304,12 @@ static Core::Id toolchainType(ProjectExplorer::RunConfiguration *runConfiguratio return ToolChainKitInformation::toolChain(runConfiguration->target()->kit())->typeId(); } -bool ClangStaticAnalyzerRunControl::startEngine() +void ClangStaticAnalyzerRunControl::start() { m_success = false; emit starting(); - QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return false); + QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return); const Utils::FileName projectFile = m_projectInfo.project()->projectFilePath(); appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile.toUserOutput()) + QLatin1Char('\n'), Utils::NormalMessageFormat); @@ -324,7 +324,7 @@ bool ClangStaticAnalyzerRunControl::startEngine() appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage); emit finished(); - return false; + return; } m_clangExecutable = executable; @@ -337,7 +337,7 @@ bool ClangStaticAnalyzerRunControl::startEngine() appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage); emit finished(); - return false; + return; } m_clangLogFileDir = temporaryDir.path(); @@ -364,19 +364,22 @@ bool ClangStaticAnalyzerRunControl::startEngine() qCDebug(LOG) << "Environment:" << m_environment; m_runners.clear(); const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses(); - QTC_ASSERT(parallelRuns >= 1, emit finished(); return false); + QTC_ASSERT(parallelRuns >= 1, emit finished(); return); m_success = true; + m_running = true; if (m_unitsToProcess.isEmpty()) { finalize(); - return false; + return; } + + emit started(); + while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty()) analyzeNextFile(); - return true; } -void ClangStaticAnalyzerRunControl::stopEngine() +RunControl::StopResult ClangStaticAnalyzerRunControl::stop() { QSetIterator<ClangStaticAnalyzerRunner *> i(m_runners); while (i.hasNext()) { @@ -389,7 +392,14 @@ void ClangStaticAnalyzerRunControl::stopEngine() appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'), Utils::NormalMessageFormat); m_progress.reportFinished(); + m_running = false; emit finished(); + return RunControl::StoppedSynchronously; +} + +bool ClangStaticAnalyzerRunControl::isRunning() const +{ + return m_running; } void ClangStaticAnalyzerRunControl::analyzeNextFile() @@ -479,7 +489,6 @@ void ClangStaticAnalyzerRunControl::handleFinished() void ClangStaticAnalyzerRunControl::onProgressCanceled() { - Analyzer::AnalyzerManager::stopTool(); m_progress.reportCanceled(); m_progress.reportFinished(); } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h index 84ad1ae9fcec41e007eb653b03b28d2d13ed10d6..0293f4d3b19037521130dcd1135f9e2b32b1377b 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h @@ -48,7 +48,7 @@ struct AnalyzeUnit { }; typedef QList<AnalyzeUnit> AnalyzeUnits; -class ClangStaticAnalyzerRunControl : public Analyzer::AnalyzerRunControl +class ClangStaticAnalyzerRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -57,8 +57,9 @@ public: Core::Id runMode, const CppTools::ProjectInfo &projectInfo); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; + bool isRunning() const override; bool success() const { return m_success; } // For testing. @@ -93,6 +94,7 @@ private: int m_filesAnalyzed; int m_filesNotAnalyzed; bool m_success; + bool m_running = false; }; } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp index a179e2fa1fe3a561c2438cb869913a4af9b382d9..017a87cefdd5b97f5a046c1837fc2c6486fd3599 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp @@ -47,7 +47,7 @@ #include <utils/qtcassert.h> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace ClangStaticAnalyzer { @@ -115,7 +115,7 @@ RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runCo return 0; } - return AnalyzerManager::createRunControl(runConfiguration, runMode); + return Debugger::createAnalyzerRunControl(runConfiguration, runMode); } } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 93a18a1d3ffcbdf64c2cd73cc2a47155280c3656..1f5d443c6ba65bfa7b8552422c47ae7bdd8b3de3 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -53,8 +53,9 @@ #include <QSortFilterProxyModel> #include <QToolButton> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; +using namespace Utils; namespace ClangStaticAnalyzer { namespace Internal { @@ -69,14 +70,6 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent) , m_running(false) { setObjectName(QLatin1String("ClangStaticAnalyzerTool")); -} - -QWidget *ClangStaticAnalyzerTool::createWidgets() -{ - QTC_ASSERT(!m_diagnosticView, return 0); - QTC_ASSERT(!m_diagnosticModel, return 0); - QTC_ASSERT(!m_goBack, return 0); - QTC_ASSERT(!m_goNext, return 0); // // Diagnostic View @@ -104,27 +97,19 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() this, &ClangStaticAnalyzerTool::handleStateUpdate); } - AnalyzerManager::registerDockWidget(ClangStaticAnalyzerDockId, m_diagnosticView); - // // Toolbar widget // - QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - QAction *action = 0; - QToolButton *button = 0; + m_startAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); // Go to previous diagnostic - action = new QAction(this); + auto action = new QAction(this); action->setDisabled(true); action->setIcon(Core::Icons::PREV.icon()); action->setToolTip(tr("Go to previous bug.")); connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); m_goBack = action; // Go to next diagnostic @@ -133,17 +118,41 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() action->setIcon(Core::Icons::NEXT.icon()); action->setToolTip(tr("Go to next bug.")); connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); m_goNext = action; - layout->addStretch(); - - QWidget *toolbarWidget = new QWidget; - toolbarWidget->setObjectName(QLatin1String("ClangStaticAnalyzerToolBarWidget")); - toolbarWidget->setLayout(layout); - return toolbarWidget; + const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project " + "to find bugs."); + + Debugger::registerPerspective(ClangStaticAnalyzerPerspectiveId, { + tr("Clang Static Analyzer"), + {{ ClangStaticAnalyzerDockId, m_diagnosticView, {}, Perspective::SplitVertical }} + }); + + ActionDescription desc; + desc.setText(tr("Clang Static Analyzer")); + desc.setToolTip(toolTip); + desc.setRunMode(Constants::CLANGSTATICANALYZER_RUN_MODE); + desc.setPerspectiveId(ClangStaticAnalyzerPerspectiveId); + desc.setRunControlCreator([this](RunConfiguration *runConfiguration, Core::Id runMode) { + return createRunControl(runConfiguration, runMode); + }); + desc.setCustomToolStarter([this](RunConfiguration *runConfiguration) { + startTool(runConfiguration); + }); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(ClangStaticAnalyzerActionId, desc, m_startAction); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + Debugger::registerToolbar(ClangStaticAnalyzerPerspectiveId, toolbar); + + updateRunActions(); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &ClangStaticAnalyzerTool::updateRunActions); } AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration *runConfiguration, @@ -171,6 +180,11 @@ AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration * this, &ClangStaticAnalyzerTool::onNewDiagnosticsAvailable); connect(runControl, &ClangStaticAnalyzerRunControl::finished, this, &ClangStaticAnalyzerTool::onEngineFinished); + + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + m_toolBusy = true; + updateRunActions(); return runControl; } @@ -208,8 +222,6 @@ static bool dontStartAfterHintForDebugMode(Project *project) void ClangStaticAnalyzerTool::startTool(ProjectExplorer::RunConfiguration *runConfiguration) { - AnalyzerManager::showMode(); - Project *project = SessionManager::startupProject(); QTC_ASSERT(project, emit finished(false); return); @@ -261,8 +273,28 @@ void ClangStaticAnalyzerTool::onEngineFinished() m_running = false; handleStateUpdate(); emit finished(static_cast<ClangStaticAnalyzerRunControl *>(sender())->success()); + m_toolBusy = false; + updateRunActions(); } +void ClangStaticAnalyzerTool::updateRunActions() +{ + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("A Clang analysis is still in progress.")); + m_stopAction->setEnabled(true); + } else { + const bool projectUsable = SessionManager::startupProject() != 0; + m_startAction->setToolTip(tr("Start Qml Profiler.")); + if (projectUsable) { + m_startAction->setEnabled(true); + m_stopAction->setEnabled(false); + } else { + m_startAction->setEnabled(false); + m_stopAction->setEnabled(false); + } + } +} void ClangStaticAnalyzerTool::setBusyCursor(bool busy) { QTC_ASSERT(m_diagnosticView, return); @@ -291,7 +323,7 @@ void ClangStaticAnalyzerTool::handleStateUpdate() message += tr("%n issues found (%1 suppressed).", 0, issuesFound) .arg(issuesFound - issuesVisible); } - AnalyzerManager::showPermanentStatusMessage(message); + Debugger::showPermanentStatusMessage(message); } } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h index 37f5f3e75c4cbe7cd304d6a8564b4914ade8bd26..08580b395373dff4ed0726fbe461a6f3282920b7 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h @@ -56,8 +56,7 @@ public: bool isRunning() const { return m_running; } QList<Diagnostic> diagnostics() const; - QWidget *createWidgets(); - Analyzer::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, + Debugger::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); void startTool(ProjectExplorer::RunConfiguration *rc); @@ -71,6 +70,7 @@ private: void setBusyCursor(bool busy); void handleStateUpdate(); + void updateRunActions(); private: CppTools::ProjectInfo m_projectInfoBeforeBuild; @@ -79,9 +79,12 @@ private: ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel; ClangStaticAnalyzerDiagnosticView *m_diagnosticView; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QAction *m_goBack; QAction *m_goNext; bool m_running; + bool m_toolBusy = false; }; } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp index 76a063a260d54433fc1fcc105cc2efa57e9ee280..ba8814cbfa3050020e0d7bb28238e6ae7942fc5f 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp @@ -44,7 +44,7 @@ #include <QTimer> #include <QtTest> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; @@ -89,7 +89,7 @@ void ClangStaticAnalyzerUnitTests::testProject() CppTools::Tests::ProjectOpenerAndCloser projectManager; const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); QVERIFY(projectInfo.isValid()); - AnalyzerManager::selectAction(ClangStaticAnalyzerPerspectiveId, /* alsoRunIt = */ true); + Debugger::runAction(ClangStaticAnalyzerActionId); QSignalSpy waiter(m_analyzerTool, SIGNAL(finished(bool))); QVERIFY(waiter.wait(30000)); const QList<QVariant> arguments = waiter.takeFirst(); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp index 1c7af5176bac1a9d797aac7b46951e75cbe3ee7d..d800af2588d35d89470dac5dda5c967dfc278ef8 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp @@ -77,7 +77,7 @@ QString clangExecutable(const QString &fileNameOrPath, bool *isValid) return executable; } -QString createFullLocationString(const Analyzer::DiagnosticLocation &location) +QString createFullLocationString(const Debugger::DiagnosticLocation &location) { const QString filePath = location.filePath; const QString lineNumber = QString::number(location.line); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h index 63f6f6517f96ae8e0c9ba752de0c3a6e5b637554..1531d050c6d7ca290c4d502f2d66d2eebd773928 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h @@ -34,7 +34,7 @@ QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE -namespace Analyzer { class DiagnosticLocation; } +namespace Debugger { class DiagnosticLocation; } namespace ClangStaticAnalyzer { namespace Internal { @@ -44,7 +44,7 @@ bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0) QString clangExecutable(const QString &fileNameOrPath, bool *isValid); QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid); -QString createFullLocationString(const Analyzer::DiagnosticLocation &location); +QString createFullLocationString(const Debugger::DiagnosticLocation &location); } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/src/plugins/debugger/analyzer/analyzer.pri b/src/plugins/debugger/analyzer/analyzer.pri index 40da12eb3d669894c99dc261c1cf1944133d1fa9..2ae4afc59873551c96b8c2105dc1f93cfd6d655e 100644 --- a/src/plugins/debugger/analyzer/analyzer.pri +++ b/src/plugins/debugger/analyzer/analyzer.pri @@ -5,7 +5,6 @@ QT += network SOURCES += \ $$PWD/analyzerruncontrol.cpp \ - $$PWD/analyzermanager.cpp \ $$PWD/analyzerrunconfigwidget.cpp \ $$PWD/analyzerutils.cpp \ $$PWD/detailederrorview.cpp \ @@ -13,7 +12,6 @@ SOURCES += \ $$PWD/startremotedialog.cpp HEADERS += \ - $$PWD/analyzerbase_global.h \ $$PWD/analyzerconstants.h \ $$PWD/analyzerruncontrol.h \ $$PWD/analyzermanager.h \ diff --git a/src/plugins/debugger/analyzer/analyzerbase_global.h b/src/plugins/debugger/analyzer/analyzerbase_global.h deleted file mode 100644 index 4d47f89a6d428b003ab0c25492830c4b27fc23e9..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/analyzer/analyzerbase_global.h +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com) -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#ifndef ANALYZERBASE_GLOBAL_H -#define ANALYZERBASE_GLOBAL_H - -#include "../debugger_global.h" - -#define ANALYZER_EXPORT DEBUGGER_EXPORT - -#endif // ANALYZERBASE_GLOBAL_H diff --git a/src/plugins/debugger/analyzer/analyzerconstants.h b/src/plugins/debugger/analyzer/analyzerconstants.h index 8f6da351e85883150d1d692fe1ba2448dac85532..c2554f42c26dbc56661687b19aa1b72860161ccb 100644 --- a/src/plugins/debugger/analyzer/analyzerconstants.h +++ b/src/plugins/debugger/analyzer/analyzerconstants.h @@ -29,16 +29,9 @@ #include <QtGlobal> -namespace Analyzer { +namespace Debugger { namespace Constants { -// Mode and its priority. -const char MODE_ANALYZE[] = "Mode.Analyze"; -const int P_MODE_ANALYZE = 76; - -// Context. -const char C_ANALYZEMODE[] = "Analyzer.AnalyzeMode"; - // Menu. const char M_DEBUG_ANALYZER[] = "Analyzer.Menu.StartAnalyzer"; const char M_DEBUG_ANALYZER_QML_OPTIONS[] = "Analyzer.Menu.QMLOptions"; @@ -51,6 +44,6 @@ const char G_ANALYZER_OPTIONS[] = "Menu.Group.Analyzer.Options"; const char ANALYZERTASK_ID[] = "Analyzer.TaskId"; } // namespace Constants -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERCONSTANTS_H diff --git a/src/plugins/debugger/analyzer/analyzericons.h b/src/plugins/debugger/analyzer/analyzericons.h index fa8d6a8bef7802fae4fcb3423a73fb96ba6220b6..f9f4a69056bca91e005d1b117b113898c2706fdb 100644 --- a/src/plugins/debugger/analyzer/analyzericons.h +++ b/src/plugins/debugger/analyzer/analyzericons.h @@ -28,7 +28,7 @@ #include <utils/icon.h> -namespace Analyzer { +namespace Debugger { namespace Icons { const Utils::Icon ANALYZER_CONTROL_START({ @@ -42,6 +42,6 @@ const Utils::Icon MODE_ANALYZE_FLAT_ACTIVE({ {QLatin1String(":/images/mode_analyze_mask.png"), Utils::Theme::IconsModeAnalyzeActiveColor}}); } // namespace Icons -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERICONS_H diff --git a/src/plugins/debugger/analyzer/analyzermanager.cpp b/src/plugins/debugger/analyzer/analyzermanager.cpp deleted file mode 100644 index 15ab6253cd6a422246a2ffac4ffb45435fab774f..0000000000000000000000000000000000000000 --- a/src/plugins/debugger/analyzer/analyzermanager.cpp +++ /dev/null @@ -1,738 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Andreas Hartmetz, KDAB (andreas.hartmetz@kdab.com) -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "analyzermanager.h" - -#include "analyzericons.h" -#include "analyzerstartparameters.h" -#include "analyzerruncontrol.h" -#include "../debuggerplugin.h" - -#include "../debuggermainwindow.h" - -#include <coreplugin/actionmanager/actioncontainer.h> -#include <coreplugin/actionmanager/actionmanager.h> -#include <coreplugin/actionmanager/command.h> -#include <coreplugin/coreicons.h> -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/findplaceholder.h> -#include <coreplugin/icore.h> -#include <coreplugin/imode.h> -#include <coreplugin/modemanager.h> -#include <coreplugin/modemanager.h> -#include <coreplugin/navigationwidget.h> -#include <coreplugin/outputpane.h> -#include <coreplugin/rightpane.h> - -#include <projectexplorer/buildconfiguration.h> -#include <projectexplorer/project.h> -#include <projectexplorer/projectexplorer.h> -#include <projectexplorer/projectexplorericons.h> -#include <projectexplorer/session.h> -#include <projectexplorer/target.h> -#include <projectexplorer/taskhub.h> - -#include <utils/algorithm.h> -#include <utils/fancymainwindow.h> -#include <utils/styledbar.h> -#include <utils/qtcassert.h> -#include <utils/checkablemessagebox.h> -#include <utils/statuslabel.h> - -#include <QAction> -#include <QComboBox> -#include <QDebug> -#include <QDialog> -#include <QDialogButtonBox> -#include <QDockWidget> -#include <QHBoxLayout> -#include <QMenu> -#include <QPointer> -#include <QPushButton> -#include <QStackedWidget> -#include <QSettings> -#include <QToolButton> -#include <QVBoxLayout> -#include <QVariant> - -using namespace Core; -using namespace Utils; -using namespace Core::Constants; -using namespace Analyzer::Constants; -using namespace ProjectExplorer; -using namespace Debugger; -using namespace Debugger::Internal; - -namespace Analyzer { - -bool ActionDescription::isRunnable(QString *reason) const -{ - if (m_customToolStarter) // Something special. Pretend we can always run it. - return true; - - return ProjectExplorerPlugin::canRun(SessionManager::startupProject(), m_runMode, reason); -} - -static bool buildTypeAccepted(QFlags<ToolMode> toolMode, BuildConfiguration::BuildType buildType) -{ - if (buildType == BuildConfiguration::Unknown) - return true; - if (buildType == BuildConfiguration::Debug && (toolMode & DebugMode)) - return true; - if (buildType == BuildConfiguration::Release && (toolMode & ReleaseMode)) - return true; - if (buildType == BuildConfiguration::Profile && (toolMode & ProfileMode)) - return true; - return false; -} - -void ActionDescription::startTool() const -{ - // Make sure mode is shown. - AnalyzerManager::showMode(); - - TaskHub::clearTasks(Constants::ANALYZERTASK_ID); - AnalyzerManager::showPermanentStatusMessage(QString()); - - if (m_toolPreparer && !m_toolPreparer()) - return; - - // ### not sure if we're supposed to check if the RunConFiguration isEnabled - Project *pro = SessionManager::startupProject(); - RunConfiguration *rc = 0; - BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; - if (pro) { - if (const Target *target = pro->activeTarget()) { - // Build configuration is 0 for QML projects. - if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration()) - buildType = buildConfig->buildType(); - rc = target->activeRunConfiguration(); - } - } - - // Custom start. - if (m_customToolStarter) { - if (rc) { - m_customToolStarter(rc); - } else { - QMessageBox *errorDialog = new QMessageBox(ICore::mainWindow()); - errorDialog->setIcon(QMessageBox::Warning); - errorDialog->setWindowTitle(m_text); - errorDialog->setText(tr("Cannot start %1 without a project. Please open the project " - "and try again.").arg(m_text)); - errorDialog->setStandardButtons(QMessageBox::Ok); - errorDialog->setDefaultButton(QMessageBox::Ok); - errorDialog->show(); - } - return; - } - - // Check the project for whether the build config is in the correct mode - // if not, notify the user and urge him to use the correct mode. - if (!buildTypeAccepted(m_toolMode, buildType)) { - QString currentMode; - switch (buildType) { - case BuildConfiguration::Debug: - currentMode = AnalyzerManager::tr("Debug"); - break; - case BuildConfiguration::Profile: - currentMode = AnalyzerManager::tr("Profile"); - break; - case BuildConfiguration::Release: - currentMode = AnalyzerManager::tr("Release"); - break; - default: - QTC_CHECK(false); - } - - QString toolModeString; - switch (m_toolMode) { - case DebugMode: - toolModeString = AnalyzerManager::tr("in Debug mode"); - break; - case ProfileMode: - toolModeString = AnalyzerManager::tr("in Profile mode"); - break; - case ReleaseMode: - toolModeString = AnalyzerManager::tr("in Release mode"); - break; - case SymbolsMode: - toolModeString = AnalyzerManager::tr("with debug symbols (Debug or Profile mode)"); - break; - case OptimizedMode: - toolModeString = AnalyzerManager::tr("on optimized code (Profile or Release mode)"); - break; - default: - QTC_CHECK(false); - } - const QString toolName = m_text; // The action text is always the name of the tool - const QString title = AnalyzerManager::tr("Run %1 in %2 Mode?").arg(toolName).arg(currentMode); - const QString message = AnalyzerManager::tr("<html><head/><body><p>You are trying " - "to run the tool \"%1\" on an application in %2 mode. " - "The tool is designed to be used %3.</p><p>" - "Run-time characteristics differ significantly between " - "optimized and non-optimized binaries. Analytical " - "findings for one mode may or may not be relevant for " - "the other.</p><p>" - "Running tools that need debug symbols on binaries that " - "don't provide any may lead to missing function names " - "or otherwise insufficient output.</p><p>" - "Do you want to continue and run the tool in %2 mode?</p></body></html>") - .arg(toolName).arg(currentMode).arg(toolModeString); - if (Utils::CheckableMessageBox::doNotAskAgainQuestion(ICore::mainWindow(), - title, message, ICore::settings(), QLatin1String("AnalyzerCorrectModeWarning")) - != QDialogButtonBox::Yes) - return; - } - - ProjectExplorerPlugin::runStartupProject(m_runMode); -} - -namespace Internal { - -const char LAST_ACTIVE_ACTION[] = "Analyzer.Plugin.LastActiveTool"; - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerMode -// -//////////////////////////////////////////////////////////////////// - -class AnalyzerMode : public IMode -{ -public: - AnalyzerMode(QObject *parent = 0) - : IMode(parent) - { - setContext(Context(C_ANALYZEMODE, C_NAVIGATION_PANE)); - setDisplayName(AnalyzerManager::tr("Analyze")); - setIcon(Utils::Icon::modeIcon(Icons::MODE_ANALYZE_CLASSIC, - Icons::MODE_ANALYZE_FLAT, Icons::MODE_ANALYZE_FLAT_ACTIVE)); - setPriority(P_MODE_ANALYZE); - setId(MODE_ANALYZE); - } - - ~AnalyzerMode() - { - delete m_widget; - m_widget = 0; - } -}; - -} // namespace Internal - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerManagerPrivate -// -//////////////////////////////////////////////////////////////////// - -class AnalyzerManagerPrivate : public QObject -{ - Q_DECLARE_TR_FUNCTIONS(Analyzer::AnalyzerManager) - -public: - AnalyzerManagerPrivate(AnalyzerManager *qq); - - /** - * After calling this, a proper instance of IMode is initialized - * It is delayed since an analyzer mode makes no sense without analyzer tools - * - * \note Call this before adding a tool to the manager - */ - void delayedInit(); - - void setupActions(); - void createModeMainWindow(); - bool showPromptDialog(const QString &title, const QString &text, - const QString &stopButtonText, const QString &cancelButtonText) const; - - void registerAction(Core::Id actionId, const ActionDescription &desc); - void selectSavedTool(); - void selectAction(Id actionId); - void handleToolStarted(); - void handleToolFinished(); - void modeChanged(IMode *mode); - void resetLayout(); - void updateRunActions(); - -public: - AnalyzerManager *q; - Internal::AnalyzerMode *m_mode = 0; - bool m_isRunning = false; - Core::Id m_currentActionId; - QHash<Id, QAction *> m_actions; - QHash<Id, ActionDescription> m_descriptions; - QAction *m_startAction = 0; - QAction *m_stopAction = 0; - ActionContainer *m_menu = 0; - MainWindowBase *m_mainWindow; -}; - -AnalyzerManagerPrivate::AnalyzerManagerPrivate(AnalyzerManager *qq): - q(qq), m_mainWindow(new MainWindowBase) -{ - QComboBox *toolBox = m_mainWindow->toolBox(); - toolBox->setObjectName(QLatin1String("AnalyzerManagerToolBox")); - toolBox->insertSeparator(0); - connect(toolBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, [this, toolBox](int item) { - selectAction(Id::fromSetting(toolBox->itemData(item))); - }); - - setupActions(); - - ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance(); - connect(pe, &ProjectExplorerPlugin::updateRunActions, this, &AnalyzerManagerPrivate::updateRunActions); -} - -void AnalyzerManagerPrivate::setupActions() -{ - Command *command = 0; - - // Menus - m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); - m_menu->menu()->setTitle(tr("&Analyze")); - m_menu->menu()->setEnabled(true); - - m_menu->appendGroup(G_ANALYZER_CONTROL); - m_menu->appendGroup(G_ANALYZER_TOOLS); - m_menu->appendGroup(G_ANALYZER_REMOTE_TOOLS); - m_menu->appendGroup(G_ANALYZER_OPTIONS); - - ActionContainer *menubar = ActionManager::actionContainer(MENU_BAR); - ActionContainer *mtools = ActionManager::actionContainer(M_TOOLS); - menubar->addMenu(mtools, m_menu); - - m_startAction = new QAction(tr("Start"), m_menu); - m_startAction->setIcon(Analyzer::Icons::ANALYZER_CONTROL_START.icon()); - ActionManager::registerAction(m_startAction, "Analyzer.Start"); - connect(m_startAction, &QAction::triggered, this, [this] { - QTC_ASSERT(m_descriptions.contains(m_currentActionId), return); - m_descriptions.value(m_currentActionId).startTool(); - }); - - m_stopAction = new QAction(tr("Stop"), m_menu); - m_stopAction->setEnabled(false); - m_stopAction->setIcon(ProjectExplorer::Icons::STOP_SMALL.icon()); - command = ActionManager::registerAction(m_stopAction, "Analyzer.Stop"); - m_menu->addAction(command, G_ANALYZER_CONTROL); - - m_menu->addSeparator(G_ANALYZER_TOOLS); - m_menu->addSeparator(G_ANALYZER_REMOTE_TOOLS); - m_menu->addSeparator(G_ANALYZER_OPTIONS); -} - -void AnalyzerManagerPrivate::delayedInit() -{ - if (m_mode) - return; - - m_mode = new Internal::AnalyzerMode(q); - createModeMainWindow(); - - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - this, &AnalyzerManagerPrivate::modeChanged); - - // Right-side window with editor, output etc. - auto mainWindowSplitter = new MiniSplitter; - mainWindowSplitter->addWidget(m_mainWindow); - mainWindowSplitter->addWidget(new OutputPanePlaceHolder(m_mode, mainWindowSplitter)); - mainWindowSplitter->setStretchFactor(0, 10); - mainWindowSplitter->setStretchFactor(1, 0); - mainWindowSplitter->setOrientation(Qt::Vertical); - - // Navigation + right-side window. - auto splitter = new MiniSplitter; - splitter->addWidget(new NavigationWidgetPlaceHolder(m_mode)); - splitter->addWidget(mainWindowSplitter); - splitter->setStretchFactor(0, 0); - splitter->setStretchFactor(1, 1); - - auto modeContextObject = new IContext(this); - modeContextObject->setContext(Context(C_EDITORMANAGER)); - modeContextObject->setWidget(splitter); - ICore::addContextObject(modeContextObject); - m_mode->setWidget(splitter); - - Debugger::Internal::DebuggerPlugin::instance()->addAutoReleasedObject(m_mode); - - // Populate Windows->Views menu with standard actions. - Context analyzerContext(C_ANALYZEMODE); - ActionContainer *viewsMenu = ActionManager::actionContainer(M_WINDOW_VIEWS); - Command *cmd = ActionManager::registerAction(m_mainWindow->menuSeparator1(), - "Analyzer.Views.Separator1", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->autoHideTitleBarsAction(), - "Analyzer.Views.AutoHideTitleBars", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator2(), - "Analyzer.Views.Separator2", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->resetLayoutAction(), - "Analyzer.Views.ResetSimple", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); -} - -static QToolButton *toolButton(QAction *action) -{ - auto button = new QToolButton; - button->setDefaultAction(action); - return button; -} - -void AnalyzerManagerPrivate::createModeMainWindow() -{ - m_mainWindow->setObjectName(QLatin1String("AnalyzerManagerMainWindow")); - m_mainWindow->setLastSettingsName(QLatin1String(Internal::LAST_ACTIVE_ACTION)); - - auto editorHolderLayout = new QVBoxLayout; - editorHolderLayout->setMargin(0); - editorHolderLayout->setSpacing(0); - - auto editorAndFindWidget = new QWidget; - editorAndFindWidget->setLayout(editorHolderLayout); - editorHolderLayout->addWidget(new EditorManagerPlaceHolder(m_mode)); - editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); - - auto documentAndRightPane = new MiniSplitter; - documentAndRightPane->addWidget(editorAndFindWidget); - documentAndRightPane->addWidget(new RightPanePlaceHolder(m_mode)); - documentAndRightPane->setStretchFactor(0, 1); - documentAndRightPane->setStretchFactor(1, 0); - - auto analyzeToolBar = new StyledBar; - analyzeToolBar->setProperty("topBorder", true); - - auto analyzeToolBarLayout = new QHBoxLayout(analyzeToolBar); - analyzeToolBarLayout->setMargin(0); - analyzeToolBarLayout->setSpacing(0); - analyzeToolBarLayout->addWidget(toolButton(m_startAction)); - analyzeToolBarLayout->addWidget(toolButton(m_stopAction)); - analyzeToolBarLayout->addWidget(new StyledSeparator); - analyzeToolBarLayout->addWidget(m_mainWindow->toolBox()); - analyzeToolBarLayout->addWidget(m_mainWindow->controlsStack()); - analyzeToolBarLayout->addWidget(m_mainWindow->statusLabel()); - analyzeToolBarLayout->addStretch(); - - auto dock = new QDockWidget(tr("Analyzer Toolbar")); - dock->setObjectName(QLatin1String("Analyzer Toolbar")); - dock->setWidget(analyzeToolBar); - dock->setFeatures(QDockWidget::NoDockWidgetFeatures); - dock->setProperty("managed_dockwidget", QLatin1String("true")); - dock->setAllowedAreas(Qt::BottomDockWidgetArea); - // hide title bar - dock->setTitleBarWidget(new QWidget(dock)); - m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock); - m_mainWindow->setToolBarDockWidget(dock); - - auto centralWidget = new QWidget; - m_mainWindow->setCentralWidget(centralWidget); - - auto centralLayout = new QVBoxLayout(centralWidget); - centralWidget->setLayout(centralLayout); - centralLayout->setMargin(0); - centralLayout->setSpacing(0); - centralLayout->addWidget(documentAndRightPane); - centralLayout->setStretch(0, 1); - centralLayout->setStretch(1, 0); -} - -bool AnalyzerManagerPrivate::showPromptDialog(const QString &title, const QString &text, - const QString &stopButtonText, const QString &cancelButtonText) const -{ - CheckableMessageBox messageBox(ICore::mainWindow()); - messageBox.setWindowTitle(title); - messageBox.setText(text); - messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel); - if (!stopButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText); - if (!cancelButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText); - messageBox.setDefaultButton(QDialogButtonBox::Yes); - messageBox.setCheckBoxVisible(false); - messageBox.exec(); - return messageBox.clickedStandardButton() == QDialogButtonBox::Yes; -} - -void AnalyzerManagerPrivate::modeChanged(IMode *mode) -{ - if (mode && mode == m_mode) { - m_mainWindow->setDockActionsVisible(true); - static bool firstTime = !m_currentActionId.isValid(); - if (firstTime) - selectSavedTool(); - firstTime = false; - updateRunActions(); - } else { - m_mainWindow->setDockActionsVisible(false); - } -} - -void AnalyzerManagerPrivate::selectSavedTool() -{ - const QSettings *settings = ICore::settings(); - - if (settings->contains(QLatin1String(Internal::LAST_ACTIVE_ACTION))) { - const Id lastAction = Id::fromSetting(settings->value(QLatin1String(Internal::LAST_ACTIVE_ACTION))); - selectAction(lastAction); - } - // fallback to first available tool - if (!m_descriptions.isEmpty()) - selectAction(m_descriptions.begin().key()); -} - -void AnalyzerManagerPrivate::selectAction(Id actionId) -{ - QTC_ASSERT(m_descriptions.contains(actionId), return); - if (m_currentActionId == actionId) - return; - - // Now change the tool. - m_currentActionId = actionId; - ActionDescription desc = m_descriptions.value(actionId); - - m_mainWindow->restorePerspective(desc.perspectiveId()); - - const int toolboxIndex = m_mainWindow->toolBox()->findText(desc.text()); - QTC_ASSERT(toolboxIndex >= 0, return); - m_mainWindow->toolBox()->setCurrentIndex(toolboxIndex); - - updateRunActions(); -} - -void AnalyzerManagerPrivate::registerAction(Id actionId, const ActionDescription &desc) -{ - delayedInit(); // Make sure that there is a valid IMode instance. - - auto action = new QAction(this); - action->setText(desc.text()); - action->setToolTip(desc.toolTip()); - m_actions.insert(actionId, action); - m_descriptions.insert(actionId, desc); - - int index = -1; - if (desc.menuGroup() == Constants::G_ANALYZER_REMOTE_TOOLS) { - index = m_mainWindow->toolBox()->count(); - } else if (desc.menuGroup() == Constants::G_ANALYZER_TOOLS) { - for (int i = m_mainWindow->toolBox()->count(); --i >= 0; ) - if (m_mainWindow->toolBox()->itemText(i).isEmpty()) - index = i; - } - - if (index >= 0) - m_mainWindow->toolBox()->insertItem(index, desc.text(), actionId.toSetting()); - - Id menuGroup = desc.menuGroup(); - if (menuGroup.isValid()) { - Command *command = ActionManager::registerAction(action, actionId); - m_menu->addAction(command, menuGroup); - } - - connect(action, &QAction::triggered, this, [this, desc, actionId] { - selectAction(actionId); - desc.startTool(); - }); -} - -void AnalyzerManagerPrivate::handleToolStarted() -{ - m_isRunning = true; // FIXME: Make less global. - updateRunActions(); -} - -void AnalyzerManagerPrivate::handleToolFinished() -{ - m_isRunning = false; - updateRunActions(); -} - -void AnalyzerManagerPrivate::updateRunActions() -{ - QString disabledReason; - bool enabled = false; - if (m_isRunning) - disabledReason = tr("An analysis is still in progress."); - else if (m_currentActionId.isValid()) - enabled = m_descriptions.value(m_currentActionId).isRunnable(&disabledReason); - else - disabledReason = tr("No analyzer tool selected."); - - m_startAction->setEnabled(enabled); - m_startAction->setToolTip(disabledReason); - m_mainWindow->toolBox()->setEnabled(!m_isRunning); - m_stopAction->setEnabled(m_isRunning); - - for (auto it = m_actions.begin(), end = m_actions.end(); it != end; ++it) - it.value()->setEnabled(!m_isRunning && m_descriptions.value(it.key()).isRunnable()); -} - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerManager -// -//////////////////////////////////////////////////////////////////// - -static AnalyzerManagerPrivate *d = 0; - -AnalyzerManager::AnalyzerManager(QObject *parent) - : QObject(parent) -{ - QTC_CHECK(d == 0); - d = new AnalyzerManagerPrivate(this); -} - -AnalyzerManager::~AnalyzerManager() -{ - QTC_CHECK(d); - delete d; - d = 0; -} - -void AnalyzerManager::shutdown() -{ - d->m_mainWindow->saveCurrentPerspective(); -} - -void AnalyzerManager::registerAction(Id actionId, const ActionDescription &desc) -{ - d->registerAction(actionId, desc); -} - -void AnalyzerManager::registerDockWidget(Id dockId, QWidget *widget) -{ - QTC_ASSERT(!widget->objectName().isEmpty(), return); - QDockWidget *dockWidget = d->m_mainWindow->registerDockWidget(dockId, widget); - - QAction *toggleViewAction = dockWidget->toggleViewAction(); - toggleViewAction->setText(dockWidget->windowTitle()); - - Command *cmd = ActionManager::registerAction(toggleViewAction, - Id("Analyzer.").withSuffix(dockWidget->objectName())); - cmd->setAttribute(Command::CA_Hide); - - ActionContainer *viewsMenu = ActionManager::actionContainer(Id(M_WINDOW_VIEWS)); - viewsMenu->addAction(cmd); -} - -void AnalyzerManager::registerToolbar(Id toolbarId, QWidget *widget) -{ - d->m_mainWindow->registerToolbar(toolbarId, widget); -} - -Perspective::Operation::Operation(Id dockId, Id existing, Perspective::OperationType operationType, - bool visibleByDefault, Qt::DockWidgetArea area) - : dockId(dockId), existing(existing), operationType(operationType), - visibleByDefault(visibleByDefault), area(area) -{} - -Perspective::Perspective(std::initializer_list<Perspective::Operation> operations) - : m_operations(operations) -{ - for (const Operation &operation : operations) - m_docks.append(operation.dockId); -} - -void Perspective::addOperation(const Operation &operation) -{ - m_docks.append(operation.dockId); - m_operations.append(operation); -} - -void AnalyzerManager::registerPerspective(Id perspectiveId, const Perspective &perspective) -{ - d->m_mainWindow->registerPerspective(perspectiveId, perspective); -} - -void AnalyzerManager::selectAction(Id actionId, bool alsoRunIt) -{ - d->selectAction(actionId); - if (alsoRunIt) - d->m_descriptions.value(actionId).startTool(); -} - -void AnalyzerManager::enableMainWindow(bool on) -{ - d->m_mainWindow->setEnabled(on); -} - -void AnalyzerManager::showStatusMessage(const QString &message, int timeoutMS) -{ - d->m_mainWindow->showStatusMessage(message, timeoutMS); -} - -void AnalyzerManager::showPermanentStatusMessage(const QString &message) -{ - d->m_mainWindow->showStatusMessage(message, -1); -} - -void AnalyzerManager::showMode() -{ - if (d->m_mode) - ModeManager::activateMode(d->m_mode->id()); -} - -void AnalyzerManager::stopTool() -{ - stopAction()->trigger(); -} - -QAction *AnalyzerManager::stopAction() -{ - return d->m_stopAction; -} - -void AnalyzerManager::handleToolStarted() -{ - d->handleToolStarted(); -} - -void AnalyzerManager::handleToolFinished() -{ - d->handleToolFinished(); -} - -AnalyzerRunControl *AnalyzerManager::createRunControl(RunConfiguration *runConfiguration, Id runMode) -{ - foreach (const ActionDescription &action, d->m_descriptions) { - if (action.runMode() == runMode) - return action.runControlCreator()(runConfiguration, runMode); - } - return 0; -} - -bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2) -{ - return c1.connParams == c2.connParams - && c1.analyzerHost == c2.analyzerHost - && c1.analyzerSocket == c2.analyzerSocket - && c1.analyzerPort == c2.analyzerPort; -} - -} // namespace Analyzer diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h index d4bfd35ab53eaa1cd5c8bfe412f61b8f9923a23b..70209ea291497880aa39cb105657a4a94dcc6d5c 100644 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ b/src/plugins/debugger/analyzer/analyzermanager.h @@ -27,7 +27,6 @@ #ifndef ANALYZERMANAGER_H #define ANALYZERMANAGER_H -#include "analyzerbase_global.h" #include "analyzerconstants.h" #include "../debuggermainwindow.h" @@ -48,7 +47,7 @@ QT_END_NAMESPACE namespace ProjectExplorer { class RunConfiguration; } -namespace Analyzer { +namespace Debugger { class AnalyzerRunControl; @@ -75,9 +74,9 @@ Q_DECLARE_FLAGS(ToolModes, ToolMode) * */ -class ANALYZER_EXPORT ActionDescription +class DEBUGGER_EXPORT ActionDescription { - Q_DECLARE_TR_FUNCTIONS(Analyzer::AnalyzerAction) + Q_DECLARE_TR_FUNCTIONS(Debugger::AnalyzerAction) public: ActionDescription() {} @@ -85,8 +84,8 @@ public: Core::Id menuGroup() const { return m_menuGroup; } void setMenuGroup(Core::Id menuGroup) { m_menuGroup = menuGroup; } - Core::Id perspectiveId() const { return m_perspective; } - void setPerspectiveId(Core::Id id) { m_perspective = id; } + QByteArray perspectiveId() const { return m_perspectiveId; } + void setPerspectiveId(const QByteArray &id) { m_perspectiveId = id; } void setToolMode(QFlags<ToolMode> mode) { m_toolMode = mode; } Core::Id runMode() const { return m_runMode; } @@ -120,7 +119,7 @@ private: QString m_text; QString m_toolTip; Core::Id m_menuGroup; - Core::Id m_perspective; + QByteArray m_perspectiveId; QFlags<ToolMode> m_toolMode = AnyMode; Core::Id m_runMode; RunControlCreator m_runControlCreator; @@ -128,41 +127,28 @@ private: ToolPreparer m_toolPreparer; }; -// FIXME: Merge with AnalyzerPlugin. -class ANALYZER_EXPORT AnalyzerManager : public QObject -{ - Q_OBJECT - -public: - explicit AnalyzerManager(QObject *parent); - ~AnalyzerManager(); +// FIXME: Merge with something sensible. - static void shutdown(); +// Register a tool for a given start mode. +DEBUGGER_EXPORT void registerAction(Core::Id actionId, const ActionDescription &desc, QAction *startAction = 0); +DEBUGGER_EXPORT void registerPerspective(const QByteArray &perspectiveId, const Utils::Perspective &perspective); +DEBUGGER_EXPORT void registerToolbar(const QByteArray &perspectiveId, const Utils::ToolbarDescription &desc); - // Register a tool for a given start mode. - static void registerAction(Core::Id actionId, const ActionDescription &desc); - static void registerPerspective(Core::Id perspectiveId, const Perspective &perspective); - static void registerDockWidget(Core::Id dockId, QWidget *widget); - static void registerToolbar(Core::Id toolbarId, QWidget *widget); +DEBUGGER_EXPORT void enableMainWindow(bool on); - static void enableMainWindow(bool on); +DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId); +DEBUGGER_EXPORT void runAction(Core::Id actionId); - static void showMode(); - static void selectAction(Core::Id actionId, bool alsoRunIt = false); - static void stopTool(); +// Convenience functions. +DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000); +DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message); - // Convenience functions. - static void showStatusMessage(const QString &message, int timeoutMS = 10000); - static void showPermanentStatusMessage(const QString &message); +DEBUGGER_EXPORT QAction *createStartAction(); +DEBUGGER_EXPORT QAction *createStopAction(); - static void handleToolStarted(); - static void handleToolFinished(); - static QAction *stopAction(); - - static AnalyzerRunControl *createRunControl( - ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); -}; +DEBUGGER_EXPORT AnalyzerRunControl *createAnalyzerRunControl( + ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERMANAGER_H diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp index 9504ebce9fb234c91f10a28eb607caac4d5341b6..94e0314d5ab75f76091043817b1c238267e96d66 100644 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp +++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp @@ -36,7 +36,7 @@ #include <QComboBox> #include <QPushButton> -namespace Analyzer { +namespace Debugger { AnalyzerRunConfigWidget::AnalyzerRunConfigWidget(ProjectExplorer::IRunConfigurationAspect *aspect) { @@ -105,4 +105,4 @@ void AnalyzerRunConfigWidget::restoreGlobal() m_aspect->resetProjectToGlobalSettings(); } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h index aa18b74156dd7a5d6e011f914b21ff06166029a2..ad4ba8cc2d33d54d486bfee00af63a9dccfb821d 100644 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h +++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h @@ -27,7 +27,7 @@ #ifndef ANALYZERRUNCONFIGWIDGET_H #define ANALYZERRUNCONFIGWIDGET_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <projectexplorer/runconfiguration.h> @@ -38,9 +38,9 @@ QT_END_NAMESPACE namespace Utils { class DetailsWidget; } -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT AnalyzerRunConfigWidget : public ProjectExplorer::RunConfigWidget +class DEBUGGER_EXPORT AnalyzerRunConfigWidget : public ProjectExplorer::RunConfigWidget { Q_OBJECT @@ -62,6 +62,6 @@ private: Utils::DetailsWidget *m_details; }; -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERRUNCONFIGWIDGET_H diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.cpp b/src/plugins/debugger/analyzer/analyzerruncontrol.cpp index 9d4957e54f2f87f2c744ca4c148bcee002db8b33..18e74abe185faa6e5778a974ac995c604a1fc0d8 100644 --- a/src/plugins/debugger/analyzer/analyzerruncontrol.cpp +++ b/src/plugins/debugger/analyzer/analyzerruncontrol.cpp @@ -37,60 +37,12 @@ using namespace ProjectExplorer; -////////////////////////////////////////////////////////////////////////// -// -// AnalyzerRunControl -// -////////////////////////////////////////////////////////////////////////// - -namespace Analyzer { +namespace Debugger { AnalyzerRunControl::AnalyzerRunControl(RunConfiguration *runConfiguration, Core::Id runMode) : RunControl(runConfiguration, runMode) { setIcon(Icons::ANALYZER_CONTROL_START); - - connect(this, &AnalyzerRunControl::finished, - this, &AnalyzerRunControl::runControlFinished); - connect(AnalyzerManager::stopAction(), &QAction::triggered, - this, &AnalyzerRunControl::stopIt); -} - -void AnalyzerRunControl::stopIt() -{ - if (stop() == RunControl::StoppedSynchronously) - AnalyzerManager::handleToolFinished(); -} - -void AnalyzerRunControl::runControlFinished() -{ - m_isRunning = false; - AnalyzerManager::handleToolFinished(); -} - -void AnalyzerRunControl::start() -{ - AnalyzerManager::handleToolStarted(); - - if (startEngine()) { - m_isRunning = true; - emit started(); - } -} - -RunControl::StopResult AnalyzerRunControl::stop() -{ - if (!m_isRunning) - return StoppedSynchronously; - - stopEngine(); - m_isRunning = false; - return AsynchronousStop; -} - -bool AnalyzerRunControl::isRunning() const -{ - return m_isRunning; } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.h b/src/plugins/debugger/analyzer/analyzerruncontrol.h index d13adc98b76826389e2cf9414d32a18fece183d7..a919a7f36388c0a3faf5e0fc87b59f2b6bedbb10 100644 --- a/src/plugins/debugger/analyzer/analyzerruncontrol.h +++ b/src/plugins/debugger/analyzer/analyzerruncontrol.h @@ -27,31 +27,26 @@ #ifndef ANALYZERRUNCONTROL_H #define ANALYZERRUNCONTROL_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <projectexplorer/runconfiguration.h> #include <utils/outputformat.h> -namespace Analyzer { +namespace Debugger { /** * An AnalyzerRunControl instance handles the launch of an analyzation tool. * * It gets created for each launch and deleted when the launch is stopped or ended. */ -class ANALYZER_EXPORT AnalyzerRunControl : public ProjectExplorer::RunControl +class DEBUGGER_EXPORT AnalyzerRunControl : public ProjectExplorer::RunControl { Q_OBJECT public: AnalyzerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - /// Start analyzation process. - virtual bool startEngine() = 0; - /// Trigger async stop of the analyzation process. - virtual void stopEngine() = 0; - /// Controller actions. virtual bool canPause() const { return false; } virtual void pause() {} @@ -60,28 +55,16 @@ public: virtual void notifyRemoteSetupDone(quint16) {} virtual void notifyRemoteFinished() {} - // ProjectExplorer::RunControl - void start() override; - StopResult stop() override; - bool isRunning() const override; +signals: + void starting(); public slots: virtual void logApplicationMessage(const QString &, Utils::OutputFormat) { } -private slots: - void stopIt(); - void runControlFinished(); - -signals: - /// Must be emitted when the engine is starting. - void starting(); - private: bool supportsReRunning() const override { return false; } - -protected: - bool m_isRunning; }; -} // namespace Analyzer + +} // namespace Debugger #endif // ANALYZERRUNCONTROL_H diff --git a/src/plugins/debugger/analyzer/analyzerstartparameters.h b/src/plugins/debugger/analyzer/analyzerstartparameters.h index 1b4a3a6bdff41ed3fbf94ec7b8320fa11984d15a..73226c0e33e609dec37b183030f7235680ac685a 100644 --- a/src/plugins/debugger/analyzer/analyzerstartparameters.h +++ b/src/plugins/debugger/analyzer/analyzerstartparameters.h @@ -26,16 +26,16 @@ #ifndef ANALYZERSTARTPARAMETERS_H #define ANALYZERSTARTPARAMETERS_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <projectexplorer/runnables.h> #include <ssh/sshconnection.h> #include <QMetaType> -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT AnalyzerConnection +class DEBUGGER_EXPORT AnalyzerConnection { public: QSsh::SshConnectionParameters connParams; @@ -44,8 +44,8 @@ public: quint16 analyzerPort = 0; }; -ANALYZER_EXPORT bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2); +DEBUGGER_EXPORT bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2); -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERSTARTPARAMETERS_H diff --git a/src/plugins/debugger/analyzer/analyzerutils.cpp b/src/plugins/debugger/analyzer/analyzerutils.cpp index cafafa1f114059ef0389248e8dc8ae84ceae54d7..c38e54bb4546efba2c0d2951e1f69bc0b0222a2b 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.cpp +++ b/src/plugins/debugger/analyzer/analyzerutils.cpp @@ -39,7 +39,7 @@ #include <QTextCursor> -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace ProjectExplorer; @@ -92,7 +92,7 @@ CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() void AnalyzerUtils::logToIssuesPane(Task::TaskType type, const QString &message) { - TaskHub::addTask(type, message, Analyzer::Constants::ANALYZERTASK_ID); + TaskHub::addTask(type, message, Debugger::Constants::ANALYZERTASK_ID); if (type == Task::Error) TaskHub::requestPopup(); } diff --git a/src/plugins/debugger/analyzer/analyzerutils.h b/src/plugins/debugger/analyzer/analyzerutils.h index e173c58d1e5d04313816c2f1586a697ca33ebef1..65f3de5f304c077f4315e3d4d22f1c8144739b86 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.h +++ b/src/plugins/debugger/analyzer/analyzerutils.h @@ -26,7 +26,7 @@ #ifndef ANALYZERUTILS_H #define ANALYZERUTILS_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <projectexplorer/task.h> @@ -34,8 +34,8 @@ namespace CPlusPlus { class Symbol; } namespace AnalyzerUtils { - ANALYZER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); - ANALYZER_EXPORT void logToIssuesPane(ProjectExplorer::Task::TaskType type, + DEBUGGER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); + DEBUGGER_EXPORT void logToIssuesPane(ProjectExplorer::Task::TaskType type, const QString &message); } diff --git a/src/plugins/debugger/analyzer/detailederrorview.cpp b/src/plugins/debugger/analyzer/detailederrorview.cpp index c539102c4f1120944e54523ede50b246fec7dec5..7a47e40857605c59d21d7f6771cae24f98eeb949 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.cpp +++ b/src/plugins/debugger/analyzer/detailederrorview.cpp @@ -44,7 +44,7 @@ #include <QSharedPointer> #include <QTextDocument> -namespace Analyzer { +namespace Debugger { namespace Internal { class DetailedErrorDelegate : public QStyledItemDelegate @@ -138,8 +138,7 @@ DetailedErrorView::DetailedErrorView(QWidget *parent) : }); connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) { if (index.column() == LocationColumn) { - const auto loc = index.model() - ->data(index, Analyzer::DetailedErrorView::LocationRole) + const auto loc = index.model()->data(index, DetailedErrorView::LocationRole) .value<DiagnosticLocation>(); if (loc.isValid()) Core::EditorManager::openEditorAt(loc.filePath, loc.line, loc.column - 1); @@ -212,6 +211,6 @@ void DetailedErrorView::setCurrentRow(int row) scrollTo(index); } -} // namespace Analyzer +} // namespace Debugger #include "detailederrorview.moc" diff --git a/src/plugins/debugger/analyzer/detailederrorview.h b/src/plugins/debugger/analyzer/detailederrorview.h index 485e082e08e9aedc1c151ceffa660c42d00c3ecd..ab141ad57ecfb3bcc0cc4f1756a25b248ce08399 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.h +++ b/src/plugins/debugger/analyzer/detailederrorview.h @@ -26,14 +26,14 @@ #ifndef DETAILEDERRORVIEW_H #define DETAILEDERRORVIEW_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <QTreeView> #include <QStyledItemDelegate> -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT DetailedErrorView : public QTreeView +class DEBUGGER_EXPORT DetailedErrorView : public QTreeView { Q_OBJECT @@ -67,6 +67,6 @@ private: QAction * const m_copyAction; }; -} // namespace Analyzer +} // namespace Debugger #endif // DETAILEDERRORVIEW_H diff --git a/src/plugins/debugger/analyzer/diagnosticlocation.cpp b/src/plugins/debugger/analyzer/diagnosticlocation.cpp index 7fa15f83c8412b15ba683f3b6cd302719693ad0c..e5f6c8ee4957908b9c176be5aca7d0ef34305d28 100644 --- a/src/plugins/debugger/analyzer/diagnosticlocation.cpp +++ b/src/plugins/debugger/analyzer/diagnosticlocation.cpp @@ -25,7 +25,7 @@ #include "diagnosticlocation.h" -namespace Analyzer { +namespace Debugger { DiagnosticLocation::DiagnosticLocation() : line(0), column(0) { @@ -56,5 +56,5 @@ QDebug operator<<(QDebug dbg, const DiagnosticLocation &location) return dbg.space(); } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/diagnosticlocation.h b/src/plugins/debugger/analyzer/diagnosticlocation.h index 497698413dd22a2ca6c85836905169ccdca8b67b..61fdbe2298875460078f6225b3b58da986269a2f 100644 --- a/src/plugins/debugger/analyzer/diagnosticlocation.h +++ b/src/plugins/debugger/analyzer/diagnosticlocation.h @@ -26,15 +26,15 @@ #ifndef ANALYZERDIAGNOSTIC_H #define ANALYZERDIAGNOSTIC_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <QDebug> #include <QMetaType> #include <QString> -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT DiagnosticLocation +class DEBUGGER_EXPORT DiagnosticLocation { public: DiagnosticLocation(); @@ -49,12 +49,12 @@ public: int column; }; -ANALYZER_EXPORT bool operator==(const DiagnosticLocation &first, const DiagnosticLocation &second); -ANALYZER_EXPORT QDebug operator<<(QDebug dbg, const DiagnosticLocation &location); +DEBUGGER_EXPORT bool operator==(const DiagnosticLocation &first, const DiagnosticLocation &second); +DEBUGGER_EXPORT QDebug operator<<(QDebug dbg, const DiagnosticLocation &location); -} // namespace Analyzer +} // namespace Debugger -Q_DECLARE_METATYPE(Analyzer::DiagnosticLocation) +Q_DECLARE_METATYPE(Debugger::DiagnosticLocation) #endif // Include guard. diff --git a/src/plugins/debugger/analyzer/startremotedialog.cpp b/src/plugins/debugger/analyzer/startremotedialog.cpp index 79c37c390ff39f52ea3f1353cb799d0ad1f788f5..8616ab2f782f33c7169c63d1e3a7c18dc345c09b 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.cpp +++ b/src/plugins/debugger/analyzer/startremotedialog.cpp @@ -41,7 +41,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace Analyzer { +namespace Debugger { namespace Internal { class StartRemoteDialogPrivate @@ -146,4 +146,4 @@ StandardRunnable StartRemoteDialog::runnable() const return r; } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/startremotedialog.h b/src/plugins/debugger/analyzer/startremotedialog.h index f6694d08efcbdabf0b39723282ffa84c308e6a9f..ff559a51bf0112fe2a0e0d5b86b9593eb34427a7 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.h +++ b/src/plugins/debugger/analyzer/startremotedialog.h @@ -26,7 +26,7 @@ #ifndef STARTREMOTEDIALOG_H #define STARTREMOTEDIALOG_H -#include "analyzerbase_global.h" +#include <debugger/debugger_global.h> #include <QDialog> @@ -34,29 +34,28 @@ namespace QSsh { class SshConnectionParameters; } namespace ProjectExplorer { class StandardRunnable; } -namespace Analyzer { +namespace Debugger { namespace Internal { class StartRemoteDialogPrivate; } -class ANALYZER_EXPORT StartRemoteDialog : public QDialog +class DEBUGGER_EXPORT StartRemoteDialog : public QDialog { Q_OBJECT public: explicit StartRemoteDialog(QWidget *parent = 0); - ~StartRemoteDialog(); + ~StartRemoteDialog() override; QSsh::SshConnectionParameters sshParams() const; ProjectExplorer::StandardRunnable runnable() const; -private slots: +private: void validate(); - virtual void accept(); + void accept() override; -private: Internal::StartRemoteDialogPrivate *d; }; -} // namespace Analyzer +} // namespace Debugger #endif // STARTREMOTEDIALOG_H diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index f9317178bb1569ee6462ec3fd8ab61db9a07e6b4..c323cf6cb71ccc5b46edffb82166f87c48a9b73f 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -32,6 +32,7 @@ #include <debugger/breakhandler.h> #include <debugger/debuggeractions.h> #include <debugger/debuggercore.h> +#include <debugger/debuggerinternalconstants.h> #include <debugger/debuggerprotocol.h> #include <debugger/debuggermainwindow.h> #include <debugger/debuggerstartparameters.h> diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 9a927632f1f5e3ef2727a1e0d34c0946c112a8b9..df08a58de4d27a470cc97fa41cb4500d8b28ed65 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -234,10 +234,8 @@ QtcPlugin { files: [ "analyzer/analyzerbase.qrc", - "analyzer/analyzerbase_global.h", "analyzer/analyzerconstants.h", "analyzer/analyzericons.h", - "analyzer/analyzermanager.cpp", "analyzer/analyzermanager.h", "analyzer/analyzerrunconfigwidget.cpp", "analyzer/analyzerrunconfigwidget.h", diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index b5966c352096ff99b9543a56251aa2230d7a0a78..5964860883edca80544122b828cfecdfff09718b 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -39,6 +39,9 @@ const char C_DEBUGMODE[] = "Debugger.DebugMode"; const char C_CPPDEBUGGER[] = "Gdb Debugger"; const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger"; +const char CppPerspectiveId[] = "Debugger.Perspective.Cpp"; +const char QmlPerspectiveId[] = "Debugger.Perspective.Qml"; + // Menu Groups const char G_GENERAL[] = "Debugger.Group.General"; const char G_SPECIAL[] = "Debugger.Group.Special"; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index 7431f4cab5803dace14ecc4af221a2325e069c9b..023278d4271bcaa65f59decb58876340d4baf354 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -74,7 +74,6 @@ bool isReverseDebugging(); void runControlStarted(DebuggerEngine *engine); void runControlFinished(DebuggerEngine *engine); void displayDebugger(DebuggerEngine *engine, bool updateEngine); -DebuggerLanguages activeLanguages(); void synchronizeBreakpoints(); QWidget *mainWindow(); diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index 89afc314f66c85fe85eeb141efe4efc179ab77e7..3b9f65977ce320bd30a9742ae4db7ca96a1c8a92 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -29,6 +29,21 @@ #include <QtGlobal> namespace Debugger { +namespace Internal { + +// DebuggerMainWindow dock widget names +const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; +const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules"; +const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register"; +const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output"; +const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots"; +const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack"; +const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles"; +const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads"; +const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.LocalsAndWatchers"; + +} // namespace Internal + namespace Constants { const char DEBUGGER_COMMON_SETTINGS_ID[] = "A.Debugger.General"; diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index dbcfe449ae8c2cee234d6e03dc70d765265f77fd..b0970d70c8bba77a4a1a6f67d7cd52bd15088d7a 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -24,37 +24,65 @@ ****************************************************************************/ #include "debuggermainwindow.h" +#include "debuggerconstants.h" +#include "debuggerinternalconstants.h" +#include "analyzer/analyzericons.h" +#include <coreplugin/actionmanager/actioncontainer.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/actionmanager/command.h> +#include <coreplugin/coreconstants.h> #include <coreplugin/icore.h> +#include <projectexplorer/projectexplorericons.h> + +#include <utils/styledbar.h> #include <utils/qtcassert.h> +#include <QAction> #include <QComboBox> #include <QDockWidget> +#include <QHBoxLayout> +#include <QMenu> #include <QStackedWidget> +#include <QToolButton> -using namespace Analyzer; +using namespace Debugger; using namespace Core; -using namespace Utils; -namespace Debugger { -namespace Internal { +namespace Utils { + +const char LAST_PERSPECTIVE_KEY[] = "LastPerspective"; -MainWindowBase::MainWindowBase() +DebuggerMainWindow::DebuggerMainWindow() { m_controlsStackWidget = new QStackedWidget; m_statusLabel = new Utils::StatusLabel; - m_toolBox = new QComboBox; + + m_perspectiveChooser = new QComboBox; + m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser")); + connect(m_perspectiveChooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), + this, [this](int item) { restorePerspective(m_perspectiveChooser->itemData(item).toByteArray()); }); setDockNestingEnabled(true); setDockActionsVisible(false); setDocumentMode(true); connect(this, &FancyMainWindow::resetLayout, - this, &MainWindowBase::resetCurrentPerspective); + this, &DebuggerMainWindow::resetCurrentPerspective); + + auto dock = new QDockWidget(tr("Toolbar")); + dock->setObjectName(QLatin1String("Toolbar")); + dock->setFeatures(QDockWidget::NoDockWidgetFeatures); + dock->setAllowedAreas(Qt::BottomDockWidgetArea); + dock->setTitleBarWidget(new QWidget(dock)); // hide title bar + dock->setProperty("managed_dockwidget", QLatin1String("true")); + + addDockWidget(Qt::BottomDockWidgetArea, dock); + setToolBarDockWidget(dock); } -MainWindowBase::~MainWindowBase() +DebuggerMainWindow::~DebuggerMainWindow() { // as we have to setParent(0) on dock widget that are not selected, // we keep track of all and make sure we don't leak any @@ -64,64 +92,155 @@ MainWindowBase::~MainWindowBase() } } -void MainWindowBase::registerPerspective(Id perspectiveId, const Perspective &perspective) +void DebuggerMainWindow::registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective) { m_perspectiveForPerspectiveId.insert(perspectiveId, perspective); + m_perspectiveChooser->addItem(perspective.name(), perspectiveId); } -void MainWindowBase::registerToolbar(Id perspectiveId, QWidget *widget) +void DebuggerMainWindow::registerToolbar(const QByteArray &perspectiveId, QWidget *widget) { m_toolbarForPerspectiveId.insert(perspectiveId, widget); m_controlsStackWidget->addWidget(widget); } -void MainWindowBase::showStatusMessage(const QString &message, int timeoutMS) +void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS) { m_statusLabel->showStatusMessage(message, timeoutMS); } -void MainWindowBase::resetCurrentPerspective() +QDockWidget *DebuggerMainWindow::dockWidget(const QByteArray &dockId) const +{ + return m_dockForDockId.value(dockId); +} + +void DebuggerMainWindow::resetCurrentPerspective() { loadPerspectiveHelper(m_currentPerspectiveId, false); } -void MainWindowBase::restorePerspective(Id perspectiveId) +void DebuggerMainWindow::restorePerspective(const QByteArray &perspectiveId) { loadPerspectiveHelper(perspectiveId, true); + + int index = m_perspectiveChooser->findData(perspectiveId); + if (index == -1) + index = m_perspectiveChooser->findData(m_currentPerspectiveId); + if (index != -1) + m_perspectiveChooser->setCurrentIndex(index); } -void MainWindowBase::loadPerspectiveHelper(Id perspectiveId, bool fromStoredSettings) +void DebuggerMainWindow::finalizeSetup() { - QTC_ASSERT(perspectiveId.isValid(), return); + auto viewButton = new QToolButton; + viewButton->setText(tr("Views")); + + auto toolbar = new Utils::StyledBar; + toolbar->setProperty("topBorder", true); + auto hbox = new QHBoxLayout(toolbar); + hbox->setMargin(0); + hbox->setSpacing(0); + hbox->addWidget(m_perspectiveChooser); + hbox->addWidget(m_controlsStackWidget); + hbox->addWidget(m_statusLabel); + hbox->addWidget(new Utils::StyledSeparator); + hbox->addStretch(); + hbox->addWidget(viewButton); + + connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { + QMenu menu; + addDockActionsToMenu(&menu); + menu.exec(viewButton->mapToGlobal(QPoint())); + }); + + toolBarDockWidget()->setWidget(toolbar); + Context debugcontext(Debugger::Constants::C_DEBUGMODE); + + ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS); + Command *cmd = ActionManager::registerAction(menuSeparator1(), + "Debugger.Views.Separator1", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(autoHideTitleBarsAction(), + "Debugger.Views.AutoHideTitleBars", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(menuSeparator2(), + "Debugger.Views.Separator2", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(resetLayoutAction(), + "Debugger.Views.ResetSimple", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + + addDockActionsToMenu(viewsMenu->menu()); +} + +void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings) +{ // Clean up old perspective. - closeCurrentPerspective(); + if (!m_currentPerspectiveId.isEmpty()) { + saveCurrentPerspective(); + foreach (QDockWidget *dockWidget, m_dockForDockId) { + QTC_ASSERT(dockWidget, continue); + removeDockWidget(dockWidget); + dockWidget->hide(); + // Prevent saveState storing the data of the wrong children. + dockWidget->setParent(0); + } + + ICore::removeAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); + } m_currentPerspectiveId = perspectiveId; - QTC_ASSERT(m_perspectiveForPerspectiveId.contains(perspectiveId), return); - const auto operations = m_perspectiveForPerspectiveId.value(perspectiveId).operations(); + if (m_currentPerspectiveId.isEmpty()) { + const QSettings *settings = ICore::settings(); + m_currentPerspectiveId = settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray(); + if (m_currentPerspectiveId.isEmpty()) + m_currentPerspectiveId = Debugger::Constants::CppPerspectiveId; + } + + ICore::addAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); + + QTC_ASSERT(m_perspectiveForPerspectiveId.contains(m_currentPerspectiveId), return); + const auto operations = m_perspectiveForPerspectiveId.value(m_currentPerspectiveId).operations(); for (const Perspective::Operation &operation : operations) { QDockWidget *dock = m_dockForDockId.value(operation.dockId); - QTC_ASSERT(dock, continue); + if (!dock) { + QTC_CHECK(!operation.widget->objectName().isEmpty()); + dock = registerDockWidget(operation.dockId, operation.widget); + + QAction *toggleViewAction = dock->toggleViewAction(); + toggleViewAction->setText(dock->windowTitle()); + + Command *cmd = ActionManager::registerAction(toggleViewAction, + Id("Dock.").withSuffix(dock->objectName()), + Context(Id::fromName(m_currentPerspectiveId))); + cmd->setAttribute(Command::CA_Hide); + + ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd); + } if (operation.operationType == Perspective::Raise) { dock->raise(); continue; } addDockWidget(operation.area, dock); - QDockWidget *existing = m_dockForDockId.value(operation.existing); - if (!existing && operation.area == Qt::BottomDockWidgetArea) - existing = toolBarDockWidget(); - if (existing) { + QDockWidget *anchor = m_dockForDockId.value(operation.anchorDockId); + if (!anchor && operation.area == Qt::BottomDockWidgetArea) + anchor = toolBarDockWidget(); + if (anchor) { switch (operation.operationType) { case Perspective::AddToTab: - tabifyDockWidget(existing, dock); + tabifyDockWidget(anchor, dock); break; case Perspective::SplitHorizontal: - splitDockWidget(existing, dock, Qt::Horizontal); + splitDockWidget(anchor, dock, Qt::Horizontal); break; case Perspective::SplitVertical: - splitDockWidget(existing, dock, Qt::Vertical); + splitDockWidget(anchor, dock, Qt::Vertical); break; default: break; @@ -135,66 +254,84 @@ void MainWindowBase::loadPerspectiveHelper(Id perspectiveId, bool fromStoredSett if (fromStoredSettings) { QSettings *settings = ICore::settings(); - settings->beginGroup(perspectiveId.toString()); + settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); if (settings->value(QLatin1String("ToolSettingsSaved"), false).toBool()) restoreSettings(settings); settings->endGroup(); } - QTC_CHECK(m_toolbarForPerspectiveId.contains(perspectiveId)); - m_controlsStackWidget->setCurrentWidget(m_toolbarForPerspectiveId.value(perspectiveId)); -} - -void MainWindowBase::closeCurrentPerspective() -{ - if (!m_currentPerspectiveId.isValid()) - return; - - saveCurrentPerspective(); - foreach (QDockWidget *dockWidget, m_dockForDockId) { - QTC_ASSERT(dockWidget, continue); - removeDockWidget(dockWidget); - dockWidget->hide(); - // Prevent saveState storing the data of the wrong children. - dockWidget->setParent(0); - } + QTC_CHECK(m_toolbarForPerspectiveId.contains(m_currentPerspectiveId)); + m_controlsStackWidget->setCurrentWidget(m_toolbarForPerspectiveId.value(m_currentPerspectiveId)); + m_statusLabel->clear(); } -void MainWindowBase::saveCurrentPerspective() +void DebuggerMainWindow::saveCurrentPerspective() { - if (!m_currentPerspectiveId.isValid()) + if (m_currentPerspectiveId.isEmpty()) return; QSettings *settings = ICore::settings(); - settings->beginGroup(m_currentPerspectiveId.toString()); + settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); saveSettings(settings); settings->setValue(QLatin1String("ToolSettingsSaved"), true); settings->endGroup(); - settings->setValue(m_lastSettingsName, m_currentPerspectiveId.toString()); + settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), m_currentPerspectiveId); } -QDockWidget *MainWindowBase::registerDockWidget(Id dockId, QWidget *widget) +QDockWidget *DebuggerMainWindow::registerDockWidget(const QByteArray &dockId, QWidget *widget) { QTC_ASSERT(!widget->objectName().isEmpty(), return 0); QDockWidget *dockWidget = addDockForWidget(widget); - m_dockWidgets.append(MainWindowBase::DockPtr(dockWidget)); + dockWidget->setParent(0); + m_dockWidgets.append(DebuggerMainWindow::DockPtr(dockWidget)); m_dockForDockId[dockId] = dockWidget; return dockWidget; } -Core::Id MainWindowBase::currentPerspectiveId() const +QString Perspective::name() const { - return m_currentPerspectiveId; + return m_name; } -QString MainWindowBase::lastSettingsName() const +void Perspective::setName(const QString &name) +{ + m_name = name; +} + +QList<QWidget *> ToolbarDescription::widgets() const +{ + return m_widgets; +} + +void ToolbarDescription::addAction(QAction *action) +{ + auto button = new QToolButton; + button->setDefaultAction(action); + m_widgets.append(button); +} + +void ToolbarDescription::addWidget(QWidget *widget) +{ + m_widgets.append(widget); +} + +Perspective::Operation::Operation(const QByteArray &dockId, QWidget *widget, const QByteArray &anchorDockId, + Perspective::OperationType splitType, bool visibleByDefault, + Qt::DockWidgetArea area) + : dockId(dockId), widget(widget), anchorDockId(anchorDockId), + operationType(splitType), visibleByDefault(visibleByDefault), area(area) +{} + +Perspective::Perspective(const QString &name, const QVector<Operation> &splits) + : m_name(name), m_operations(splits) { - return m_lastSettingsName; + for (const Operation &split : splits) + m_docks.append(split.dockId); } -void MainWindowBase::setLastSettingsName(const QString &lastSettingsName) +void Perspective::addOperation(const Operation &operation) { - m_lastSettingsName = lastSettingsName; + m_docks.append(operation.dockId); + m_operations.append(operation); } -} // Internal -} // Debugger +} // Utils diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 3f12344c84af0f9df892b7254a0cb7ef38c10e0b..b1aeb1633970778bb32fea0f9689c3317ade85d3 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -27,9 +27,6 @@ #define DEBUGGERMAINWINDOW_H #include "debugger_global.h" -#include "analyzer/analyzerbase_global.h" - -#include <coreplugin/id.h> #include <utils/fancymainwindow.h> #include <utils/statuslabel.h> @@ -38,113 +35,108 @@ #include <QSet> #include <functional> -#include <initializer_list> QT_BEGIN_NAMESPACE class QComboBox; class QStackedWidget; QT_END_NAMESPACE -namespace Analyzer { +namespace Utils { -class ANALYZER_EXPORT Perspective +class DEBUGGER_EXPORT Perspective { public: enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise }; - class ANALYZER_EXPORT Operation + class DEBUGGER_EXPORT Operation { public: Operation() = default; - Operation(Core::Id dockId, Core::Id existing, OperationType operationType, - bool visibleByDefault = true, - Qt::DockWidgetArea area = Qt::BottomDockWidgetArea); - - Core::Id dockId; - Core::Id existing; + Operation(const QByteArray &dockId, QWidget *widget, + const QByteArray &anchorDockId, + OperationType operationType, + bool visibleByDefault = true, + Qt::DockWidgetArea area = Qt::BottomDockWidgetArea); + + QByteArray dockId; + QWidget *widget = 0; + QByteArray anchorDockId; OperationType operationType; bool visibleByDefault; Qt::DockWidgetArea area; }; Perspective() = default; - Perspective(std::initializer_list<Operation> operations); + Perspective(const QString &name, const QVector<Operation> &operations); void addOperation(const Operation &operation); QVector<Operation> operations() const { return m_operations; } - QVector<Core::Id> docks() const { return m_docks; } + QVector<QByteArray> docks() const { return m_docks; } + + QString name() const; + void setName(const QString &name); private: - QVector<Core::Id> m_docks; + QString m_name; + QVector<QByteArray> m_docks; QVector<Operation> m_operations; }; -} // Analyzer +class DEBUGGER_EXPORT ToolbarDescription +{ +public: + ToolbarDescription() = default; + ToolbarDescription(const QList<QWidget *> &widgets) : m_widgets(widgets) {} -namespace Debugger { -namespace Internal { + QList<QWidget *> widgets() const; -// DebuggerMainWindow dock widget names -const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; -const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules"; -const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register"; -const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output"; -const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots"; -const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack"; -const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles"; -const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads"; -const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.LocalsAndWatchers"; + void addAction(QAction *action); + void addWidget(QWidget *widget); -const char CppPerspectiveId[] = "Debugger.Perspective.Cpp"; -const char QmlPerspectiveId[] = "Debugger.Perspective.Qml"; +private: + QList<QWidget *> m_widgets; +}; -class MainWindowBase : public Utils::FancyMainWindow +class DebuggerMainWindow : public FancyMainWindow { Q_OBJECT public: - MainWindowBase(); - ~MainWindowBase() override; - - QComboBox *toolBox() const { return m_toolBox; } - QStackedWidget *controlsStack() const { return m_controlsStackWidget; } - Utils::StatusLabel *statusLabel() const { return m_statusLabel; } + DebuggerMainWindow(); + ~DebuggerMainWindow() override; - void registerPerspective(Core::Id perspectiveId, const Analyzer::Perspective &perspective); - void registerToolbar(Core::Id perspectiveId, QWidget *widget); - QDockWidget *registerDockWidget(Core::Id dockId, QWidget *widget); + void registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective); + void registerToolbar(const QByteArray &perspectiveId, QWidget *widget); void saveCurrentPerspective(); - void closeCurrentPerspective(); void resetCurrentPerspective(); - void restorePerspective(Core::Id perspectiveId); - - void showStatusMessage(const QString &message, int timeoutMS); + void restorePerspective(const QByteArray &perspectiveId); - QString lastSettingsName() const; - void setLastSettingsName(const QString &lastSettingsName); + void finalizeSetup(); - Core::Id currentPerspectiveId() const; + void showStatusMessage(const QString &message, int timeoutMS); + QDockWidget *dockWidget(const QByteArray &dockId) const; + QByteArray currentPerspective() const { return m_currentPerspectiveId; } private: - void loadPerspectiveHelper(Core::Id perspectiveId, bool fromStoredSettings = true); + QDockWidget *registerDockWidget(const QByteArray &dockId, QWidget *widget); + void loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings = true); - Core::Id m_currentPerspectiveId; - QString m_lastSettingsName; - QComboBox *m_toolBox; + QByteArray m_currentPerspectiveId; + QComboBox *m_perspectiveChooser; QStackedWidget *m_controlsStackWidget; Utils::StatusLabel *m_statusLabel; - QHash<Core::Id, QDockWidget *> m_dockForDockId; - QHash<Core::Id, QWidget *> m_toolbarForPerspectiveId; - QHash<Core::Id, Analyzer::Perspective> m_perspectiveForPerspectiveId; + + QHash<QByteArray, QDockWidget *> m_dockForDockId; + QHash<QByteArray, QWidget *> m_toolbarForPerspectiveId; + QHash<QByteArray, Perspective> m_perspectiveForPerspectiveId; // list of dock widgets to prevent memory leak typedef QPointer<QDockWidget> DockPtr; QList<DockPtr> m_dockWidgets; }; -} // namespace Internal -} // namespace Debugger +} // Utils #endif // DEBUGGERMAINWINDOW_H diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 78d24374b1ddc4ba7ed84cabd7330f3cb331bef0..090c2eff3e7b53af08e193c813e0ab4dc19b8d8d 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -71,7 +71,10 @@ #include "gdb/startgdbserverdialog.h" #include "analyzer/analyzerconstants.h" +#include "analyzer/analyzericons.h" #include "analyzer/analyzermanager.h" +#include "analyzer/analyzerruncontrol.h" +#include "analyzer/analyzerstartparameters.h" #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> @@ -87,6 +90,7 @@ #include <coreplugin/messagebox.h> #include <coreplugin/messagemanager.h> #include <coreplugin/modemanager.h> +#include <coreplugin/modemanager.h> #include <coreplugin/navigationwidget.h> #include <coreplugin/outputpane.h> #include <coreplugin/rightpane.h> @@ -96,21 +100,21 @@ #include <extensionsystem/invoker.h> +#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildmanager.h> -#include <projectexplorer/taskhub.h> -#include <projectexplorer/toolchain.h> -#include <projectexplorer/devicesupport/deviceprocesslist.h> #include <projectexplorer/devicesupport/deviceprocessesdialog.h> +#include <projectexplorer/devicesupport/deviceprocesslist.h> +#include <projectexplorer/project.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorericons.h> -#include <projectexplorer/projecttree.h> #include <projectexplorer/projectexplorersettings.h> -#include <projectexplorer/project.h> +#include <projectexplorer/projecttree.h> #include <projectexplorer/runconfiguration.h> #include <projectexplorer/runnables.h> #include <projectexplorer/session.h> -#include <projectexplorer/taskhub.h> #include <projectexplorer/target.h> +#include <projectexplorer/taskhub.h> +#include <projectexplorer/toolchain.h> #include <texteditor/texteditor.h> #include <texteditor/textdocument.h> @@ -120,6 +124,7 @@ #include <utils/algorithm.h> #include <utils/appmainwindow.h> #include <utils/basetreeview.h> +#include <utils/checkablemessagebox.h> #include <utils/fancymainwindow.h> #include <utils/hostosinfo.h> #include <utils/mimetypes/mimedatabase.h> @@ -128,7 +133,6 @@ #include <utils/savedaction.h> #include <utils/statuslabel.h> #include <utils/styledbar.h> -#include <utils/styledbar.h> #include <utils/winutils.h> #include <QAction> @@ -136,21 +140,33 @@ #include <QCheckBox> #include <QComboBox> #include <QDebug> +#include <QDialog> +#include <QDialogButtonBox> #include <QDockWidget> #include <QFileDialog> #include <QHBoxLayout> #include <QHeaderView> #include <QInputDialog> #include <QMenu> -#include <QMenu> #include <QMessageBox> +#include <QPointer> +#include <QPushButton> +#include <QSettings> #include <QStackedWidget> #include <QTextBlock> #include <QToolButton> #include <QTreeWidget> #include <QVBoxLayout> +#include <QVariant> #include <QtPlugin> +using namespace Core; +using namespace Utils; +using namespace Core::Constants; +using namespace ProjectExplorer; +using namespace Debugger; +using namespace Debugger::Internal; + #ifdef WITH_TESTS #include <QTest> #include <QSignalSpy> @@ -405,13 +421,9 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; -using namespace Analyzer; -//using namespace Analyzer::Internal; - namespace CC = Core::Constants; namespace PE = ProjectExplorer::Constants; - namespace Debugger { namespace Internal { @@ -425,36 +437,15 @@ struct TestCallBack QVariant cookie; }; - -} // namespace Internal -} // namespace Debugger - -Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack) - -namespace Debugger { -namespace Internal { - void addCdbOptionPages(QList<IOptionsPage*> *opts); void addGdbOptionPages(QList<IOptionsPage*> *opts); QObject *createDebuggerRunControlFactory(QObject *parent); -static QToolButton *toolButton(QAction *action) -{ - QToolButton *button = new QToolButton; - button->setDefaultAction(action); - return button; -} - static void setProxyAction(ProxyAction *proxy, Id id) { proxy->setAction(ActionManager::command(id)->action()); } -static QToolButton *toolButton(Id id) -{ - return toolButton(ActionManager::command(id)->action()); -} - /////////////////////////////////////////////////////////////////////// // // DummyEngine @@ -465,17 +456,17 @@ class DummyEngine : public DebuggerEngine { public: DummyEngine() : DebuggerEngine(DebuggerRunParameters()) {} - ~DummyEngine() {} - - void setupEngine() {} - void setupInferior() {} - void runEngine() {} - void shutdownEngine() {} - void shutdownInferior() {} - bool hasCapability(unsigned cap) const; - bool acceptsBreakpoint(Breakpoint) const { return false; } - bool acceptsDebuggerCommands() const { return false; } - void selectThread(ThreadId) {} + ~DummyEngine() override {} + + void setupEngine() override {} + void setupInferior() override {} + void runEngine() override {} + void shutdownEngine() override {} + void shutdownInferior() override {} + bool hasCapability(unsigned cap) const override; + bool acceptsBreakpoint(Breakpoint) const override { return false; } + bool acceptsDebuggerCommands() const override { return false; } + void selectThread(ThreadId) override {} }; bool DummyEngine::hasCapability(unsigned cap) const @@ -516,13 +507,15 @@ public: setDisplayName(DebuggerPlugin::tr("Debug")); setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC, Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE)); +// setIcon(Utils::Icon::modeIcon(Icons::MODE_ANALYZE_CLASSIC, +// Icons::MODE_ANALYZE_FLAT, Icons::MODE_ANALYZE_FLAT_ACTIVE)); setPriority(85); setId(MODE_DEBUG); } ~DebugMode() { - delete m_widget; +// delete m_widget; } }; @@ -716,7 +709,6 @@ public: void toggleBreakpointHelper(); void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString()); void onModeChanged(IMode *mode); - void onCoreAboutToOpen(); void updateDebugWithoutDeployMenu(); void startAndDebugApplication(); @@ -778,7 +770,7 @@ public: #endif -public slots: +public: void updateDebugActions(); void handleExecDetach() @@ -962,45 +954,35 @@ public slots: bool parseArguments(const QStringList &args, QString *errorMessage); void parseCommandLineArguments(); -public: - // Active languages to be debugged. - DebuggerLanguages activeDebugLanguages() const; + // Ex-Analyzer + bool showPromptDialog(const QString &title, const QString &text, + const QString &stopButtonText, const QString &cancelButtonText) const; + + void registerAction(Core::Id actionId, const ActionDescription &desc, QAction *startAction); + void selectPerspective(const QByteArray &perspectiveId); // Called when all dependent plugins have loaded. void initialize(); - void onModeChangedHelper(Core::IMode *mode); - - // Dockwidgets are registered to the main window. - QDockWidget *createDockWidget(Id dockId, QWidget *widget); - QWidget *createContents(Core::IMode *mode); - - void readWindowSettings(); - void writeWindowSettings() const; - - void createViewsMenuItems(); - - QWidget *mainWindow() const { return m_mainWindow; } - void updateUiForProject(ProjectExplorer::Project *project); void updateUiForTarget(ProjectExplorer::Target *target); void updateUiForRunConfiguration(ProjectExplorer::RunConfiguration *rc); void updateActiveLanguages(); public: - MainWindowBase *m_mainWindow = 0; + DebuggerMainWindow *m_mainWindow = 0; + + QHash<Id, QAction *> m_actions; + QHash<Id, ActionDescription> m_descriptions; + ActionContainer *m_menu = 0; // DockWidgetEventFilter m_resizeEventFilter; QHash<DebuggerLanguage, Core::Context> m_contextsForLanguage; - bool m_inDebugMode = false; - - Core::ActionContainer *m_viewsMenu = 0; - - ProjectExplorer::Project *m_previousProject = 0; - ProjectExplorer::Target *m_previousTarget = 0; - ProjectExplorer::RunConfiguration *m_previousRunConfiguration = 0; + Project *m_previousProject = 0; + Target *m_previousTarget = 0; + QPointer<RunConfiguration> m_previousRunConfiguration; Id m_previousMode; QVector<QPair<DebuggerRunParameters, Kit *>> m_scheduledStarts; @@ -1037,15 +1019,11 @@ public: QAction *m_frameUpAction = 0; QAction *m_frameDownAction = 0; QAction *m_resetAction = 0; + QAction *m_operateByInstructionAction = 0; QToolButton *m_reverseToolButton = 0; - QIcon m_startIcon; - QIcon m_exitIcon; - QIcon m_continueIcon; - QIcon m_interruptIcon; QIcon m_locationMarkIcon; - QIcon m_resetIcon; QComboBox *m_threadBox = 0; @@ -1091,6 +1069,8 @@ public: CommonOptionsPage *m_commonOptionsPage = 0; DummyEngine *m_dummyEngine = 0; const QSharedPointer<GlobalDebuggerOptions> m_globalDebuggerOptions; + + DebugMode *m_debugMode = 0; }; DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) @@ -1112,10 +1092,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) DebuggerPluginPrivate::~DebuggerPluginPrivate() { -// Mainwindow will be deleted by debug mode. -// delete m_mainWindow; -// m_mainWindow = 0; - delete m_debuggerSettings; m_debuggerSettings = 0; @@ -1124,6 +1100,11 @@ DebuggerPluginPrivate::~DebuggerPluginPrivate() delete m_breakHandler; m_breakHandler = 0; + +// delete m_debugMode; +// m_debugMode = 0; + delete m_mainWindow; + m_mainWindow = 0; } DebuggerEngine *DebuggerPluginPrivate::dummyEngine() @@ -1270,10 +1251,37 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, connect(KitManager::instance(), &KitManager::kitsLoaded, this, &DebuggerPluginPrivate::parseCommandLineArguments); - m_mainWindow = new MainWindowBase; - m_mainWindow->setObjectName(QLatin1String("DebuggerMainWindow")); + m_mainWindow = new DebuggerMainWindow; + + // Menus + m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); + m_menu->menu()->setTitle(tr("&Analyze")); + m_menu->menu()->setEnabled(true); + + m_menu->appendGroup(G_ANALYZER_CONTROL); + m_menu->appendGroup(G_ANALYZER_TOOLS); + m_menu->appendGroup(G_ANALYZER_REMOTE_TOOLS); + m_menu->appendGroup(G_ANALYZER_OPTIONS); + + ActionContainer *menubar = ActionManager::actionContainer(MENU_BAR); + ActionContainer *mtools = ActionManager::actionContainer(M_TOOLS); + menubar->addMenu(mtools, m_menu); + + m_menu->addSeparator(G_ANALYZER_TOOLS); + m_menu->addSeparator(G_ANALYZER_REMOTE_TOOLS); + m_menu->addSeparator(G_ANALYZER_OPTIONS); + + // Populate Windows->Views menu with standard actions. + Context debugcontext(Constants::C_DEBUGMODE); + + auto openMemoryEditorAction = new QAction(this); + openMemoryEditorAction->setText(DebuggerPluginPrivate::tr("Memory...")); + connect(openMemoryEditorAction, &QAction::triggered, + this, &Internal::openMemoryEditor); - createViewsMenuItems(); + Command *cmd = ActionManager::registerAction(openMemoryEditorAction, + "Debugger.Views.OpenMemoryEditor", debugcontext); + cmd->setAttribute(Command::CA_Hide); m_plugin->addAutoReleasedObject(debuggerConsole()); @@ -1282,1741 +1290,1722 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, TaskHub::addCategory(TASK_CATEGORY_DEBUGGER_RUNTIME, tr("Debugger Runtime")); - return true; -} - -void setConfigValue(const QByteArray &name, const QVariant &value) -{ - ICore::settings()->setValue(_("DebugMode/" + name), value); -} + const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5")); -QVariant configValue(const QByteArray &name) -{ - return ICore::settings()->value(_("DebugMode/" + name)); -} + QSettings *settings = ICore::settings(); -void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project) -{ - RunConfiguration *activeRc = 0; - if (project) { - Target *target = project->activeTarget(); - if (target) - activeRc = target->activeRunConfiguration(); - if (!activeRc) - return; - } - for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) { - // Run controls might be deleted during exit. - if (DebuggerEngine *engine = m_snapshotHandler->at(i)) { - DebuggerRunControl *runControl = engine->runControl(); - RunConfiguration *rc = runControl->runConfiguration(); - if (rc == activeRc) { - m_snapshotHandler->setCurrentIndex(i); - updateState(engine); - return; - } - } - } + m_debuggerSettings = new DebuggerSettings; + m_debuggerSettings->readSettings(); - // If we have a running debugger, don't touch it. - if (m_snapshotHandler->size()) - return; + connect(ICore::instance(), &ICore::coreAboutToClose, this, &DebuggerPluginPrivate::coreShutdown); - // No corresponding debugger found. So we are ready to start one. - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(false); - QString whyNot; - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); - m_startAction->setEnabled(canRun); - m_startAction->setToolTip(whyNot); - m_debugWithoutDeployAction->setEnabled(canRun); - setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); -} + const Context cppDebuggercontext(C_CPPDEBUGGER); + const Context cppeditorcontext(CppEditor::Constants::CPPEDITOR_ID); -void DebuggerPluginPrivate::startAndDebugApplication() -{ - DebuggerRunParameters rp; - Kit *kit; - if (StartApplicationDialog::run(ICore::dialogParent(), &rp, &kit)) - createAndScheduleRun(rp, kit); -} + const QIcon continueSideBarIcon = Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT); + const QIcon interruptSideBarIcon = Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT); + m_locationMarkIcon = Icons::LOCATION.icon(); -void DebuggerPluginPrivate::attachCore() -{ - AttachCoreDialog dlg(ICore::dialogParent()); + m_busy = false; - const QString lastExternalKit = configValue("LastExternalKit").toString(); - if (!lastExternalKit.isEmpty()) - dlg.setKitId(Id::fromString(lastExternalKit)); - dlg.setLocalExecutableFile(configValue("LastExternalExecutableFile").toString()); - dlg.setLocalCoreFile(configValue("LastLocalCoreFile").toString()); - dlg.setRemoteCoreFile(configValue("LastRemoteCoreFile").toString()); - dlg.setOverrideStartScript(configValue("LastExternalStartScript").toString()); - dlg.setForceLocalCoreFile(configValue("LastForceLocalCoreFile").toBool()); + m_logWindow = new LogWindow; + m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT)); - if (dlg.exec() != QDialog::Accepted) - return; + m_breakHandler = new BreakHandler; + m_breakView = new BreakTreeView; + m_breakView->setSettings(settings, "Debugger.BreakWindow"); + m_breakView->setModel(m_breakHandler->model()); + m_breakWindow = addSearch(m_breakView, tr("Breakpoints"), DOCKWIDGET_BREAK); - setConfigValue("LastExternalExecutableFile", dlg.localExecutableFile()); - setConfigValue("LastLocalCoreFile", dlg.localCoreFile()); - setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile()); - setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); - setConfigValue("LastExternalStartScript", dlg.overrideStartScript()); - setConfigValue("LastForceLocalCoreFile", dlg.forcesLocalCoreFile()); + m_modulesView = new ModulesTreeView; + m_modulesView->setSettings(settings, "Debugger.ModulesView"); + m_modulesWindow = addSearch(m_modulesView, tr("Modules"), DOCKWIDGET_MODULES); - QString display = dlg.useLocalCoreFile() ? dlg.localCoreFile() : dlg.remoteCoreFile(); - DebuggerRunParameters rp; - rp.masterEngineType = DebuggerKitInformation::engineType(dlg.kit()); - rp.inferior.executable = dlg.localExecutableFile(); - rp.coreFile = dlg.localCoreFile(); - rp.displayName = tr("Core file \"%1\"").arg(display); - rp.startMode = AttachCore; - rp.closeMode = DetachAtClose; - rp.overrideStartScript = dlg.overrideStartScript(); - createAndScheduleRun(rp, dlg.kit()); -} + m_registerView = new RegisterTreeView; + m_registerView->setSettings(settings, "Debugger.RegisterView"); + m_registerWindow = addSearch(m_registerView, tr("Registers"), DOCKWIDGET_REGISTER); -void DebuggerPluginPrivate::startRemoteCdbSession() -{ - const QByteArray connectionKey = "CdbRemoteConnection"; - DebuggerRunParameters rp; - Kit *kit = findUniversalCdbKit(); - QTC_ASSERT(kit, return); - rp.startMode = AttachToRemoteServer; - rp.closeMode = KillAtClose; - StartRemoteCdbDialog dlg(ICore::dialogParent()); - QString previousConnection = configValue(connectionKey).toString(); - if (previousConnection.isEmpty()) - previousConnection = QLatin1String("localhost:1234"); - dlg.setConnection(previousConnection); - if (dlg.exec() != QDialog::Accepted) - return; - rp.remoteChannel = dlg.connection(); - setConfigValue(connectionKey, rp.remoteChannel); - createAndScheduleRun(rp, kit); -} + m_stackView = new StackTreeView; + m_stackView->setSettings(settings, "Debugger.StackView"); + m_stackWindow = addSearch(m_stackView, tr("Stack"), DOCKWIDGET_STACK); -void DebuggerPluginPrivate::attachToRemoteServer() -{ - DebuggerRunParameters rp; - Kit *kit; - rp.startMode = AttachToRemoteServer; - if (StartApplicationDialog::run(ICore::dialogParent(), &rp, &kit)) { - rp.closeMode = KillAtClose; - createAndScheduleRun(rp, kit); - } -} + m_sourceFilesView = new SourceFilesTreeView; + m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView"); + m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES); -void DebuggerPluginPrivate::startRemoteServerAndAttachToProcess() -{ - auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging); - auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent()); - dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); - dlg->showAllDevices(); - if (dlg->exec() == QDialog::Rejected) { - delete dlg; - return; - } + m_threadsView = new ThreadsTreeView; + m_threadsView->setSettings(settings, "Debugger.ThreadsView"); + m_threadsWindow = addSearch(m_threadsView, tr("Threads"), DOCKWIDGET_THREADS); - dlg->setAttribute(Qt::WA_DeleteOnClose); - Kit *kit = kitChooser->currentKit(); - QTC_ASSERT(kit, return); - IDevice::ConstPtr device = DeviceKitInformation::device(kit); - QTC_ASSERT(device, return); + m_returnView = new WatchTreeView(ReturnType); // No settings. + m_returnWindow = addSearch(m_returnView, tr("Locals and Expressions"), "CppDebugReturn"); - GdbServerStarter *starter = new GdbServerStarter(dlg, true); - starter->run(); -} + m_localsView = new WatchTreeView(LocalsType); + m_localsView->setSettings(settings, "Debugger.LocalsView"); + m_localsWindow = addSearch(m_localsView, tr("Locals and Expressions"), "CppDebugLocals"); -void DebuggerPluginPrivate::attachToRunningApplication() -{ - auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::LocalDebugging); + m_watchersView = new WatchTreeView(WatchersType); // No settings. + m_watchersWindow = addSearch(m_watchersView, tr("Locals and Expressions"), "CppDebugWatchers"); - auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent()); - dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); - dlg->showAllDevices(); - if (dlg->exec() == QDialog::Rejected) { - delete dlg; - return; - } + m_inspectorView = new WatchTreeView(InspectType); + m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view. + m_inspectorWindow = addSearch(m_inspectorView, tr("Locals and Expressions"), "Inspector"); - dlg->setAttribute(Qt::WA_DeleteOnClose); - Kit *kit = kitChooser->currentKit(); - QTC_ASSERT(kit, return); - IDevice::ConstPtr device = DeviceKitInformation::device(kit); - QTC_ASSERT(device, return); + // Snapshot + m_snapshotHandler = new SnapshotHandler; + m_snapshotView = new SnapshotTreeView(m_snapshotHandler); + m_snapshotView->setSettings(settings, "Debugger.SnapshotView"); + m_snapshotView->setModel(m_snapshotHandler->model()); + m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS); - if (device->type() == PE::DESKTOP_DEVICE_TYPE) { - attachToRunningProcess(kit, dlg->currentProcess(), false); - } else { - GdbServerStarter *starter = new GdbServerStarter(dlg, true); - starter->run(); - } -} + // Watchers + connect(m_localsView->header(), &QHeaderView::sectionResized, + this, &DebuggerPluginPrivate::updateWatchersHeader, Qt::QueuedConnection); -void DebuggerPluginPrivate::attachToUnstartedApplicationDialog() -{ - auto dlg = new UnstartedAppWatcherDialog(ICore::dialogParent()); + auto act = m_continueAction = new QAction(tr("Continue"), this); + act->setIcon(Icon::combinedIcon({Core::Icons::DEBUG_CONTINUE_SMALL.icon(), continueSideBarIcon})); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue); - connect(dlg, &QDialog::finished, dlg, &QObject::deleteLater); - connect(dlg, &UnstartedAppWatcherDialog::processFound, this, [this, dlg] { - DebuggerRunControl *rc = attachToRunningProcess(dlg->currentKit(), - dlg->currentProcess(), - dlg->continueOnAttach()); - if (!rc) - return; + act = m_exitAction = new QAction(tr("Stop Debugger"), this); + act->setIcon(Core::Icons::DEBUG_EXIT_SMALL.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecExit); - if (dlg->hideOnAttach()) - connect(rc, &RunControl::finished, dlg, &UnstartedAppWatcherDialog::startWatching); - }); + auto interruptIcon = Icon::combinedIcon({Core::Icons::DEBUG_INTERRUPT_SMALL.icon(), interruptSideBarIcon}); + act = m_interruptAction = new QAction(tr("Interrupt"), this); + act->setIcon(interruptIcon); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt); - dlg->show(); -} + // A "disabled pause" seems to be a good choice. + act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this); + act->setIcon(interruptIcon); + act->setEnabled(false); -DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, - DeviceProcessItem process, bool contAfterAttach) -{ - QTC_ASSERT(kit, return 0); - IDevice::ConstPtr device = DeviceKitInformation::device(kit); - QTC_ASSERT(device, return 0); - if (process.pid == 0) { - AsynchronousMessageBox::warning(tr("Warning"), tr("Cannot attach to process with PID 0")); - return 0; - } + act = m_abortAction = new QAction(tr("Abort Debugging"), this); + act->setToolTip(tr("Aborts debugging and " + "resets the debugger to the initial state.")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort); - bool isWindows = false; - if (const ToolChain *tc = ToolChainKitInformation::toolChain(kit)) - isWindows = tc->targetAbi().os() == Abi::WindowsOS; - if (isWindows && isWinProcessBeingDebugged(process.pid)) { - AsynchronousMessageBox::warning(tr("Process Already Under Debugger Control"), - tr("The process %1 is already under the control of a debugger.\n" - "Qt Creator cannot attach to it.").arg(process.pid)); - return 0; - } + act = m_resetAction = new QAction(tr("Restart Debugging"),this); + act->setToolTip(tr("Restart the debugging session.")); + act->setIcon(Icons::RESTART.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset); - if (device->type() != PE::DESKTOP_DEVICE_TYPE) { - AsynchronousMessageBox::warning(tr("Not a Desktop Device Type"), - tr("It is only possible to attach to a locally running process.")); - return 0; - } + act = m_nextAction = new QAction(tr("Step Over"), this); + act->setIcon(Icons::STEP_OVER.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext); - DebuggerRunParameters rp; - rp.attachPID = process.pid; - rp.displayName = tr("Process %1").arg(process.pid); - rp.inferior.executable = process.exe; - rp.startMode = AttachExternal; - rp.closeMode = DetachAtClose; - rp.continueAfterAttach = contAfterAttach; - return createAndScheduleRun(rp, kit); -} + act = m_stepAction = new QAction(tr("Step Into"), this); + act->setIcon(Icons::STEP_INTO.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep); -void DebuggerPlugin::attachExternalApplication(RunControl *rc) -{ - DebuggerRunParameters rp; - rp.attachPID = rc->applicationProcessHandle().pid(); - rp.displayName = tr("Process %1").arg(rp.attachPID); - rp.startMode = AttachExternal; - rp.closeMode = DetachAtClose; - rp.toolChainAbi = rc->abi(); - Kit *kit = 0; - if (const RunConfiguration *runConfiguration = rc->runConfiguration()) - if (const Target *target = runConfiguration->target()) - kit = target->kit(); - createAndScheduleRun(rp, kit); -} + act = m_stepOutAction = new QAction(tr("Step Out"), this); + act->setIcon(Icons::STEP_OUT.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut); -void DebuggerPluginPrivate::attachToQmlPort() -{ - DebuggerRunParameters rp; - AttachToQmlPortDialog dlg(ICore::mainWindow()); + act = m_runToLineAction = new QAction(tr("Run to Line"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine); - const QVariant qmlServerPort = configValue("LastQmlServerPort"); - if (qmlServerPort.isValid()) - dlg.setPort(qmlServerPort.toInt()); - else - dlg.setPort(rp.qmlServerPort); + act = m_runToSelectedFunctionAction = new QAction(tr("Run to Selected Function"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction); - const Id kitId = Id::fromSetting(configValue("LastProfile")); - if (kitId.isValid()) - dlg.setKitId(kitId); + act = m_returnFromFunctionAction = + new QAction(tr("Immediately Return From Inner Function"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn); - if (dlg.exec() != QDialog::Accepted) - return; + act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine); - Kit *kit = dlg.kit(); - QTC_ASSERT(kit, return); - setConfigValue("LastQmlServerPort", dlg.port()); - setConfigValue("LastProfile", kit->id().toSetting()); + m_breakAction = new QAction(tr("Toggle Breakpoint"), this); - IDevice::ConstPtr device = DeviceKitInformation::device(kit); - if (device) { - rp.connParams = device->sshParameters(); - rp.qmlServerAddress = device->qmlProfilerHost(); - } - rp.qmlServerPort = dlg.port(); - rp.startMode = AttachToRemoteProcess; - rp.closeMode = KillAtClose; - rp.languages = QmlLanguage; - rp.masterEngineType = QmlEngineType; + act = m_watchAction1 = new QAction(tr("Add Expression Evaluator"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); - // - // get files from all the projects in the session - // - QList<Project *> projects = SessionManager::projects(); - if (Project *startupProject = SessionManager::startupProject()) { - // startup project first - projects.removeOne(startupProject); - projects.insert(0, startupProject); - } - QStringList sourceFiles; - foreach (Project *project, projects) - sourceFiles << project->files(Project::SourceFiles); + act = m_watchAction2 = new QAction(tr("Add Expression Evaluator"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); - rp.projectSourceDirectory = - !projects.isEmpty() ? projects.first()->projectDirectory().toString() : QString(); - rp.projectSourceFiles = sourceFiles; - createAndScheduleRun(rp, kit); -} + //act = m_snapshotAction = new QAction(tr("Create Snapshot"), this); + //act->setProperty(Role, RequestCreateSnapshotRole); + //act->setIcon(Icons::SNAPSHOT.icon()); -void DebuggerPluginPrivate::enableReverseDebuggingTriggered(const QVariant &value) -{ - QTC_ASSERT(m_reverseToolButton, return); - m_reverseToolButton->setVisible(value.toBool()); - m_reverseDirectionAction->setChecked(false); - m_reverseDirectionAction->setEnabled(value.toBool()); -} + act = m_reverseDirectionAction = new QAction(tr("Reverse Direction"), this); + act->setCheckable(true); + act->setChecked(false); + act->setCheckable(false); + act->setIcon(Icons::REVERSE_MODE.icon()); + act->setIconVisibleInMenu(false); -void DebuggerPluginPrivate::runScheduled() -{ - for (int i = 0, n = m_scheduledStarts.size(); i != n; ++i) - createAndScheduleRun(m_scheduledStarts.at(i).first, m_scheduledStarts.at(i).second); -} + act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown); -void DebuggerPluginPrivate::editorOpened(IEditor *editor) -{ - if (auto widget = qobject_cast<TextEditorWidget *>(editor->widget())) { - connect(widget, &TextEditorWidget::markRequested, - this, &DebuggerPluginPrivate::requestMark); + act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp); - connect(widget, &TextEditorWidget::markContextMenuRequested, - this, &DebuggerPluginPrivate::requestContextMenu); - } -} + act = m_operateByInstructionAction = action(OperateByInstruction); + connect(act, &QAction::triggered, + this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered); -void DebuggerPluginPrivate::updateBreakMenuItem(IEditor *editor) -{ - BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(editor); - m_breakAction->setEnabled(textEditor != 0); -} + ActionContainer *debugMenu = ActionManager::actionContainer(PE::M_DEBUG); -void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, - int lineNumber, QMenu *menu) -{ - Breakpoint bp; - TextDocument *document = widget->textDocument(); + m_localsAndExpressionsWindow = new LocalsAndExpressionsWindow( + m_localsWindow, m_inspectorWindow, m_returnWindow, m_watchersWindow); + m_localsAndExpressionsWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS)); + m_localsAndExpressionsWindow->setWindowTitle(m_localsWindow->windowTitle()); - ContextData args = getLocationContext(document, lineNumber); - if (args.type == LocationByAddress) { - BreakpointResponse needle; - needle.type = BreakpointByAddress; - needle.address = args.address; - needle.lineNumber = -1; - bp = breakHandler()->findSimilarBreakpoint(needle); - } else if (args.type == LocationByFile) { - bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber); - if (!bp) - bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber, false); - } + m_plugin->addAutoReleasedObject(createDebuggerRunControlFactory(m_plugin)); - if (bp) { - QString id = bp.id().toString(); + // The main "Start Debugging" action. + act = m_startAction = new QAction(this); + const QIcon sideBarIcon = + Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT); + const QIcon debuggerIcon = Icon::combinedIcon({Core::Icons::DEBUG_START_SMALL.icon(), sideBarIcon}); + act->setIcon(debuggerIcon); + act->setText(tr("Start Debugging")); + connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); }); - // Remove existing breakpoint. - auto act = menu->addAction(tr("Remove Breakpoint %1").arg(id)); - connect(act, &QAction::triggered, [bp] { bp.removeBreakpoint(); }); + act = m_debugWithoutDeployAction = new QAction(this); + act->setText(tr("Start Debugging Without Deployment")); + connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); }); - // Enable/disable existing breakpoint. - if (bp.isEnabled()) { - act = menu->addAction(tr("Disable Breakpoint %1").arg(id)); - connect(act, &QAction::triggered, [bp] { bp.setEnabled(false); }); - } else { - act = menu->addAction(tr("Enable Breakpoint %1").arg(id)); - connect(act, &QAction::triggered, [bp] { bp.setEnabled(true); }); - } + act = m_startAndDebugApplicationAction = new QAction(this); + act->setText(tr("Start and Debug External Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startAndDebugApplication); - // Edit existing breakpoint. - act = menu->addAction(tr("Edit Breakpoint %1...").arg(id)); - connect(act, &QAction::triggered, [bp] { - BreakTreeView::editBreakpoint(bp, ICore::dialogParent()); - }); + act = m_attachToCoreAction = new QAction(this); + act->setText(tr("Load Core File...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); - } else { - // Handle non-existing breakpoint. - const QString text = args.address - ? tr("Set Breakpoint at 0x%1").arg(args.address, 0, 16) - : tr("Set Breakpoint at Line %1").arg(lineNumber); - auto act = menu->addAction(text); - act->setEnabled(args.isValid()); - connect(act, &QAction::triggered, [this, args] { - breakpointSetMarginActionTriggered(false, args); - }); - - // Message trace point - const QString tracePointText = args.address - ? tr("Set Message Tracepoint at 0x%1...").arg(args.address, 0, 16) - : tr("Set Message Tracepoint at Line %1...").arg(lineNumber); - act = menu->addAction(tracePointText); - act->setEnabled(args.isValid()); - connect(act, &QAction::triggered, [this, args] { - breakpointSetMarginActionTriggered(true, args); - }); - } + act = m_attachToRemoteServerAction = new QAction(this); + act->setText(tr("Attach to Running Debug Server...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRemoteServer); - // Run to, jump to line below in stopped state. - if (currentEngine()->state() == InferiorStopOk && args.isValid()) { - menu->addSeparator(); - if (currentEngine()->hasCapability(RunToLineCapability)) { - auto act = menu->addAction(args.address - ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16) - : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber)); - connect(act, &QAction::triggered, [this, args] { - currentEngine()->executeRunToLine(args); - }); - } - if (currentEngine()->hasCapability(JumpToLineCapability)) { - auto act = menu->addAction(args.address - ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16) - : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber)); - connect(act, &QAction::triggered, [this, args] { - currentEngine()->executeJumpToLine(args); - }); - } - // Disassemble current function in stopped state. - if (currentEngine()->hasCapability(DisassemblerCapability)) { - StackFrame frame; - frame.function = cppFunctionAt(args.fileName, lineNumber, 1); - frame.line = 42; // trick gdb into mixed mode. - if (!frame.function.isEmpty()) { - const QString text = tr("Disassemble Function \"%1\"") - .arg(frame.function); - auto act = new QAction(text, menu); - connect(act, &QAction::triggered, [this, frame] { - currentEngine()->openDisassemblerView(Location(frame)); - }); - menu->addAction(act); - } - } - } -} + act = m_startRemoteServerAction = new QAction(this); + act->setText(tr("Start Debug Server Attached to Process...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess); -void DebuggerPluginPrivate::toggleBreakpoint(const ContextData &location, const QString &tracePointMessage) -{ - QTC_ASSERT(location.isValid(), return); - BreakHandler *handler = m_breakHandler; - Breakpoint bp; - if (location.type == LocationByFile) { - bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, true); - if (!bp) - bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, false); - } else if (location.type == LocationByAddress) { - bp = handler->findBreakpointByAddress(location.address); - } + act = m_attachToRunningApplication = new QAction(this); + act->setText(tr("Attach to Running Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); - if (bp) { - bp.removeBreakpoint(); - } else { - BreakpointParameters data; - if (location.type == LocationByFile) { - data.type = BreakpointByFileAndLine; - if (boolSetting(BreakpointsFullPathByDefault)) - data.pathUsage = BreakpointUseFullPath; - data.tracepoint = !tracePointMessage.isEmpty(); - data.message = tracePointMessage; - data.fileName = location.fileName; - data.lineNumber = location.lineNumber; - } else if (location.type == LocationByAddress) { - data.type = BreakpointByAddress; - data.tracepoint = !tracePointMessage.isEmpty(); - data.message = tracePointMessage; - data.address = location.address; - } - handler->appendBreakpoint(data); - } -} + act = m_attachToUnstartedApplication = new QAction(this); + act->setText(tr("Attach to Unstarted Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); -void DebuggerPluginPrivate::toggleBreakpointHelper() -{ - BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor(); - QTC_ASSERT(textEditor, return); - const int lineNumber = textEditor->currentLine(); - ContextData location = getLocationContext(textEditor->textDocument(), lineNumber); - if (location.isValid()) - toggleBreakpoint(location); -} + act = m_attachToQmlPortAction = new QAction(this); + act->setText(tr("Attach to QML Port...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort); -void DebuggerPluginPrivate::requestMark(TextEditorWidget *widget, int lineNumber, - TextMarkRequestKind kind) -{ - if (kind == BreakpointRequest) { - ContextData location = getLocationContext(widget->textDocument(), lineNumber); - if (location.isValid()) - toggleBreakpoint(location); + if (HostOsInfo::isWindowsHost()) { + m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this); + connect(m_startRemoteCdbAction, &QAction::triggered, + this, &DebuggerPluginPrivate::startRemoteCdbSession); } -} -// If updateEngine is set, the engine will update its threads/modules and so forth. -void DebuggerPluginPrivate::displayDebugger(DebuggerEngine *engine, bool updateEngine) -{ - QTC_ASSERT(engine, return); - disconnectEngine(); - connectEngine(engine); - if (updateEngine) - engine->updateAll(); - engine->updateViews(); -} + act = m_detachAction = new QAction(this); + act->setText(tr("Detach Debugger")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach); -void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine) -{ - if (!engine) - engine = dummyEngine(); + // "Start Debugging" sub-menu + // groups: + // G_DEFAULT_ONE + // G_START_LOCAL + // G_START_REMOTE + // G_START_QML - if (m_currentEngine == engine) - return; + ActionContainer *mstart = ActionManager::actionContainer(PE::M_DEBUG_STARTDEBUGGING); - if (m_currentEngine) - m_currentEngine->resetLocation(); - m_currentEngine = engine; + cmd = ActionManager::registerAction(m_startAction, Constants::DEBUG); + cmd->setDescription(tr("Start Debugging")); + cmd->setDefaultKeySequence(debugKey); + cmd->setAttribute(Command::CA_UpdateText); + mstart->addAction(cmd, CC::G_DEFAULT_ONE); + m_visibleStartAction = new ProxyAction(this); + m_visibleStartAction->initialize(cmd->action()); + m_visibleStartAction->setAttribute(ProxyAction::UpdateText); + m_visibleStartAction->setAttribute(ProxyAction::UpdateIcon); + m_visibleStartAction->setAction(cmd->action()); - m_localsView->setModel(engine->watchModel()); - m_modulesView->setModel(engine->modulesModel()); - m_registerView->setModel(engine->registerModel()); - m_returnView->setModel(engine->watchModel()); - m_sourceFilesView->setModel(engine->sourceFilesModel()); - m_stackView->setModel(engine->stackModel()); - m_threadsView->setModel(engine->threadsModel()); - m_watchersView->setModel(engine->watchModel()); - m_inspectorView->setModel(engine->watchModel()); + ModeManager::addAction(m_visibleStartAction, Constants::P_ACTION_DEBUG); - engine->watchHandler()->resetWatchers(); - m_localsView->hideProgressIndicator(); -} + cmd = ActionManager::registerAction(m_debugWithoutDeployAction, + "Debugger.DebugWithoutDeploy"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, CC::G_DEFAULT_ONE); -static void changeFontSize(QWidget *widget, qreal size) -{ - QFont font = widget->font(); - font.setPointSizeF(size); - widget->setFont(font); -} + cmd = ActionManager::registerAction(m_attachToRunningApplication, + "Debugger.AttachToRemoteProcess"); + cmd->setDescription(tr("Attach to Running Application")); + mstart->addAction(cmd, G_GENERAL); -void DebuggerPluginPrivate::fontSettingsChanged - (const FontSettings &settings) -{ - if (!boolSetting(FontSizeFollowsEditor)) - return; - qreal size = settings.fontZoom() * settings.fontSize() / 100.; - changeFontSize(m_breakWindow, size); - changeFontSize(m_logWindow, size); - changeFontSize(m_localsWindow, size); - changeFontSize(m_modulesWindow, size); - //changeFontSize(m_consoleWindow, size); - changeFontSize(m_registerWindow, size); - changeFontSize(m_returnWindow, size); - changeFontSize(m_sourceFilesWindow, size); - changeFontSize(m_stackWindow, size); - changeFontSize(m_threadsWindow, size); - changeFontSize(m_watchersWindow, size); - changeFontSize(m_inspectorWindow, size); -} + cmd = ActionManager::registerAction(m_attachToUnstartedApplication, + "Debugger.AttachToUnstartedProcess"); + cmd->setDescription(tr("Attach to Unstarted Application")); + mstart->addAction(cmd, G_GENERAL); -void DebuggerPluginPrivate::cleanupViews() -{ - m_reverseDirectionAction->setChecked(false); - m_reverseDirectionAction->setEnabled(false); + cmd = ActionManager::registerAction(m_startAndDebugApplicationAction, + "Debugger.StartAndDebugApplication"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, G_GENERAL); - const bool closeSource = boolSetting(CloseSourceBuffersOnExit); - const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit); + cmd = ActionManager::registerAction(m_attachToCoreAction, + "Debugger.AttachCore"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_GENERAL); - QList<IDocument *> toClose; - foreach (IDocument *document, DocumentModel::openedDocuments()) { - const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool(); - if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) { - bool keepIt = true; - if (document->isModified()) - keepIt = true; - else if (document->filePath().toString().contains(_("qeventdispatcher"))) - keepIt = false; - else if (isMemory) - keepIt = !closeMemory; - else - keepIt = !closeSource; + cmd = ActionManager::registerAction(m_attachToRemoteServerAction, + "Debugger.AttachToRemoteServer"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_SPECIAL); - if (keepIt) - document->setProperty(Constants::OPENED_BY_DEBUGGER, false); - else - toClose.append(document); - } + cmd = ActionManager::registerAction(m_startRemoteServerAction, + "Debugger.StartRemoteServer"); + cmd->setDescription(tr("Start Gdbserver")); + mstart->addAction(cmd, Constants::G_SPECIAL); + + if (m_startRemoteCdbAction) { + cmd = ActionManager::registerAction(m_startRemoteCdbAction, + "Debugger.AttachRemoteCdb"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_SPECIAL); } - EditorManager::closeDocuments(toClose); -} -void DebuggerPluginPrivate::setBusyCursor(bool busy) -{ - //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy); - if (busy == m_busy) - return; - m_busy = busy; - QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor); - m_breakWindow->setCursor(cursor); - //m_consoleWindow->setCursor(cursor); - m_localsWindow->setCursor(cursor); - m_modulesWindow->setCursor(cursor); - m_logWindow->setCursor(cursor); - m_registerWindow->setCursor(cursor); - m_returnWindow->setCursor(cursor); - m_sourceFilesWindow->setCursor(cursor); - m_stackWindow->setCursor(cursor); - m_threadsWindow->setCursor(cursor); - m_watchersWindow->setCursor(cursor); - m_snapshotWindow->setCursor(cursor); -} + mstart->addSeparator(Context(CC::C_GLOBAL), Constants::G_START_QML); -void DebuggerPluginPrivate::setInitialState() -{ - m_watchersWindow->setVisible(false); - m_returnWindow->setVisible(false); - setBusyCursor(false); - m_reverseDirectionAction->setChecked(false); - m_reverseDirectionAction->setEnabled(false); - m_toolTipManager.closeAllToolTips(); + cmd = ActionManager::registerAction(m_attachToQmlPortAction, "Debugger.AttachToQmlPort"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_START_QML); - m_startAndDebugApplicationAction->setEnabled(true); - m_attachToQmlPortAction->setEnabled(true); - m_attachToCoreAction->setEnabled(true); - m_attachToRemoteServerAction->setEnabled(true); - m_attachToRunningApplication->setEnabled(true); - m_attachToUnstartedApplication->setEnabled(true); - m_detachAction->setEnabled(false); + cmd = ActionManager::registerAction(m_detachAction, "Debugger.Detach"); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_watchAction1->setEnabled(true); - m_watchAction2->setEnabled(true); - m_breakAction->setEnabled(false); - //m_snapshotAction->setEnabled(false); - action(OperateByInstruction)->setEnabled(false); + cmd = ActionManager::registerAction(m_interruptAction, Constants::INTERRUPT); + cmd->setDescription(tr("Interrupt Debugger")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_exitAction->setEnabled(false); - m_abortAction->setEnabled(false); - m_resetAction->setEnabled(false); + cmd = ActionManager::registerAction(m_continueAction, Constants::CONTINUE); + cmd->setDefaultKeySequence(debugKey); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); + cmd = ActionManager::registerAction(m_exitAction, Constants::STOP); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + m_hiddenStopAction = new ProxyAction(this); + m_hiddenStopAction->initialize(cmd->action()); + m_hiddenStopAction->setAttribute(ProxyAction::UpdateText); + m_hiddenStopAction->setAttribute(ProxyAction::UpdateIcon); - m_stepAction->setEnabled(true); - m_stepOutAction->setEnabled(false); - m_runToLineAction->setEnabled(false); - m_runToSelectedFunctionAction->setEnabled(true); - m_returnFromFunctionAction->setEnabled(false); - m_jumpToLineAction->setEnabled(false); - m_nextAction->setEnabled(true); + cmd = ActionManager::registerAction(m_hiddenStopAction, Constants::HIDDEN_STOP); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+Ctrl+Y") : tr("Shift+F5"))); - action(AutoDerefPointers)->setEnabled(true); - action(ExpandStack)->setEnabled(false); -} + cmd = ActionManager::registerAction(m_abortAction, Constants::ABORT); + cmd->setDescription(tr("Reset Debugger")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); -void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) -{ - QTC_ASSERT(engine, return); - QTC_ASSERT(m_watchersView->model(), return); - QTC_ASSERT(m_returnView->model(), return); - QTC_ASSERT(!engine->isSlaveEngine(), return); + cmd = ActionManager::registerAction(m_resetAction, Constants::RESET); + cmd->setDescription(tr("Restart Debugging")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThreadIndex()); + debugMenu->addSeparator(); - const DebuggerState state = engine->state(); - //showMessage(QString::fromLatin1("PLUGIN SET STATE: ") - // + DebuggerEngine::stateName(state), LogStatus); - //qDebug() << "PLUGIN SET STATE: " << state; + cmd = ActionManager::registerAction(m_nextAction, Constants::NEXT); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10"))); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_UpdateText); + debugMenu->addAction(cmd); - static DebuggerState previousState = DebuggerNotReady; - if (state == previousState) - return; + cmd = ActionManager::registerAction(m_stepAction, Constants::STEP); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11"))); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_UpdateText); + debugMenu->addAction(cmd); - bool actionsEnabled = DebuggerEngine::debuggerActionsEnabled(state); + cmd = ActionManager::registerAction(m_stepOutAction, + Constants::STEPOUT, cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); - if (state == DebuggerNotReady) { - QTC_ASSERT(false, /* We use the Core's m_debugAction here */); - // F5 starts debugging. It is "startable". - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(false); - m_startAction->setEnabled(true); - m_debugWithoutDeployAction->setEnabled(true); - setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); - m_hiddenStopAction->setAction(m_undisturbableAction); - } else if (state == InferiorStopOk) { - // F5 continues, Shift-F5 kills. It is "continuable". - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(true); - m_exitAction->setEnabled(true); - m_startAction->setEnabled(false); - m_debugWithoutDeployAction->setEnabled(false); - setProxyAction(m_visibleStartAction, Id(Constants::CONTINUE)); - m_hiddenStopAction->setAction(m_exitAction); - m_localsAndExpressionsWindow->setShowLocals(true); - } else if (state == InferiorRunOk) { - // Shift-F5 interrupts. It is also "interruptible". - m_interruptAction->setEnabled(true); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(true); - m_startAction->setEnabled(false); - m_debugWithoutDeployAction->setEnabled(false); - setProxyAction(m_visibleStartAction, Id(Constants::INTERRUPT)); - m_hiddenStopAction->setAction(m_interruptAction); - m_localsAndExpressionsWindow->setShowLocals(false); - activateDebugMode(); - } else if (state == DebuggerFinished) { - Project *project = SessionManager::startupProject(); - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE); - // We don't want to do anything anymore. - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(false); - m_startAction->setEnabled(canRun); - m_debugWithoutDeployAction->setEnabled(canRun); - setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); - m_hiddenStopAction->setAction(m_undisturbableAction); - m_codeModelSnapshot = CPlusPlus::Snapshot(); - setBusyCursor(false); - cleanupViews(); - } else if (state == InferiorUnrunnable) { - // We don't want to do anything anymore. - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(true); - m_startAction->setEnabled(false); - m_debugWithoutDeployAction->setEnabled(false); - m_visibleStartAction->setAction(m_undisturbableAction); - m_hiddenStopAction->setAction(m_exitAction); - // show locals in core dumps - m_localsAndExpressionsWindow->setShowLocals(true); - activateDebugMode(); - } else { - // Everything else is "undisturbable". - m_interruptAction->setEnabled(false); - m_continueAction->setEnabled(false); - m_exitAction->setEnabled(false); - m_startAction->setEnabled(false); - m_debugWithoutDeployAction->setEnabled(false); - m_visibleStartAction->setAction(m_undisturbableAction); - m_hiddenStopAction->setAction(m_undisturbableAction); - } + cmd = ActionManager::registerAction(m_runToLineAction, + "Debugger.RunToLine", cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+F8") : tr("Ctrl+F10"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); - m_startAndDebugApplicationAction->setEnabled(true); - m_attachToQmlPortAction->setEnabled(true); - m_attachToCoreAction->setEnabled(true); - m_attachToRemoteServerAction->setEnabled(true); - m_attachToRunningApplication->setEnabled(true); - m_attachToUnstartedApplication->setEnabled(true); + cmd = ActionManager::registerAction(m_runToSelectedFunctionAction, + "Debugger.RunToSelectedFunction", cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F6"))); + cmd->setAttribute(Command::CA_Hide); + // Don't add to menu by default as keeping its enabled state + // and text up-to-date is a lot of hassle. + // debugMenu->addAction(cmd); - m_threadBox->setEnabled(state == InferiorStopOk || state == InferiorUnrunnable); + cmd = ActionManager::registerAction(m_jumpToLineAction, + "Debugger.JumpToLine", cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); - const bool isCore = engine->runParameters().startMode == AttachCore; - const bool stopped = state == InferiorStopOk; - const bool detachable = stopped && !isCore; - m_detachAction->setEnabled(detachable); + cmd = ActionManager::registerAction(m_returnFromFunctionAction, + "Debugger.ReturnFromFunction", cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); - if (stopped) - QApplication::alert(mainWindow(), 3000); + if (isReverseDebuggingEnabled()) { + cmd = ActionManager::registerAction(m_reverseDirectionAction, + Constants::REVERSE, cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? QString() : tr("F12"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + } - const bool canReverse = engine->hasCapability(ReverseSteppingCapability) - && boolSetting(EnableReverseDebugging); - m_reverseDirectionAction->setEnabled(canReverse); + debugMenu->addSeparator(); - m_watchAction1->setEnabled(true); - m_watchAction2->setEnabled(true); - m_breakAction->setEnabled(true); + //cmd = ActionManager::registerAction(m_snapshotAction, + // "Debugger.Snapshot", cppDebuggercontext); + //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+S"))); + //cmd->setAttribute(Command::CA_Hide); + //debugMenu->addAction(cmd); - const bool canOperateByInstruction = engine->hasCapability(OperateByInstructionCapability) - && (stopped || isCore); - action(OperateByInstruction)->setEnabled(canOperateByInstruction); + ActionManager::registerAction(m_frameDownAction, + "Debugger.FrameDown", cppDebuggercontext); + ActionManager::registerAction(m_frameUpAction, + "Debugger.FrameUp", cppDebuggercontext); - m_abortAction->setEnabled(state != DebuggerNotReady - && state != DebuggerFinished); - m_resetAction->setEnabled((stopped || state == DebuggerNotReady) - && engine->hasCapability(ResetInferiorCapability)); + cmd = ActionManager::registerAction(m_operateByInstructionAction, + Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); - m_stepAction->setEnabled(stopped || state == DebuggerNotReady); - m_nextAction->setEnabled(stopped || state == DebuggerNotReady); - m_stepAction->setToolTip(QString()); - m_nextAction->setToolTip(QString()); + cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak"); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); + debugMenu->addAction(cmd); + connect(m_breakAction, &QAction::triggered, + this, &DebuggerPluginPrivate::toggleBreakpointHelper); - m_stepOutAction->setEnabled(stopped); - m_runToLineAction->setEnabled(stopped && engine->hasCapability(RunToLineCapability)); - m_runToSelectedFunctionAction->setEnabled(stopped); - m_returnFromFunctionAction-> - setEnabled(stopped && engine->hasCapability(ReturnFromFunctionCapability)); + debugMenu->addSeparator(); - const bool canJump = stopped && engine->hasCapability(JumpToLineCapability); - m_jumpToLineAction->setEnabled(canJump); + // currently broken +// auto qmlUpdateOnSaveDummyAction = new QAction(tr("Apply Changes on Save"), this); +// qmlUpdateOnSaveDummyAction->setCheckable(true); +// qmlUpdateOnSaveDummyAction->setIcon(Icons::APPLY_ON_SAVE.icon()); +// qmlUpdateOnSaveDummyAction->setEnabled(false); +// cmd = ActionManager::registerAction(qmlUpdateOnSaveDummyAction, Constants::QML_UPDATE_ON_SAVE); +// debugMenu->addAction(cmd); - const bool canDeref = actionsEnabled && engine->hasCapability(AutoDerefPointersCapability); - action(AutoDerefPointers)->setEnabled(canDeref); - action(AutoDerefPointers)->setEnabled(true); - action(ExpandStack)->setEnabled(actionsEnabled); + auto qmlShowAppOnTopDummyAction = new QAction(tr("Show Application on Top"), this); + qmlShowAppOnTopDummyAction->setCheckable(true); + qmlShowAppOnTopDummyAction->setIcon(Icons::APP_ON_TOP.icon()); + qmlShowAppOnTopDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlShowAppOnTopDummyAction, Constants::QML_SHOW_APP_ON_TOP); + debugMenu->addAction(cmd); - const bool notbusy = state == InferiorStopOk - || state == DebuggerNotReady - || state == DebuggerFinished - || state == InferiorUnrunnable; - setBusyCursor(!notbusy); -} + auto qmlSelectDummyAction = new QAction(tr("Select"), this); + qmlSelectDummyAction->setCheckable(true); + qmlSelectDummyAction->setIcon(Icons::SELECT.icon()); + qmlSelectDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlSelectDummyAction, Constants::QML_SELECTTOOL); + debugMenu->addAction(cmd); -void DebuggerPluginPrivate::updateDebugActions() -{ - //if we're currently debugging the actions are controlled by engine - if (m_currentEngine->state() != DebuggerNotReady) - return; + auto qmlZoomDummyAction = new QAction(tr("Zoom"), this); + qmlZoomDummyAction->setCheckable(true); + qmlZoomDummyAction->setIcon(Core::Icons::ZOOM.icon()); + qmlZoomDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlZoomDummyAction, Constants::QML_ZOOMTOOL); + debugMenu->addAction(cmd); - Project *project = SessionManager::startupProject(); - QString whyNot; - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); - m_startAction->setEnabled(canRun); - m_startAction->setToolTip(whyNot); - m_debugWithoutDeployAction->setEnabled(canRun); + debugMenu->addSeparator(); - // Step into/next: Start and break at 'main' unless a debugger is running. - if (m_snapshotHandler->currentIndex() < 0) { - QString toolTip; - const bool canRunAndBreakMain - = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN, &toolTip); - m_stepAction->setEnabled(canRunAndBreakMain); - m_nextAction->setEnabled(canRunAndBreakMain); - if (canRunAndBreakMain) { - QTC_ASSERT(project, return ; ); - toolTip = tr("Start \"%1\" and break at function \"main()\"") - .arg(project->displayName()); - } - m_stepAction->setToolTip(toolTip); - m_nextAction->setToolTip(toolTip); - } -} + // Don't add '1' to the string as it shows up in the shortcut dialog. + cmd = ActionManager::registerAction(m_watchAction1, + "Debugger.AddToWatch", cppeditorcontext); + //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W"))); + debugMenu->addAction(cmd); -void DebuggerPluginPrivate::onCoreAboutToOpen() -{ - onModeChangedHelper(ModeManager::currentMode()); -} + // If the CppEditor plugin is there, we want to add something to + // the editor context menu. + if (ActionContainer *editorContextMenu = + ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { + cmd = editorContextMenu->addSeparator(cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); -void DebuggerPluginPrivate::onModeChanged(IMode *mode) -{ - // FIXME: This one gets always called, even if switching between modes - // different then the debugger mode. E.g. Welcome and Help mode and - // also on shutdown. + cmd = ActionManager::registerAction(m_watchAction2, + "Debugger.AddToWatch2", cppDebuggercontext); + cmd->action()->setEnabled(true); + editorContextMenu->addAction(cmd); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_NonConfigurable); + // Debugger.AddToWatch is enough. + } - onModeChangedHelper(mode); + QList<IOptionsPage *> engineOptionPages; + addGdbOptionPages(&engineOptionPages); + addCdbOptionPages(&engineOptionPages); - if (mode->id() != Constants::MODE_DEBUG) { - m_toolTipManager.leavingDebugMode(); - return; - } + foreach (IOptionsPage *op, engineOptionPages) + m_plugin->addAutoReleasedObject(op); + m_plugin->addAutoReleasedObject(new LocalsAndExpressionsOptionsPage); + m_plugin->addAutoReleasedObject(new DebuggerOptionsPage); - if (IEditor *editor = EditorManager::currentEditor()) - editor->widget()->setFocus(); + connect(ModeManager::instance(), &ModeManager::currentModeChanged, + this, &DebuggerPluginPrivate::onModeChanged); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, + this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu); - m_toolTipManager.debugModeEntered(); -} + // Debug mode setup + m_debugMode = new DebugMode; -void DebuggerPluginPrivate::onModeChangedHelper(IMode *mode) -{ - m_inDebugMode = (mode && mode->id() == Constants::MODE_DEBUG); - m_mainWindow->setDockActionsVisible(m_inDebugMode); + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + this, &DebuggerPluginPrivate::updateUiForProject); - // Hide all the debugger windows if mode is different. - if (m_inDebugMode) { -// readWindowSettings(); - updateActiveLanguages(); - } else { - // Hide dock widgets manually in case they are floating. - foreach (QDockWidget *dockWidget, m_mainWindow->dockWidgets()) { - if (dockWidget->isFloating()) - dockWidget->hide(); - } - } -} + auto editorHolderLayout = new QVBoxLayout; + editorHolderLayout->setMargin(0); + editorHolderLayout->setSpacing(0); -void DebuggerPluginPrivate::updateDebugWithoutDeployMenu() -{ - const bool state = ProjectExplorerPlugin::projectExplorerSettings().deployBeforeRun; - m_debugWithoutDeployAction->setVisible(state); -} + auto editorAndFindWidget = new QWidget; + editorAndFindWidget->setLayout(editorHolderLayout); + auto editorManagerPlaceHolder = new EditorManagerPlaceHolder(m_debugMode); + editorHolderLayout->addWidget(editorManagerPlaceHolder); + editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); -void DebuggerPluginPrivate::dumpLog() -{ - QString fileName = QFileDialog::getSaveFileName(ICore::mainWindow(), - tr("Save Debugger Log"), QDir::tempPath()); - if (fileName.isEmpty()) - return; - FileSaver saver(fileName); - if (!saver.hasError()) { - QTextStream ts(saver.file()); - ts << m_logWindow->inputContents(); - ts << "\n\n=======================================\n\n"; - ts << m_logWindow->combinedContents(); - saver.setResult(&ts); - } - saver.finalize(ICore::mainWindow()); -} + auto documentAndRightPane = new MiniSplitter; + documentAndRightPane->addWidget(editorAndFindWidget); + documentAndRightPane->addWidget(new RightPanePlaceHolder(m_debugMode)); + documentAndRightPane->setStretchFactor(0, 1); + documentAndRightPane->setStretchFactor(1, 0); -/*! Activates the previous mode when the current mode is the debug mode. */ -void DebuggerPluginPrivate::activatePreviousMode() -{ - if (ModeManager::currentMode() == ModeManager::mode(MODE_DEBUG) - && m_previousMode.isValid()) { - // If stopping the application also makes Qt Creator active (as the - // "previously active application"), doing the switch synchronously - // leads to funny effects with floating dock widgets - const Core::Id mode = m_previousMode; - QTimer::singleShot(0, this, [mode]() { ModeManager::activateMode(mode); }); - m_previousMode = Id(); - } -} + auto centralWidget = new QWidget; + m_mainWindow->setCentralWidget(centralWidget); -void DebuggerPluginPrivate::activateDebugMode() -{ - m_reverseDirectionAction->setChecked(false); - m_reverseDirectionAction->setEnabled(false); - m_previousMode = ModeManager::currentMode()->id(); - ModeManager::activateMode(MODE_DEBUG); -} + m_mainWindow->finalizeSetup(); -void DebuggerPluginPrivate::sessionLoaded() -{ - m_breakHandler->loadSessionData(); - dummyEngine()->watchHandler()->loadSessionData(); - DebuggerToolTipManager::loadSessionData(); -} + auto centralLayout = new QVBoxLayout(centralWidget); + centralWidget->setLayout(centralLayout); + centralLayout->setMargin(0); + centralLayout->setSpacing(0); + centralLayout->addWidget(documentAndRightPane); + centralLayout->setStretch(0, 1); + centralLayout->setStretch(1, 0); -void DebuggerPluginPrivate::aboutToUnloadSession() -{ - m_toolTipManager.sessionAboutToChange(); -} + // Right-side window with editor, output etc. + auto mainWindowSplitter = new MiniSplitter; + mainWindowSplitter->addWidget(m_mainWindow); + mainWindowSplitter->addWidget(new OutputPanePlaceHolder(m_debugMode, mainWindowSplitter)); + auto outputPane = new OutputPanePlaceHolder(m_debugMode, mainWindowSplitter); + outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); + mainWindowSplitter->addWidget(outputPane); + mainWindowSplitter->setStretchFactor(0, 10); + mainWindowSplitter->setStretchFactor(1, 0); + mainWindowSplitter->setOrientation(Qt::Vertical); -void DebuggerPluginPrivate::aboutToSaveSession() -{ - dummyEngine()->watchHandler()->saveSessionData(); - m_breakHandler->saveSessionData(); - DebuggerToolTipManager::saveSessionData(); -} + // Navigation and right-side window. + auto splitter = new MiniSplitter; + splitter->setFocusProxy(editorManagerPlaceHolder); + splitter->addWidget(new NavigationWidgetPlaceHolder(m_debugMode)); + splitter->addWidget(mainWindowSplitter); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); + splitter->setObjectName(QLatin1String("DebugModeWidget")); -void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout) -{ - showMessage(msg0, LogStatus); - QString msg = msg0; - msg.replace(QChar::LineFeed, QLatin1String("; ")); - m_mainWindow->showStatusMessage(msg, timeout); -} + IContext *modeContextObject = new IContext(this); + modeContextObject->setContext(Context(CC::C_EDITORMANAGER)); + modeContextObject->setWidget(splitter); + ICore::addContextObject(modeContextObject); + m_debugMode->setWidget(splitter); -void DebuggerPluginPrivate::coreShutdown() -{ - m_shuttingDown = true; -} + m_plugin->addAutoReleasedObject(m_debugMode); -const CPlusPlus::Snapshot &cppCodeModelSnapshot() -{ - if (dd->m_codeModelSnapshot.isEmpty() && action(UseCodeModel)->isChecked()) - dd->m_codeModelSnapshot = CppTools::CppModelManager::instance()->snapshot(); - return dd->m_codeModelSnapshot; -} -void setSessionValue(const QByteArray &key, const QVariant &value) -{ - SessionManager::setValue(QString::fromUtf8(key), value); -} + // + // Connections + // -QVariant sessionValue(const QByteArray &key) -{ - return SessionManager::value(QString::fromUtf8(key)); -} + // Core + connect(ICore::instance(), &ICore::saveSettingsRequested, + this, &DebuggerPluginPrivate::writeSettings); -QTreeView *inspectorView() -{ - return dd->m_inspectorView; -} + // TextEditor + connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, + this, &DebuggerPluginPrivate::fontSettingsChanged); -void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int timeout) -{ - //qDebug() << "PLUGIN OUTPUT: " << channel << msg; - //ConsoleWindow *cw = m_consoleWindow; - QTC_ASSERT(m_logWindow, return); - switch (channel) { - case StatusBar: - // This will append to m_logWindow's output pane, too. - showStatusMessage(msg, timeout); - break; - case LogMiscInput: - m_logWindow->showInput(LogMisc, msg); - m_logWindow->showOutput(LogMisc, msg); - break; - case LogInput: - m_logWindow->showInput(LogInput, msg); - m_logWindow->showOutput(LogInput, msg); - break; - case LogError: - m_logWindow->showInput(LogError, QLatin1String("ERROR: ") + msg); - m_logWindow->showOutput(LogError, QLatin1String("ERROR: ") + msg); - break; - default: - m_logWindow->showOutput(channel, msg); - break; - } -} + // ProjectExplorer + connect(SessionManager::instance(), &SessionManager::sessionLoaded, + this, &DebuggerPluginPrivate::sessionLoaded); + connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, + this, &DebuggerPluginPrivate::aboutToSaveSession); + connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession, + this, &DebuggerPluginPrivate::aboutToUnloadSession); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &DebuggerPluginPrivate::updateDebugActions); -static void createNewDock(QWidget *widget) -{ - dd->createDockWidget(Core::Id::fromString(widget->objectName()), widget); - QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget->parentWidget()); - dockWidget->setWindowTitle(widget->windowTitle()); - dockWidget->setFeatures(QDockWidget::DockWidgetClosable); - dockWidget->show(); -} + // EditorManager + connect(EditorManager::instance(), &EditorManager::editorOpened, + this, &DebuggerPluginPrivate::editorOpened); + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, + this, &DebuggerPluginPrivate::updateBreakMenuItem); -static QString formatStartParameters(DebuggerRunParameters &sp) -{ - QString rc; - QTextStream str(&rc); - str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode - << "\nABI: " << sp.toolChainAbi.toString() << '\n'; - str << "Languages: "; - if (sp.languages == AnyLanguage) - str << "any"; - if (sp.languages & CppLanguage) - str << "c++ "; - if (sp.languages & QmlLanguage) - str << "qml"; - str << '\n'; - if (!sp.inferior.executable.isEmpty()) { - str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable) - << ' ' << sp.inferior.commandLineArguments; - if (sp.useTerminal) - str << " [terminal]"; - str << '\n'; - if (!sp.inferior.workingDirectory.isEmpty()) - str << "Directory: " << QDir::toNativeSeparators(sp.inferior.workingDirectory) - << '\n'; - } - QString cmd = sp.debuggerCommand; - if (!cmd.isEmpty()) - str << "Debugger: " << QDir::toNativeSeparators(cmd) << '\n'; - if (!sp.coreFile.isEmpty()) - str << "Core: " << QDir::toNativeSeparators(sp.coreFile) << '\n'; - if (sp.attachPID > 0) - str << "PID: " << sp.attachPID << ' ' << sp.crashParameter << '\n'; - if (!sp.projectSourceDirectory.isEmpty()) { - str << "Project: " << QDir::toNativeSeparators(sp.projectSourceDirectory); - str << "Addtional Search Directories:" - << sp.additionalSearchDirectories.join(QLatin1Char(' ')) << '\n'; - } - if (!sp.qmlServerAddress.isEmpty()) - str << "QML server: " << sp.qmlServerAddress << ':' - << sp.qmlServerPort << '\n'; - if (!sp.remoteChannel.isEmpty()) - str << "Remote: " << sp.remoteChannel << '\n'; - str << "Sysroot: " << sp.sysRoot << '\n'; - str << "Debug Source Location: " << sp.debugSourceLocation.join(QLatin1Char(':')) << '\n'; - return rc; -} + // Application interaction + connect(action(SettingsDialog), &QAction::triggered, + [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); -void DebuggerPluginPrivate::runControlStarted(DebuggerEngine *engine) -{ - activateDebugMode(); - const QString message = tr("Starting debugger \"%1\" for ABI \"%2\"...") - .arg(engine->objectName()) - .arg(engine->runParameters().toolChainAbi.toString()); - showStatusMessage(message); - showMessage(formatStartParameters(engine->runParameters()), LogDebug); - showMessage(m_debuggerSettings->dump(), LogDebug); - m_snapshotHandler->appendSnapshot(engine); - connectEngine(engine); -} + // Toolbar + ToolbarDescription toolbar; + toolbar.addAction(m_visibleStartAction); + toolbar.addAction(m_exitAction); + toolbar.addAction(m_nextAction); + toolbar.addAction(m_stepAction); + toolbar.addAction(m_stepOutAction); + toolbar.addAction(m_resetAction); + toolbar.addAction(m_operateByInstructionAction); -void DebuggerPluginPrivate::runControlFinished(DebuggerEngine *engine) -{ - showStatusMessage(tr("Debugger finished.")); - m_snapshotHandler->removeSnapshot(engine); - if (m_snapshotHandler->size() == 0) { - // Last engine quits. - disconnectEngine(); - if (boolSetting(SwitchModeOnExit)) - activatePreviousMode(); - } else { - // Connect to some existing engine. - m_snapshotHandler->activateSnapshot(0); + if (isReverseDebuggingEnabled()) { + m_reverseToolButton = new QToolButton; + m_reverseToolButton->setDefaultAction(m_reverseDirectionAction); + toolbar.addWidget(m_reverseToolButton); } - action(OperateByInstruction)->setValue(QVariant(false)); - m_logWindow->clearUndoRedoStacks(); -} -void DebuggerPluginPrivate::remoteCommand(const QStringList &options) -{ - if (options.isEmpty()) - return; + toolbar.addWidget(new StyledSeparator); + toolbar.addWidget(new QLabel(tr("Threads:"))); - QString errorMessage; + m_threadBox = new QComboBox; + m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + connect(m_threadBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), + this, &DebuggerPluginPrivate::selectThread); - if (!parseArguments(options, &errorMessage)) { - qWarning("%s", qPrintable(errorMessage)); - return; - } - runScheduled(); -} + toolbar.addWidget(m_threadBox); +// toolbar.addSpacerItem(new QSpacerItem(4, 0)); + +// ToolbarDescription qmlToolbar +// qmlToolbar.addAction(qmlUpdateOnSaveDummyAction); +// qmlToolbar.addAction(qmlShowAppOnTopDummyAction); +// qmlToolbar.addWidget(new StyledSeparator); +// qmlToolbar.addAction(qmlSelectDummyAction); +// qmlToolbar.addAction(qmlZoomDummyAction); +// qmlToolbar.addWidget(new StyledSeparator); + + Perspective basePerspective({}, { + { DOCKWIDGET_STACK, m_stackWindow, {}, Perspective::SplitVertical }, + { DOCKWIDGET_BREAK, m_breakWindow, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, + { DOCKWIDGET_THREADS, m_threadsWindow, DOCKWIDGET_BREAK, Perspective::AddToTab, false }, + { DOCKWIDGET_MODULES, m_modulesWindow, DOCKWIDGET_THREADS, Perspective::AddToTab, false }, + { DOCKWIDGET_SOURCE_FILES, m_sourceFilesWindow, DOCKWIDGET_MODULES, Perspective::AddToTab, false }, + { DOCKWIDGET_SNAPSHOTS, m_snapshotWindow, DOCKWIDGET_SOURCE_FILES, Perspective::AddToTab, false }, + { DOCKWIDGET_WATCHERS, m_localsAndExpressionsWindow, {}, Perspective::AddToTab, true, + Qt::RightDockWidgetArea }, + { DOCKWIDGET_OUTPUT, m_logWindow, {}, Perspective::AddToTab, false, Qt::TopDockWidgetArea }, + { DOCKWIDGET_BREAK, 0, {}, Perspective::Raise } + }); -QMessageBox *showMessageBox(int icon, const QString &title, - const QString &text, int buttons) -{ - QMessageBox *mb = new QMessageBox(QMessageBox::Icon(icon), - title, text, QMessageBox::StandardButtons(buttons), - ICore::mainWindow()); - mb->setAttribute(Qt::WA_DeleteOnClose); - mb->setTextInteractionFlags(Qt::TextSelectableByMouse); - mb->show(); - return mb; + Perspective cppPerspective = basePerspective; + cppPerspective.setName(tr("Debugger")); + cppPerspective.addOperation({ DOCKWIDGET_REGISTER, m_registerWindow, DOCKWIDGET_SNAPSHOTS, + Perspective::AddToTab, false }); + + Debugger::registerToolbar(CppPerspectiveId, toolbar); + Debugger::registerPerspective(CppPerspectiveId, cppPerspective); + +// Perspective qmlPerspective = basePerspective; +// qmlPerspective.setName(tr("QML Debugger")); +// qmlPerspective.addOperation({ DOCKWIDGET_REGISTER, DOCKWIDGET_SNAPSHOTS, +// Perspective::AddToTab, false }); +// +// Debugger::registerToolbar(QmlPerspectiveId, toolbarContainer); +// Debugger::registerPerspective(QmlPerspectiveId, qmlPerspective); + + connect(action(EnableReverseDebugging), &SavedAction::valueChanged, + this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered); + + setInitialState(); + connectEngine(0); + + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + this, &DebuggerPluginPrivate::onCurrentProjectChanged); + + m_commonOptionsPage = new CommonOptionsPage(m_globalDebuggerOptions); + m_plugin->addAutoReleasedObject(m_commonOptionsPage); + + m_globalDebuggerOptions->fromSettings(); + m_watchersWindow->setVisible(false); + m_returnWindow->setVisible(false); + + return true; } -bool isReverseDebuggingEnabled() +void setConfigValue(const QByteArray &name, const QVariant &value) { - static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_ENABLE_REVERSE"); - return enabled; + ICore::settings()->setValue(_("DebugMode/" + name), value); } -bool isReverseDebugging() +QVariant configValue(const QByteArray &name) { - return isReverseDebuggingEnabled() && dd->m_reverseDirectionAction->isChecked(); + return ICore::settings()->value(_("DebugMode/" + name)); } -void DebuggerPluginPrivate::extensionsInitialized() +void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project) { - const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5")); + RunConfiguration *activeRc = 0; + if (project) { + Target *target = project->activeTarget(); + if (target) + activeRc = target->activeRunConfiguration(); + if (!activeRc) + return; + } + for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) { + // Run controls might be deleted during exit. + if (DebuggerEngine *engine = m_snapshotHandler->at(i)) { + DebuggerRunControl *runControl = engine->runControl(); + RunConfiguration *rc = runControl->runConfiguration(); + if (rc == activeRc) { + m_snapshotHandler->setCurrentIndex(i); + updateState(engine); + return; + } + } + } - QSettings *settings = ICore::settings(); + // If we have a running debugger, don't touch it. + if (m_snapshotHandler->size()) + return; - m_debuggerSettings = new DebuggerSettings; - m_debuggerSettings->readSettings(); + // No corresponding debugger found. So we are ready to start one. + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(false); + QString whyNot; + const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); + m_startAction->setEnabled(canRun); + m_startAction->setToolTip(whyNot); + m_debugWithoutDeployAction->setEnabled(canRun); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); +} - connect(ICore::instance(), &ICore::coreAboutToClose, this, &DebuggerPluginPrivate::coreShutdown); +void DebuggerPluginPrivate::startAndDebugApplication() +{ + DebuggerRunParameters rp; + Kit *kit; + if (StartApplicationDialog::run(ICore::dialogParent(), &rp, &kit)) + createAndScheduleRun(rp, kit); +} - const Context cppDebuggercontext(C_CPPDEBUGGER); - const Context cppeditorcontext(CppEditor::Constants::CPPEDITOR_ID); +void DebuggerPluginPrivate::attachCore() +{ + AttachCoreDialog dlg(ICore::dialogParent()); - m_startIcon = Core::Icons::DEBUG_START_SMALL.icon(); - m_exitIcon = Core::Icons::DEBUG_EXIT_SMALL.icon(); - const QIcon continueSideBarIcon = - Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT); - m_continueIcon = Icon::combinedIcon({Core::Icons::DEBUG_CONTINUE_SMALL.icon(), continueSideBarIcon}); - const QIcon interruptSideBarIcon = - Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT); - m_interruptIcon = Icon::combinedIcon({Core::Icons::DEBUG_INTERRUPT_SMALL.icon(), interruptSideBarIcon}); - m_locationMarkIcon = Icons::LOCATION.icon(); - m_resetIcon = Icons::RESTART.icon(); + const QString lastExternalKit = configValue("LastExternalKit").toString(); + if (!lastExternalKit.isEmpty()) + dlg.setKitId(Id::fromString(lastExternalKit)); + dlg.setLocalExecutableFile(configValue("LastExternalExecutableFile").toString()); + dlg.setLocalCoreFile(configValue("LastLocalCoreFile").toString()); + dlg.setRemoteCoreFile(configValue("LastRemoteCoreFile").toString()); + dlg.setOverrideStartScript(configValue("LastExternalStartScript").toString()); + dlg.setForceLocalCoreFile(configValue("LastForceLocalCoreFile").toBool()); - m_busy = false; + if (dlg.exec() != QDialog::Accepted) + return; - m_logWindow = new LogWindow; - m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT)); + setConfigValue("LastExternalExecutableFile", dlg.localExecutableFile()); + setConfigValue("LastLocalCoreFile", dlg.localCoreFile()); + setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile()); + setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); + setConfigValue("LastExternalStartScript", dlg.overrideStartScript()); + setConfigValue("LastForceLocalCoreFile", dlg.forcesLocalCoreFile()); - m_breakHandler = new BreakHandler; - m_breakView = new BreakTreeView; - m_breakView->setSettings(settings, "Debugger.BreakWindow"); - m_breakView->setModel(m_breakHandler->model()); - m_breakWindow = addSearch(m_breakView, tr("Breakpoints"), DOCKWIDGET_BREAK); + QString display = dlg.useLocalCoreFile() ? dlg.localCoreFile() : dlg.remoteCoreFile(); + DebuggerRunParameters rp; + rp.masterEngineType = DebuggerKitInformation::engineType(dlg.kit()); + rp.inferior.executable = dlg.localExecutableFile(); + rp.coreFile = dlg.localCoreFile(); + rp.displayName = tr("Core file \"%1\"").arg(display); + rp.startMode = AttachCore; + rp.closeMode = DetachAtClose; + rp.overrideStartScript = dlg.overrideStartScript(); + createAndScheduleRun(rp, dlg.kit()); +} - m_modulesView = new ModulesTreeView; - m_modulesView->setSettings(settings, "Debugger.ModulesView"); - m_modulesWindow = addSearch(m_modulesView, tr("Modules"), DOCKWIDGET_MODULES); - - m_registerView = new RegisterTreeView; - m_registerView->setSettings(settings, "Debugger.RegisterView"); - m_registerWindow = addSearch(m_registerView, tr("Registers"), DOCKWIDGET_REGISTER); - - m_stackView = new StackTreeView; - m_stackView->setSettings(settings, "Debugger.StackView"); - m_stackWindow = addSearch(m_stackView, tr("Stack"), DOCKWIDGET_STACK); +void DebuggerPluginPrivate::startRemoteCdbSession() +{ + const QByteArray connectionKey = "CdbRemoteConnection"; + DebuggerRunParameters rp; + Kit *kit = findUniversalCdbKit(); + QTC_ASSERT(kit, return); + rp.startMode = AttachToRemoteServer; + rp.closeMode = KillAtClose; + StartRemoteCdbDialog dlg(ICore::dialogParent()); + QString previousConnection = configValue(connectionKey).toString(); + if (previousConnection.isEmpty()) + previousConnection = QLatin1String("localhost:1234"); + dlg.setConnection(previousConnection); + if (dlg.exec() != QDialog::Accepted) + return; + rp.remoteChannel = dlg.connection(); + setConfigValue(connectionKey, rp.remoteChannel); + createAndScheduleRun(rp, kit); +} - m_sourceFilesView = new SourceFilesTreeView; - m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView"); - m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES); +void DebuggerPluginPrivate::attachToRemoteServer() +{ + DebuggerRunParameters rp; + Kit *kit; + rp.startMode = AttachToRemoteServer; + if (StartApplicationDialog::run(ICore::dialogParent(), &rp, &kit)) { + rp.closeMode = KillAtClose; + createAndScheduleRun(rp, kit); + } +} - m_threadsView = new ThreadsTreeView; - m_threadsView->setSettings(settings, "Debugger.ThreadsView"); - m_threadsWindow = addSearch(m_threadsView, tr("Threads"), DOCKWIDGET_THREADS); +void DebuggerPluginPrivate::startRemoteServerAndAttachToProcess() +{ + auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging); + auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent()); + dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); + dlg->showAllDevices(); + if (dlg->exec() == QDialog::Rejected) { + delete dlg; + return; + } - m_returnView = new WatchTreeView(ReturnType); // No settings. - m_returnWindow = addSearch(m_returnView, tr("Locals and Expressions"), "CppDebugReturn"); + dlg->setAttribute(Qt::WA_DeleteOnClose); + Kit *kit = kitChooser->currentKit(); + QTC_ASSERT(kit, return); + IDevice::ConstPtr device = DeviceKitInformation::device(kit); + QTC_ASSERT(device, return); - m_localsView = new WatchTreeView(LocalsType); - m_localsView->setSettings(settings, "Debugger.LocalsView"); - m_localsWindow = addSearch(m_localsView, tr("Locals and Expressions"), "CppDebugLocals"); + GdbServerStarter *starter = new GdbServerStarter(dlg, true); + starter->run(); +} - m_watchersView = new WatchTreeView(WatchersType); // No settings. - m_watchersWindow = addSearch(m_watchersView, tr("Locals and Expressions"), "CppDebugWatchers"); +void DebuggerPluginPrivate::attachToRunningApplication() +{ + auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::LocalDebugging); - m_inspectorView = new WatchTreeView(InspectType); - m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view. - m_inspectorWindow = addSearch(m_inspectorView, tr("Locals and Expressions"), "Inspector"); + auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent()); + dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process")); + dlg->showAllDevices(); + if (dlg->exec() == QDialog::Rejected) { + delete dlg; + return; + } - // Snapshot - m_snapshotHandler = new SnapshotHandler; - m_snapshotView = new SnapshotTreeView(m_snapshotHandler); - m_snapshotView->setSettings(settings, "Debugger.SnapshotView"); - m_snapshotView->setModel(m_snapshotHandler->model()); - m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS); + dlg->setAttribute(Qt::WA_DeleteOnClose); + Kit *kit = kitChooser->currentKit(); + QTC_ASSERT(kit, return); + IDevice::ConstPtr device = DeviceKitInformation::device(kit); + QTC_ASSERT(device, return); - // Watchers - connect(m_localsView->header(), &QHeaderView::sectionResized, - this, &DebuggerPluginPrivate::updateWatchersHeader, Qt::QueuedConnection); + if (device->type() == PE::DESKTOP_DEVICE_TYPE) { + attachToRunningProcess(kit, dlg->currentProcess(), false); + } else { + GdbServerStarter *starter = new GdbServerStarter(dlg, true); + starter->run(); + } +} - QAction *act = 0; +void DebuggerPluginPrivate::attachToUnstartedApplicationDialog() +{ + auto dlg = new UnstartedAppWatcherDialog(ICore::dialogParent()); - act = m_continueAction = new QAction(tr("Continue"), this); - act->setIcon(m_continueIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue); + connect(dlg, &QDialog::finished, dlg, &QObject::deleteLater); + connect(dlg, &UnstartedAppWatcherDialog::processFound, this, [this, dlg] { + DebuggerRunControl *rc = attachToRunningProcess(dlg->currentKit(), + dlg->currentProcess(), + dlg->continueOnAttach()); + if (!rc) + return; - act = m_exitAction = new QAction(tr("Stop Debugger"), this); - act->setIcon(m_exitIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecExit); + if (dlg->hideOnAttach()) + connect(rc, &RunControl::finished, dlg, &UnstartedAppWatcherDialog::startWatching); + }); - act = m_interruptAction = new QAction(tr("Interrupt"), this); - act->setIcon(m_interruptIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt); + dlg->show(); +} - // A "disabled pause" seems to be a good choice. - act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this); - act->setIcon(m_interruptIcon); - act->setEnabled(false); +DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit, + DeviceProcessItem process, bool contAfterAttach) +{ + QTC_ASSERT(kit, return 0); + IDevice::ConstPtr device = DeviceKitInformation::device(kit); + QTC_ASSERT(device, return 0); + if (process.pid == 0) { + AsynchronousMessageBox::warning(tr("Warning"), tr("Cannot attach to process with PID 0")); + return 0; + } - act = m_abortAction = new QAction(tr("Abort Debugging"), this); - act->setToolTip(tr("Aborts debugging and " - "resets the debugger to the initial state.")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort); + bool isWindows = false; + if (const ToolChain *tc = ToolChainKitInformation::toolChain(kit)) + isWindows = tc->targetAbi().os() == Abi::WindowsOS; + if (isWindows && isWinProcessBeingDebugged(process.pid)) { + AsynchronousMessageBox::warning(tr("Process Already Under Debugger Control"), + tr("The process %1 is already under the control of a debugger.\n" + "Qt Creator cannot attach to it.").arg(process.pid)); + return 0; + } - act = m_resetAction = new QAction(tr("Restart Debugging"),this); - act->setToolTip(tr("Restart the debugging session.")); - act->setIcon(m_resetIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset); + if (device->type() != PE::DESKTOP_DEVICE_TYPE) { + AsynchronousMessageBox::warning(tr("Not a Desktop Device Type"), + tr("It is only possible to attach to a locally running process.")); + return 0; + } - act = m_nextAction = new QAction(tr("Step Over"), this); - act->setIcon(Icons::STEP_OVER.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext); + DebuggerRunParameters rp; + rp.attachPID = process.pid; + rp.displayName = tr("Process %1").arg(process.pid); + rp.inferior.executable = process.exe; + rp.startMode = AttachExternal; + rp.closeMode = DetachAtClose; + rp.continueAfterAttach = contAfterAttach; + return createAndScheduleRun(rp, kit); +} - act = m_stepAction = new QAction(tr("Step Into"), this); - act->setIcon(Icons::STEP_INTO.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep); +void DebuggerPlugin::attachExternalApplication(RunControl *rc) +{ + DebuggerRunParameters rp; + rp.attachPID = rc->applicationProcessHandle().pid(); + rp.displayName = tr("Process %1").arg(rp.attachPID); + rp.startMode = AttachExternal; + rp.closeMode = DetachAtClose; + rp.toolChainAbi = rc->abi(); + Kit *kit = 0; + if (const RunConfiguration *runConfiguration = rc->runConfiguration()) + if (const Target *target = runConfiguration->target()) + kit = target->kit(); + createAndScheduleRun(rp, kit); +} - act = m_stepOutAction = new QAction(tr("Step Out"), this); - act->setIcon(Icons::STEP_OUT.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut); +void DebuggerPluginPrivate::attachToQmlPort() +{ + DebuggerRunParameters rp; + AttachToQmlPortDialog dlg(ICore::mainWindow()); - act = m_runToLineAction = new QAction(tr("Run to Line"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine); + const QVariant qmlServerPort = configValue("LastQmlServerPort"); + if (qmlServerPort.isValid()) + dlg.setPort(qmlServerPort.toInt()); + else + dlg.setPort(rp.qmlServerPort); - act = m_runToSelectedFunctionAction = - new QAction(tr("Run to Selected Function"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction); + const Id kitId = Id::fromSetting(configValue("LastProfile")); + if (kitId.isValid()) + dlg.setKitId(kitId); - act = m_returnFromFunctionAction = - new QAction(tr("Immediately Return From Inner Function"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn); + if (dlg.exec() != QDialog::Accepted) + return; - act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine); + Kit *kit = dlg.kit(); + QTC_ASSERT(kit, return); + setConfigValue("LastQmlServerPort", dlg.port()); + setConfigValue("LastProfile", kit->id().toSetting()); - m_breakAction = new QAction(tr("Toggle Breakpoint"), this); + IDevice::ConstPtr device = DeviceKitInformation::device(kit); + if (device) { + rp.connParams = device->sshParameters(); + rp.qmlServerAddress = device->qmlProfilerHost(); + } + rp.qmlServerPort = dlg.port(); + rp.startMode = AttachToRemoteProcess; + rp.closeMode = KillAtClose; + rp.languages = QmlLanguage; + rp.masterEngineType = QmlEngineType; - act = m_watchAction1 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); + // + // get files from all the projects in the session + // + QList<Project *> projects = SessionManager::projects(); + if (Project *startupProject = SessionManager::startupProject()) { + // startup project first + projects.removeOne(startupProject); + projects.insert(0, startupProject); + } + QStringList sourceFiles; + foreach (Project *project, projects) + sourceFiles << project->files(Project::SourceFiles); - act = m_watchAction2 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); + rp.projectSourceDirectory = + !projects.isEmpty() ? projects.first()->projectDirectory().toString() : QString(); + rp.projectSourceFiles = sourceFiles; + createAndScheduleRun(rp, kit); +} - //m_snapshotAction = new QAction(tr("Create Snapshot"), this); - //m_snapshotAction->setProperty(Role, RequestCreateSnapshotRole); - //m_snapshotAction->setIcon(Icons::SNAPSHOT.icon()); +void DebuggerPluginPrivate::enableReverseDebuggingTriggered(const QVariant &value) +{ + QTC_ASSERT(m_reverseToolButton, return); + m_reverseToolButton->setVisible(value.toBool()); + m_reverseDirectionAction->setChecked(false); + m_reverseDirectionAction->setEnabled(value.toBool()); +} - act = m_reverseDirectionAction = new QAction(tr("Reverse Direction"), this); - act->setCheckable(true); - act->setChecked(false); - act->setCheckable(false); - act->setIcon(Icons::REVERSE_MODE.icon()); - act->setIconVisibleInMenu(false); +void DebuggerPluginPrivate::runScheduled() +{ + for (int i = 0, n = m_scheduledStarts.size(); i != n; ++i) + createAndScheduleRun(m_scheduledStarts.at(i).first, m_scheduledStarts.at(i).second); +} - act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown); +void DebuggerPluginPrivate::editorOpened(IEditor *editor) +{ + if (auto widget = qobject_cast<TextEditorWidget *>(editor->widget())) { + connect(widget, &TextEditorWidget::markRequested, + this, &DebuggerPluginPrivate::requestMark); - act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp); + connect(widget, &TextEditorWidget::markContextMenuRequested, + this, &DebuggerPluginPrivate::requestContextMenu); + } +} - connect(action(OperateByInstruction), &QAction::triggered, - this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered); +void DebuggerPluginPrivate::updateBreakMenuItem(IEditor *editor) +{ + BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(editor); + m_breakAction->setEnabled(textEditor != 0); +} - ActionContainer *debugMenu = ActionManager::actionContainer(PE::M_DEBUG); +void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, + int lineNumber, QMenu *menu) +{ + Breakpoint bp; + TextDocument *document = widget->textDocument(); - // Dock widgets - QDockWidget *dock = 0; - dock = createDockWidget(DOCKWIDGET_MODULES, m_modulesWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::modulesDockToggled, Qt::QueuedConnection); + ContextData args = getLocationContext(document, lineNumber); + if (args.type == LocationByAddress) { + BreakpointResponse needle; + needle.type = BreakpointByAddress; + needle.address = args.address; + needle.lineNumber = -1; + bp = breakHandler()->findSimilarBreakpoint(needle); + } else if (args.type == LocationByFile) { + bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber); + if (!bp) + bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber, false); + } - dock = createDockWidget(DOCKWIDGET_REGISTER, m_registerWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::registerDockToggled, Qt::QueuedConnection); + if (bp) { + QString id = bp.id().toString(); - dock = createDockWidget(DOCKWIDGET_SOURCE_FILES, m_sourceFilesWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::sourceFilesDockToggled, Qt::QueuedConnection); + // Remove existing breakpoint. + auto act = menu->addAction(tr("Remove Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.removeBreakpoint(); }); - createDockWidget(DOCKWIDGET_OUTPUT, m_logWindow); - createDockWidget(DOCKWIDGET_BREAK, m_breakWindow); - createDockWidget(DOCKWIDGET_SNAPSHOTS, m_snapshotWindow); - createDockWidget(DOCKWIDGET_STACK, m_stackWindow); - createDockWidget(DOCKWIDGET_THREADS, m_threadsWindow); + // Enable/disable existing breakpoint. + if (bp.isEnabled()) { + act = menu->addAction(tr("Disable Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.setEnabled(false); }); + } else { + act = menu->addAction(tr("Enable Breakpoint %1").arg(id)); + connect(act, &QAction::triggered, [bp] { bp.setEnabled(true); }); + } - m_localsAndExpressionsWindow = new LocalsAndExpressionsWindow( - m_localsWindow, m_inspectorWindow, m_returnWindow, - m_watchersWindow); - m_localsAndExpressionsWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS)); - m_localsAndExpressionsWindow->setWindowTitle(m_localsWindow->windowTitle()); + // Edit existing breakpoint. + act = menu->addAction(tr("Edit Breakpoint %1...").arg(id)); + connect(act, &QAction::triggered, [bp] { + BreakTreeView::editBreakpoint(bp, ICore::dialogParent()); + }); - dock = createDockWidget(DOCKWIDGET_WATCHERS, m_localsAndExpressionsWindow); + } else { + // Handle non-existing breakpoint. + const QString text = args.address + ? tr("Set Breakpoint at 0x%1").arg(args.address, 0, 16) + : tr("Set Breakpoint at Line %1").arg(lineNumber); + auto act = menu->addAction(text); + act->setEnabled(args.isValid()); + connect(act, &QAction::triggered, [this, args] { + breakpointSetMarginActionTriggered(false, args); + }); - m_mainWindow->addDockActionsToMenu(m_viewsMenu->menu()); + // Message trace point + const QString tracePointText = args.address + ? tr("Set Message Tracepoint at 0x%1...").arg(args.address, 0, 16) + : tr("Set Message Tracepoint at Line %1...").arg(lineNumber); + act = menu->addAction(tracePointText); + act->setEnabled(args.isValid()); + connect(act, &QAction::triggered, [this, args] { + breakpointSetMarginActionTriggered(true, args); + }); + } - m_plugin->addAutoReleasedObject(createDebuggerRunControlFactory(m_plugin)); + // Run to, jump to line below in stopped state. + if (currentEngine()->state() == InferiorStopOk && args.isValid()) { + menu->addSeparator(); + if (currentEngine()->hasCapability(RunToLineCapability)) { + auto act = menu->addAction(args.address + ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16) + : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber)); + connect(act, &QAction::triggered, [this, args] { + currentEngine()->executeRunToLine(args); + }); + } + if (currentEngine()->hasCapability(JumpToLineCapability)) { + auto act = menu->addAction(args.address + ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16) + : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber)); + connect(act, &QAction::triggered, [this, args] { + currentEngine()->executeJumpToLine(args); + }); + } + // Disassemble current function in stopped state. + if (currentEngine()->hasCapability(DisassemblerCapability)) { + StackFrame frame; + frame.function = cppFunctionAt(args.fileName, lineNumber, 1); + frame.line = 42; // trick gdb into mixed mode. + if (!frame.function.isEmpty()) { + const QString text = tr("Disassemble Function \"%1\"") + .arg(frame.function); + auto act = new QAction(text, menu); + connect(act, &QAction::triggered, [this, frame] { + currentEngine()->openDisassemblerView(Location(frame)); + }); + menu->addAction(act); + } + } + } +} - // The main "Start Debugging" action. - act = m_startAction = new QAction(this); - const QIcon sideBarIcon = - Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT); - const QIcon debuggerIcon = Icon::combinedIcon({Core::Icons::DEBUG_START_SMALL.icon(), sideBarIcon}); - act->setIcon(debuggerIcon); - act->setText(tr("Start Debugging")); - connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); }); +void DebuggerPluginPrivate::toggleBreakpoint(const ContextData &location, const QString &tracePointMessage) +{ + QTC_ASSERT(location.isValid(), return); + BreakHandler *handler = m_breakHandler; + Breakpoint bp; + if (location.type == LocationByFile) { + bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, true); + if (!bp) + bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, false); + } else if (location.type == LocationByAddress) { + bp = handler->findBreakpointByAddress(location.address); + } - act = m_debugWithoutDeployAction = new QAction(this); - act->setText(tr("Start Debugging Without Deployment")); - connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); }); + if (bp) { + bp.removeBreakpoint(); + } else { + BreakpointParameters data; + if (location.type == LocationByFile) { + data.type = BreakpointByFileAndLine; + if (boolSetting(BreakpointsFullPathByDefault)) + data.pathUsage = BreakpointUseFullPath; + data.tracepoint = !tracePointMessage.isEmpty(); + data.message = tracePointMessage; + data.fileName = location.fileName; + data.lineNumber = location.lineNumber; + } else if (location.type == LocationByAddress) { + data.type = BreakpointByAddress; + data.tracepoint = !tracePointMessage.isEmpty(); + data.message = tracePointMessage; + data.address = location.address; + } + handler->appendBreakpoint(data); + } +} - act = m_startAndDebugApplicationAction = new QAction(this); - act->setText(tr("Start and Debug External Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startAndDebugApplication); +void DebuggerPluginPrivate::toggleBreakpointHelper() +{ + BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor(); + QTC_ASSERT(textEditor, return); + const int lineNumber = textEditor->currentLine(); + ContextData location = getLocationContext(textEditor->textDocument(), lineNumber); + if (location.isValid()) + toggleBreakpoint(location); +} - act = m_attachToCoreAction = new QAction(this); - act->setText(tr("Load Core File...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); +void DebuggerPluginPrivate::requestMark(TextEditorWidget *widget, int lineNumber, + TextMarkRequestKind kind) +{ + if (kind == BreakpointRequest) { + ContextData location = getLocationContext(widget->textDocument(), lineNumber); + if (location.isValid()) + toggleBreakpoint(location); + } +} - act = m_attachToRemoteServerAction = new QAction(this); - act->setText(tr("Attach to Running Debug Server...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRemoteServer); +// If updateEngine is set, the engine will update its threads/modules and so forth. +void DebuggerPluginPrivate::displayDebugger(DebuggerEngine *engine, bool updateEngine) +{ + QTC_ASSERT(engine, return); + disconnectEngine(); + connectEngine(engine); + if (updateEngine) + engine->updateAll(); + engine->updateViews(); +} - act = m_startRemoteServerAction = new QAction(this); - act->setText(tr("Start Debug Server Attached to Process...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess); +void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine) +{ + if (!engine) + engine = dummyEngine(); - act = m_attachToRunningApplication = new QAction(this); - act->setText(tr("Attach to Running Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); + if (m_currentEngine == engine) + return; - act = m_attachToUnstartedApplication = new QAction(this); - act->setText(tr("Attach to Unstarted Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); + if (m_currentEngine) + m_currentEngine->resetLocation(); + m_currentEngine = engine; - act = m_attachToQmlPortAction = new QAction(this); - act->setText(tr("Attach to QML Port...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort); + m_localsView->setModel(engine->watchModel()); + m_modulesView->setModel(engine->modulesModel()); + m_registerView->setModel(engine->registerModel()); + m_returnView->setModel(engine->watchModel()); + m_sourceFilesView->setModel(engine->sourceFilesModel()); + m_stackView->setModel(engine->stackModel()); + m_threadsView->setModel(engine->threadsModel()); + m_watchersView->setModel(engine->watchModel()); + m_inspectorView->setModel(engine->watchModel()); - if (HostOsInfo::isWindowsHost()) { - m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this); - connect(m_startRemoteCdbAction, &QAction::triggered, - this, &DebuggerPluginPrivate::startRemoteCdbSession); - } + engine->watchHandler()->resetWatchers(); + m_localsView->hideProgressIndicator(); +} - act = m_detachAction = new QAction(this); - act->setText(tr("Detach Debugger")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach); +static void changeFontSize(QWidget *widget, qreal size) +{ + QFont font = widget->font(); + font.setPointSizeF(size); + widget->setFont(font); +} - // "Start Debugging" sub-menu - // groups: - // G_DEFAULT_ONE - // G_START_LOCAL - // G_START_REMOTE - // G_START_QML - - Command *cmd = 0; - ActionContainer *mstart = ActionManager::actionContainer(PE::M_DEBUG_STARTDEBUGGING); - - cmd = ActionManager::registerAction(m_startAction, Constants::DEBUG); - cmd->setDescription(tr("Start Debugging")); - cmd->setDefaultKeySequence(debugKey); - cmd->setAttribute(Command::CA_UpdateText); - mstart->addAction(cmd, CC::G_DEFAULT_ONE); - m_visibleStartAction = new ProxyAction(this); - m_visibleStartAction->initialize(cmd->action()); - m_visibleStartAction->setAttribute(ProxyAction::UpdateText); - m_visibleStartAction->setAttribute(ProxyAction::UpdateIcon); - m_visibleStartAction->setAction(cmd->action()); - - ModeManager::addAction(m_visibleStartAction, Constants::P_ACTION_DEBUG); +void DebuggerPluginPrivate::fontSettingsChanged(const FontSettings &settings) +{ + if (!boolSetting(FontSizeFollowsEditor)) + return; + qreal size = settings.fontZoom() * settings.fontSize() / 100.; + changeFontSize(m_breakWindow, size); + changeFontSize(m_logWindow, size); + changeFontSize(m_localsWindow, size); + changeFontSize(m_modulesWindow, size); + //changeFontSize(m_consoleWindow, size); + changeFontSize(m_registerWindow, size); + changeFontSize(m_returnWindow, size); + changeFontSize(m_sourceFilesWindow, size); + changeFontSize(m_stackWindow, size); + changeFontSize(m_threadsWindow, size); + changeFontSize(m_watchersWindow, size); + changeFontSize(m_inspectorWindow, size); +} - cmd = ActionManager::registerAction(m_debugWithoutDeployAction, - "Debugger.DebugWithoutDeploy"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, CC::G_DEFAULT_ONE); +void DebuggerPluginPrivate::cleanupViews() +{ + m_reverseDirectionAction->setChecked(false); + m_reverseDirectionAction->setEnabled(false); - cmd = ActionManager::registerAction(m_attachToRunningApplication, - "Debugger.AttachToRemoteProcess"); - cmd->setDescription(tr("Attach to Running Application")); - mstart->addAction(cmd, G_GENERAL); + const bool closeSource = boolSetting(CloseSourceBuffersOnExit); + const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit); - cmd = ActionManager::registerAction(m_attachToUnstartedApplication, - "Debugger.AttachToUnstartedProcess"); - cmd->setDescription(tr("Attach to Unstarted Application")); - mstart->addAction(cmd, G_GENERAL); + QList<IDocument *> toClose; + foreach (IDocument *document, DocumentModel::openedDocuments()) { + const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool(); + if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) { + bool keepIt = true; + if (document->isModified()) + keepIt = true; + else if (document->filePath().toString().contains(_("qeventdispatcher"))) + keepIt = false; + else if (isMemory) + keepIt = !closeMemory; + else + keepIt = !closeSource; - cmd = ActionManager::registerAction(m_startAndDebugApplicationAction, - "Debugger.StartAndDebugApplication"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, G_GENERAL); + if (keepIt) + document->setProperty(Constants::OPENED_BY_DEBUGGER, false); + else + toClose.append(document); + } + } + EditorManager::closeDocuments(toClose); +} - cmd = ActionManager::registerAction(m_attachToCoreAction, - "Debugger.AttachCore"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_GENERAL); +void DebuggerPluginPrivate::setBusyCursor(bool busy) +{ + //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy); + if (busy == m_busy) + return; + m_busy = busy; + QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor); + m_breakWindow->setCursor(cursor); + //m_consoleWindow->setCursor(cursor); + m_localsWindow->setCursor(cursor); + m_modulesWindow->setCursor(cursor); + m_logWindow->setCursor(cursor); + m_registerWindow->setCursor(cursor); + m_returnWindow->setCursor(cursor); + m_sourceFilesWindow->setCursor(cursor); + m_stackWindow->setCursor(cursor); + m_threadsWindow->setCursor(cursor); + m_watchersWindow->setCursor(cursor); + m_snapshotWindow->setCursor(cursor); +} - cmd = ActionManager::registerAction(m_attachToRemoteServerAction, - "Debugger.AttachToRemoteServer"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_SPECIAL); +void DebuggerPluginPrivate::setInitialState() +{ + m_watchersWindow->setVisible(false); + m_returnWindow->setVisible(false); + setBusyCursor(false); + m_reverseDirectionAction->setChecked(false); + m_reverseDirectionAction->setEnabled(false); + m_toolTipManager.closeAllToolTips(); - cmd = ActionManager::registerAction(m_startRemoteServerAction, - "Debugger.StartRemoteServer"); - cmd->setDescription(tr("Start Gdbserver")); - mstart->addAction(cmd, Constants::G_SPECIAL); + m_startAndDebugApplicationAction->setEnabled(true); + m_attachToQmlPortAction->setEnabled(true); + m_attachToCoreAction->setEnabled(true); + m_attachToRemoteServerAction->setEnabled(true); + m_attachToRunningApplication->setEnabled(true); + m_attachToUnstartedApplication->setEnabled(true); + m_detachAction->setEnabled(false); - if (m_startRemoteCdbAction) { - cmd = ActionManager::registerAction(m_startRemoteCdbAction, - "Debugger.AttachRemoteCdb"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_SPECIAL); - } + m_watchAction1->setEnabled(true); + m_watchAction2->setEnabled(true); + m_breakAction->setEnabled(false); + //m_snapshotAction->setEnabled(false); + m_operateByInstructionAction->setEnabled(false); - mstart->addSeparator(Context(CC::C_GLOBAL), Constants::G_START_QML); + m_exitAction->setEnabled(false); + m_abortAction->setEnabled(false); + m_resetAction->setEnabled(false); - cmd = ActionManager::registerAction(m_attachToQmlPortAction, "Debugger.AttachToQmlPort"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_START_QML); + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); - cmd = ActionManager::registerAction(m_detachAction, "Debugger.Detach"); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + m_stepAction->setEnabled(true); + m_stepOutAction->setEnabled(false); + m_runToLineAction->setEnabled(false); + m_runToSelectedFunctionAction->setEnabled(true); + m_returnFromFunctionAction->setEnabled(false); + m_jumpToLineAction->setEnabled(false); + m_nextAction->setEnabled(true); - cmd = ActionManager::registerAction(m_interruptAction, Constants::INTERRUPT); - cmd->setDescription(tr("Interrupt Debugger")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + action(AutoDerefPointers)->setEnabled(true); + action(ExpandStack)->setEnabled(false); +} - cmd = ActionManager::registerAction(m_continueAction, Constants::CONTINUE); - cmd->setDefaultKeySequence(debugKey); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); +void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) +{ + QTC_ASSERT(engine, return); + QTC_ASSERT(m_watchersView->model(), return); + QTC_ASSERT(m_returnView->model(), return); + QTC_ASSERT(!engine->isSlaveEngine(), return); - cmd = ActionManager::registerAction(m_exitAction, Constants::STOP); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_hiddenStopAction = new ProxyAction(this); - m_hiddenStopAction->initialize(cmd->action()); - m_hiddenStopAction->setAttribute(ProxyAction::UpdateText); - m_hiddenStopAction->setAttribute(ProxyAction::UpdateIcon); + m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThreadIndex()); - cmd = ActionManager::registerAction(m_hiddenStopAction, Constants::HIDDEN_STOP); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+Ctrl+Y") : tr("Shift+F5"))); + const DebuggerState state = engine->state(); + //showMessage(QString::fromLatin1("PLUGIN SET STATE: ") + // + DebuggerEngine::stateName(state), LogStatus); + //qDebug() << "PLUGIN SET STATE: " << state; - cmd = ActionManager::registerAction(m_abortAction, Constants::ABORT); - cmd->setDescription(tr("Reset Debugger")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + static DebuggerState previousState = DebuggerNotReady; + if (state == previousState) + return; - cmd = ActionManager::registerAction(m_resetAction, Constants::RESET); - cmd->setDescription(tr("Restart Debugging")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + bool actionsEnabled = DebuggerEngine::debuggerActionsEnabled(state); - debugMenu->addSeparator(); + if (state == DebuggerNotReady) { + QTC_ASSERT(false, /* We use the Core's m_debugAction here */); + // F5 starts debugging. It is "startable". + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(false); + m_startAction->setEnabled(true); + m_debugWithoutDeployAction->setEnabled(true); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); + m_hiddenStopAction->setAction(m_undisturbableAction); + } else if (state == InferiorStopOk) { + // F5 continues, Shift-F5 kills. It is "continuable". + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(true); + m_exitAction->setEnabled(true); + m_startAction->setEnabled(false); + m_debugWithoutDeployAction->setEnabled(false); + setProxyAction(m_visibleStartAction, Id(Constants::CONTINUE)); + m_hiddenStopAction->setAction(m_exitAction); + m_localsAndExpressionsWindow->setShowLocals(true); + } else if (state == InferiorRunOk) { + // Shift-F5 interrupts. It is also "interruptible". + m_interruptAction->setEnabled(true); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(true); + m_startAction->setEnabled(false); + m_debugWithoutDeployAction->setEnabled(false); + setProxyAction(m_visibleStartAction, Id(Constants::INTERRUPT)); + m_hiddenStopAction->setAction(m_interruptAction); + m_localsAndExpressionsWindow->setShowLocals(false); + activateDebugMode(); + } else if (state == DebuggerFinished) { + Project *project = SessionManager::startupProject(); + const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE); + // We don't want to do anything anymore. + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(false); + m_startAction->setEnabled(canRun); + m_debugWithoutDeployAction->setEnabled(canRun); + setProxyAction(m_visibleStartAction, Id(Constants::DEBUG)); + m_hiddenStopAction->setAction(m_undisturbableAction); + m_codeModelSnapshot = CPlusPlus::Snapshot(); + setBusyCursor(false); + cleanupViews(); + } else if (state == InferiorUnrunnable) { + // We don't want to do anything anymore. + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(true); + m_startAction->setEnabled(false); + m_debugWithoutDeployAction->setEnabled(false); + m_visibleStartAction->setAction(m_undisturbableAction); + m_hiddenStopAction->setAction(m_exitAction); + // show locals in core dumps + m_localsAndExpressionsWindow->setShowLocals(true); + activateDebugMode(); + } else { + // Everything else is "undisturbable". + m_interruptAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_exitAction->setEnabled(false); + m_startAction->setEnabled(false); + m_debugWithoutDeployAction->setEnabled(false); + m_visibleStartAction->setAction(m_undisturbableAction); + m_hiddenStopAction->setAction(m_undisturbableAction); + } - cmd = ActionManager::registerAction(m_nextAction, Constants::NEXT); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10"))); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_UpdateText); - debugMenu->addAction(cmd); + m_startAndDebugApplicationAction->setEnabled(true); + m_attachToQmlPortAction->setEnabled(true); + m_attachToCoreAction->setEnabled(true); + m_attachToRemoteServerAction->setEnabled(true); + m_attachToRunningApplication->setEnabled(true); + m_attachToUnstartedApplication->setEnabled(true); - cmd = ActionManager::registerAction(m_stepAction, Constants::STEP); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11"))); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_UpdateText); - debugMenu->addAction(cmd); + m_threadBox->setEnabled(state == InferiorStopOk || state == InferiorUnrunnable); - cmd = ActionManager::registerAction(m_stepOutAction, - Constants::STEPOUT, cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); + const bool isCore = engine->runParameters().startMode == AttachCore; + const bool stopped = state == InferiorStopOk; + const bool detachable = stopped && !isCore; + m_detachAction->setEnabled(detachable); - cmd = ActionManager::registerAction(m_runToLineAction, - "Debugger.RunToLine", cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+F8") : tr("Ctrl+F10"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); + if (stopped) + QApplication::alert(mainWindow(), 3000); - cmd = ActionManager::registerAction(m_runToSelectedFunctionAction, - "Debugger.RunToSelectedFunction", cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F6"))); - cmd->setAttribute(Command::CA_Hide); - // Don't add to menu by default as keeping its enabled state - // and text up-to-date is a lot of hassle. - // debugMenu->addAction(cmd); + const bool canReverse = engine->hasCapability(ReverseSteppingCapability) + && boolSetting(EnableReverseDebugging); + m_reverseDirectionAction->setEnabled(canReverse); - cmd = ActionManager::registerAction(m_jumpToLineAction, - "Debugger.JumpToLine", cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); + m_watchAction1->setEnabled(true); + m_watchAction2->setEnabled(true); + m_breakAction->setEnabled(true); - cmd = ActionManager::registerAction(m_returnFromFunctionAction, - "Debugger.ReturnFromFunction", cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); + const bool canOperateByInstruction = engine->hasCapability(OperateByInstructionCapability) + && (stopped || isCore); + m_operateByInstructionAction->setEnabled(canOperateByInstruction); - if (isReverseDebuggingEnabled()) { - cmd = ActionManager::registerAction(m_reverseDirectionAction, - Constants::REVERSE, cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? QString() : tr("F12"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - } + m_abortAction->setEnabled(state != DebuggerNotReady + && state != DebuggerFinished); + m_resetAction->setEnabled((stopped || state == DebuggerNotReady) + && engine->hasCapability(ResetInferiorCapability)); - debugMenu->addSeparator(); + m_stepAction->setEnabled(stopped || state == DebuggerNotReady); + m_nextAction->setEnabled(stopped || state == DebuggerNotReady); + m_stepAction->setToolTip(QString()); + m_nextAction->setToolTip(QString()); - //cmd = ActionManager::registerAction(m_snapshotAction, - // "Debugger.Snapshot", cppDebuggercontext); - //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+S"))); - //cmd->setAttribute(Command::CA_Hide); - //debugMenu->addAction(cmd); + m_stepOutAction->setEnabled(stopped); + m_runToLineAction->setEnabled(stopped && engine->hasCapability(RunToLineCapability)); + m_runToSelectedFunctionAction->setEnabled(stopped); + m_returnFromFunctionAction-> + setEnabled(stopped && engine->hasCapability(ReturnFromFunctionCapability)); - ActionManager::registerAction(m_frameDownAction, - "Debugger.FrameDown", cppDebuggercontext); - ActionManager::registerAction(m_frameUpAction, - "Debugger.FrameUp", cppDebuggercontext); + const bool canJump = stopped && engine->hasCapability(JumpToLineCapability); + m_jumpToLineAction->setEnabled(canJump); - cmd = ActionManager::registerAction(action(OperateByInstruction), - Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); + const bool canDeref = actionsEnabled && engine->hasCapability(AutoDerefPointersCapability); + action(AutoDerefPointers)->setEnabled(canDeref); + action(AutoDerefPointers)->setEnabled(true); + action(ExpandStack)->setEnabled(actionsEnabled); - cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak"); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); - debugMenu->addAction(cmd); - connect(m_breakAction, &QAction::triggered, - this, &DebuggerPluginPrivate::toggleBreakpointHelper); + const bool notbusy = state == InferiorStopOk + || state == DebuggerNotReady + || state == DebuggerFinished + || state == InferiorUnrunnable; + setBusyCursor(!notbusy); +} - debugMenu->addSeparator(); +void DebuggerPluginPrivate::updateDebugActions() +{ + //if we're currently debugging the actions are controlled by engine + if (m_currentEngine->state() != DebuggerNotReady) + return; - // currently broken -// QAction *qmlUpdateOnSaveDummyAction = new QAction(tr("Apply Changes on Save"), this); -// qmlUpdateOnSaveDummyAction->setCheckable(true); -// qmlUpdateOnSaveDummyAction->setIcon(Icons::APPLY_ON_SAVE.icon()); -// qmlUpdateOnSaveDummyAction->setEnabled(false); -// cmd = ActionManager::registerAction(qmlUpdateOnSaveDummyAction, Constants::QML_UPDATE_ON_SAVE); -// debugMenu->addAction(cmd); + Project *project = SessionManager::startupProject(); + QString whyNot; + const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); + m_startAction->setEnabled(canRun); + m_startAction->setToolTip(whyNot); + m_debugWithoutDeployAction->setEnabled(canRun); - QAction *qmlShowAppOnTopDummyAction = new QAction(tr("Show Application on Top"), this); - qmlShowAppOnTopDummyAction->setCheckable(true); - qmlShowAppOnTopDummyAction->setIcon(Icons::APP_ON_TOP.icon()); - qmlShowAppOnTopDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlShowAppOnTopDummyAction, Constants::QML_SHOW_APP_ON_TOP); - debugMenu->addAction(cmd); + // Step into/next: Start and break at 'main' unless a debugger is running. + if (m_snapshotHandler->currentIndex() < 0) { + QString toolTip; + const bool canRunAndBreakMain + = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN, &toolTip); + m_stepAction->setEnabled(canRunAndBreakMain); + m_nextAction->setEnabled(canRunAndBreakMain); + if (canRunAndBreakMain) { + QTC_ASSERT(project, return ; ); + toolTip = tr("Start \"%1\" and break at function \"main()\"") + .arg(project->displayName()); + } + m_stepAction->setToolTip(toolTip); + m_nextAction->setToolTip(toolTip); + } +} - QAction *qmlSelectDummyAction = new QAction(tr("Select"), this); - qmlSelectDummyAction->setCheckable(true); - qmlSelectDummyAction->setIcon(Icons::SELECT.icon()); - qmlSelectDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlSelectDummyAction, Constants::QML_SELECTTOOL); - debugMenu->addAction(cmd); +void DebuggerPluginPrivate::updateDebugWithoutDeployMenu() +{ + const bool state = ProjectExplorerPlugin::projectExplorerSettings().deployBeforeRun; + m_debugWithoutDeployAction->setVisible(state); +} - QAction *qmlZoomDummyAction = new QAction(tr("Zoom"), this); - qmlZoomDummyAction->setCheckable(true); - qmlZoomDummyAction->setIcon(Core::Icons::ZOOM.icon()); - qmlZoomDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlZoomDummyAction, Constants::QML_ZOOMTOOL); - debugMenu->addAction(cmd); +void DebuggerPluginPrivate::dumpLog() +{ + QString fileName = QFileDialog::getSaveFileName(ICore::mainWindow(), + tr("Save Debugger Log"), QDir::tempPath()); + if (fileName.isEmpty()) + return; + FileSaver saver(fileName); + if (!saver.hasError()) { + QTextStream ts(saver.file()); + ts << m_logWindow->inputContents(); + ts << "\n\n=======================================\n\n"; + ts << m_logWindow->combinedContents(); + saver.setResult(&ts); + } + saver.finalize(ICore::mainWindow()); +} - debugMenu->addSeparator(); +/*! Activates the previous mode when the current mode is the debug mode. */ +void DebuggerPluginPrivate::activatePreviousMode() +{ + if (ModeManager::currentMode() == ModeManager::mode(MODE_DEBUG) + && m_previousMode.isValid()) { + // If stopping the application also makes Qt Creator active (as the + // "previously active application"), doing the switch synchronously + // leads to funny effects with floating dock widgets + const Core::Id mode = m_previousMode; + QTimer::singleShot(0, this, [mode]() { ModeManager::activateMode(mode); }); + m_previousMode = Id(); + } +} - // Don't add '1' to the string as it shows up in the shortcut dialog. - cmd = ActionManager::registerAction(m_watchAction1, - "Debugger.AddToWatch", cppeditorcontext); - //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W"))); - debugMenu->addAction(cmd); +void DebuggerPluginPrivate::activateDebugMode() +{ + m_reverseDirectionAction->setChecked(false); + m_reverseDirectionAction->setEnabled(false); + m_previousMode = ModeManager::currentMode()->id(); + ModeManager::activateMode(MODE_DEBUG); +} - // If the CppEditor plugin is there, we want to add something to - // the editor context menu. - if (ActionContainer *editorContextMenu = - ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { - cmd = editorContextMenu->addSeparator(cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); +void DebuggerPluginPrivate::sessionLoaded() +{ + m_breakHandler->loadSessionData(); + dummyEngine()->watchHandler()->loadSessionData(); + DebuggerToolTipManager::loadSessionData(); +} - cmd = ActionManager::registerAction(m_watchAction2, - "Debugger.AddToWatch2", cppDebuggercontext); - cmd->action()->setEnabled(true); - editorContextMenu->addAction(cmd); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_NonConfigurable); - // Debugger.AddToWatch is enough. - } +void DebuggerPluginPrivate::aboutToUnloadSession() +{ + m_toolTipManager.sessionAboutToChange(); +} - QList<IOptionsPage *> engineOptionPages; - addGdbOptionPages(&engineOptionPages); - addCdbOptionPages(&engineOptionPages); +void DebuggerPluginPrivate::aboutToSaveSession() +{ + dummyEngine()->watchHandler()->saveSessionData(); + m_breakHandler->saveSessionData(); + DebuggerToolTipManager::saveSessionData(); +} - foreach (IOptionsPage *op, engineOptionPages) - m_plugin->addAutoReleasedObject(op); - m_plugin->addAutoReleasedObject(new LocalsAndExpressionsOptionsPage); - m_plugin->addAutoReleasedObject(new DebuggerOptionsPage); +void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout) +{ + showMessage(msg0, LogStatus); + QString msg = msg0; + msg.replace(QChar::LineFeed, QLatin1String("; ")); + m_mainWindow->showStatusMessage(msg, timeout); +} - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - this, &DebuggerPluginPrivate::onModeChanged); - connect(ICore::instance(), &ICore::coreAboutToOpen, - this, &DebuggerPluginPrivate::onCoreAboutToOpen); - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, - this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu); +void DebuggerPluginPrivate::coreShutdown() +{ + m_shuttingDown = true; +} - // Debug mode setup - DebugMode *debugMode = new DebugMode; - QWidget *widget = createContents(debugMode); - IContext *modeContextObject = new IContext(this); - modeContextObject->setContext(Context(CC::C_EDITORMANAGER)); - modeContextObject->setWidget(widget); - ICore::addContextObject(modeContextObject); - debugMode->setWidget(widget); +const CPlusPlus::Snapshot &cppCodeModelSnapshot() +{ + if (dd->m_codeModelSnapshot.isEmpty() && action(UseCodeModel)->isChecked()) + dd->m_codeModelSnapshot = CppTools::CppModelManager::instance()->snapshot(); + return dd->m_codeModelSnapshot; +} - m_plugin->addAutoReleasedObject(debugMode); +void setSessionValue(const QByteArray &key, const QVariant &value) +{ + SessionManager::setValue(QString::fromUtf8(key), value); +} - // - // Connections - // +QVariant sessionValue(const QByteArray &key) +{ + return SessionManager::value(QString::fromUtf8(key)); +} - // Core - connect(ICore::instance(), &ICore::saveSettingsRequested, - this, &DebuggerPluginPrivate::writeSettings); +QTreeView *inspectorView() +{ + return dd->m_inspectorView; +} - // TextEditor - connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, - this, &DebuggerPluginPrivate::fontSettingsChanged); +void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int timeout) +{ + //qDebug() << "PLUGIN OUTPUT: " << channel << msg; + QTC_ASSERT(m_logWindow, return); + switch (channel) { + case StatusBar: + // This will append to m_logWindow's output pane, too. + showStatusMessage(msg, timeout); + break; + case LogMiscInput: + m_logWindow->showInput(LogMisc, msg); + m_logWindow->showOutput(LogMisc, msg); + break; + case LogInput: + m_logWindow->showInput(LogInput, msg); + m_logWindow->showOutput(LogInput, msg); + break; + case LogError: + m_logWindow->showInput(LogError, QLatin1String("ERROR: ") + msg); + m_logWindow->showOutput(LogError, QLatin1String("ERROR: ") + msg); + break; + default: + m_logWindow->showOutput(channel, msg); + break; + } +} - // ProjectExplorer - connect(SessionManager::instance(), &SessionManager::sessionLoaded, - this, &DebuggerPluginPrivate::sessionLoaded); - connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, - this, &DebuggerPluginPrivate::aboutToSaveSession); - connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession, - this, &DebuggerPluginPrivate::aboutToUnloadSession); - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &DebuggerPluginPrivate::updateDebugActions); +static void createNewDock(QWidget *widget) +{ +// m_mainWindow->registerDockWidget(dockId, widget); - // EditorManager - connect(EditorManager::instance(), &EditorManager::editorOpened, - this, &DebuggerPluginPrivate::editorOpened); - connect(EditorManager::instance(), &EditorManager::currentEditorChanged, - this, &DebuggerPluginPrivate::updateBreakMenuItem); +// QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget->parentWidget()); +// //dockWidget->installEventFilter(&m_resizeEventFilter); - // Application interaction - connect(action(SettingsDialog), &QAction::triggered, - [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); +// QAction *toggleViewAction = dockWidget->toggleViewAction(); +// Command *cmd = ActionManager::registerAction(toggleViewAction, +// Id("Debugger.").withSuffix(widget->objectName())); +// cmd->setAttribute(Command::CA_Hide); +// dd->createDockWidget(Core::Id::fromString(widget->objectName()), widget); +// QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget->parentWidget()); +// QDockWidget *dockWidget = Debugger::registerDockWidget(Id::fromString(widget->objectName()), widget); + QDockWidget *dockWidget = new QDockWidget; + dockWidget->setWidget(widget); - // Toolbar - QWidget *toolbarContainer = new QWidget(mainWindow()); + dockWidget->setWindowTitle(widget->windowTitle()); + dockWidget->setFeatures(QDockWidget::DockWidgetClosable); + dockWidget->show(); +} + +static QString formatStartParameters(DebuggerRunParameters &sp) +{ + QString rc; + QTextStream str(&rc); + str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode + << "\nABI: " << sp.toolChainAbi.toString() << '\n'; + str << "Languages: "; + if (sp.languages == AnyLanguage) + str << "any"; + if (sp.languages & CppLanguage) + str << "c++ "; + if (sp.languages & QmlLanguage) + str << "qml"; + str << '\n'; + if (!sp.inferior.executable.isEmpty()) { + str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable) + << ' ' << sp.inferior.commandLineArguments; + if (sp.useTerminal) + str << " [terminal]"; + str << '\n'; + if (!sp.inferior.workingDirectory.isEmpty()) + str << "Directory: " << QDir::toNativeSeparators(sp.inferior.workingDirectory) + << '\n'; + } + QString cmd = sp.debuggerCommand; + if (!cmd.isEmpty()) + str << "Debugger: " << QDir::toNativeSeparators(cmd) << '\n'; + if (!sp.coreFile.isEmpty()) + str << "Core: " << QDir::toNativeSeparators(sp.coreFile) << '\n'; + if (sp.attachPID > 0) + str << "PID: " << sp.attachPID << ' ' << sp.crashParameter << '\n'; + if (!sp.projectSourceDirectory.isEmpty()) { + str << "Project: " << QDir::toNativeSeparators(sp.projectSourceDirectory); + str << "Addtional Search Directories:" + << sp.additionalSearchDirectories.join(QLatin1Char(' ')) << '\n'; + } + if (!sp.qmlServerAddress.isEmpty()) + str << "QML server: " << sp.qmlServerAddress << ':' + << sp.qmlServerPort << '\n'; + if (!sp.remoteChannel.isEmpty()) + str << "Remote: " << sp.remoteChannel << '\n'; + str << "Sysroot: " << sp.sysRoot << '\n'; + str << "Debug Source Location: " << sp.debugSourceLocation.join(QLatin1Char(':')) << '\n'; + return rc; +} - QHBoxLayout *hbox = new QHBoxLayout(toolbarContainer); - hbox->setMargin(0); - hbox->setSpacing(0); - hbox->addWidget(toolButton(m_visibleStartAction)); - hbox->addWidget(toolButton(Constants::STOP)); - hbox->addWidget(toolButton(Constants::NEXT)); - hbox->addWidget(toolButton(Constants::STEP)); - hbox->addWidget(toolButton(Constants::STEPOUT)); - hbox->addWidget(toolButton(Constants::RESET)); - hbox->addWidget(toolButton(Constants::OPERATE_BY_INSTRUCTION)); +void DebuggerPluginPrivate::runControlStarted(DebuggerEngine *engine) +{ + activateDebugMode(); + const QString message = tr("Starting debugger \"%1\" for ABI \"%2\"...") + .arg(engine->objectName()) + .arg(engine->runParameters().toolChainAbi.toString()); + showStatusMessage(message); + showMessage(formatStartParameters(engine->runParameters()), LogDebug); + showMessage(m_debuggerSettings->dump(), LogDebug); + m_snapshotHandler->appendSnapshot(engine); + connectEngine(engine); +} - if (isReverseDebuggingEnabled()) { - m_reverseToolButton = toolButton(Constants::REVERSE); - hbox->addWidget(m_reverseToolButton); +void DebuggerPluginPrivate::runControlFinished(DebuggerEngine *engine) +{ + showStatusMessage(tr("Debugger finished.")); + m_snapshotHandler->removeSnapshot(engine); + if (m_snapshotHandler->size() == 0) { + // Last engine quits. + disconnectEngine(); + if (boolSetting(SwitchModeOnExit)) + activatePreviousMode(); + } else { + // Connect to some existing engine. + m_snapshotHandler->activateSnapshot(0); } + m_operateByInstructionAction->setChecked(false); + m_logWindow->clearUndoRedoStacks(); +} - hbox->addWidget(new StyledSeparator); - hbox->addWidget(new QLabel(tr("Threads:"))); - - m_threadBox = new QComboBox; - m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - connect(m_threadBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated), - this, &DebuggerPluginPrivate::selectThread); - - hbox->addWidget(m_threadBox); - hbox->addSpacerItem(new QSpacerItem(4, 0)); - - QWidget *qmlToolbar = new QWidget(mainWindow()); - hbox = new QHBoxLayout(qmlToolbar); - hbox->setMargin(0); - hbox->setSpacing(0); - // currently broken - //hbox->addWidget(toolButton(Constants::QML_UPDATE_ON_SAVE)); - hbox->addWidget(toolButton(Constants::QML_SHOW_APP_ON_TOP)); - hbox->addWidget(new StyledSeparator); - hbox->addWidget(toolButton(Constants::QML_SELECTTOOL)); - hbox->addWidget(toolButton(Constants::QML_ZOOMTOOL)); - hbox->addWidget(new StyledSeparator); - - m_mainWindow->registerToolbar(CppPerspectiveId, toolbarContainer); - m_mainWindow->registerPerspective(CppPerspectiveId, { - { DOCKWIDGET_STACK, Core::Id(), Perspective::SplitVertical }, - { DOCKWIDGET_BREAK, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, - { DOCKWIDGET_MODULES, DOCKWIDGET_BREAK, Perspective::AddToTab }, - { DOCKWIDGET_SOURCE_FILES, DOCKWIDGET_MODULES, Perspective::AddToTab }, - { DOCKWIDGET_WATCHERS, Core::Id(), Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_REGISTER, DOCKWIDGET_WATCHERS, Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_OUTPUT, Core::Id(), Perspective::AddToTab, - false, Qt::TopDockWidgetArea } - }); - - m_mainWindow->registerToolbar(QmlPerspectiveId, toolbarContainer); - m_mainWindow->registerPerspective(QmlPerspectiveId, { - { DOCKWIDGET_STACK, Core::Id(), Perspective::SplitVertical }, - { DOCKWIDGET_BREAK, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, - { DOCKWIDGET_MODULES, DOCKWIDGET_BREAK, Perspective::AddToTab }, - { DOCKWIDGET_SOURCE_FILES, DOCKWIDGET_MODULES, Perspective::AddToTab }, - { DOCKWIDGET_WATCHERS, Core::Id(), Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_OUTPUT, Core::Id(), Perspective::AddToTab, - false, Qt::TopDockWidgetArea } - }); +void DebuggerPluginPrivate::remoteCommand(const QStringList &options) +{ + if (options.isEmpty()) + return; - connect(action(EnableReverseDebugging), &SavedAction::valueChanged, - this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered); + QString errorMessage; - setInitialState(); - connectEngine(0); + if (!parseArguments(options, &errorMessage)) { + qWarning("%s", qPrintable(errorMessage)); + return; + } + runScheduled(); +} - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, - this, &DebuggerPluginPrivate::onCurrentProjectChanged); +QMessageBox *showMessageBox(int icon, const QString &title, + const QString &text, int buttons) +{ + QMessageBox *mb = new QMessageBox(QMessageBox::Icon(icon), + title, text, QMessageBox::StandardButtons(buttons), + ICore::mainWindow()); + mb->setAttribute(Qt::WA_DeleteOnClose); + mb->setTextInteractionFlags(Qt::TextSelectableByMouse); + mb->show(); + return mb; +} - m_commonOptionsPage = new CommonOptionsPage(m_globalDebuggerOptions); - m_plugin->addAutoReleasedObject(m_commonOptionsPage); +bool isReverseDebuggingEnabled() +{ + static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_ENABLE_REVERSE"); + return enabled; +} - m_globalDebuggerOptions->fromSettings(); - m_watchersWindow->setVisible(false); - m_returnWindow->setVisible(false); +bool isReverseDebugging() +{ + return isReverseDebuggingEnabled() && dd->m_reverseDirectionAction->isChecked(); +} - // time gdb -i mi -ex 'b debuggerplugin.cpp:800' -ex r -ex q bin/qtcreator.bin +void DebuggerPluginPrivate::extensionsInitialized() +{ } DebuggerEngine *currentEngine() @@ -3174,11 +3163,6 @@ void displayDebugger(DebuggerEngine *engine, bool updateEngine) dd->displayDebugger(engine, updateEngine); } -DebuggerLanguages activeLanguages() -{ - return dd->activeDebugLanguages(); -} - void synchronizeBreakpoints() { dd->synchronizeBreakpoints(); @@ -3186,7 +3170,7 @@ void synchronizeBreakpoints() QWidget *mainWindow() { - return dd->mainWindow(); + return dd->m_mainWindow; } bool isDockVisible(const QString &objectName) @@ -3215,8 +3199,6 @@ QSharedPointer<Internal::GlobalDebuggerOptions> globalDebuggerOptions() return dd->m_globalDebuggerOptions; } -} // namespace Internal - /////////////////////////////////////////////////////////////////////// // // DebuggerPlugin @@ -3272,12 +3254,9 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess KitManager::registerKitInformation(new DebuggerKitInformation); - // Ex-Analyzer stuff - (void) new AnalyzerManager(this); - // Task integration. //: Category under which Analyzer tasks are listed in Issues view - ProjectExplorer::TaskHub::addCategory(Analyzer::Constants::ANALYZERTASK_ID, tr("Analyzer")); + ProjectExplorer::TaskHub::addCategory(Debugger::Constants::ANALYZERTASK_ID, tr("Debugger")); return dd->initialize(arguments, errorMessage); } @@ -3286,7 +3265,7 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown() { removeObject(this); dd->aboutToShutdown(); - AnalyzerManager::shutdown(); + dd->m_mainWindow->saveCurrentPerspective(); return SynchronousShutdown; } @@ -3317,7 +3296,8 @@ void DebuggerPluginPrivate::updateUiForProject(Project *project) return; } connect(project, &Project::activeTargetChanged, - this, &DebuggerPluginPrivate::updateUiForTarget); + this, &DebuggerPluginPrivate::updateUiForTarget, + Qt::QueuedConnection); updateUiForTarget(project->activeTarget()); } @@ -3336,178 +3316,340 @@ void DebuggerPluginPrivate::updateUiForTarget(Target *target) } connect(target, &Target::activeRunConfigurationChanged, - this, &DebuggerPluginPrivate::updateUiForRunConfiguration); + this, &DebuggerPluginPrivate::updateUiForRunConfiguration, + Qt::QueuedConnection); updateUiForRunConfiguration(target->activeRunConfiguration()); } // updates default debug language settings per run config. void DebuggerPluginPrivate::updateUiForRunConfiguration(RunConfiguration *rc) { - if (m_previousRunConfiguration) - disconnect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, - this, &DebuggerPluginPrivate::updateActiveLanguages); - m_previousRunConfiguration = rc; +// if (m_previousRunConfiguration) +// disconnect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, +// this, &DebuggerPluginPrivate::updateActiveLanguages); +// m_previousRunConfiguration = rc; + Q_UNUSED(rc); // FIXME updateActiveLanguages(); - if (m_previousRunConfiguration) - connect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, - this, &DebuggerPluginPrivate::updateActiveLanguages); +// if (m_previousRunConfiguration) +// connect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, +// this, &DebuggerPluginPrivate::updateActiveLanguages, +// Qt::QueuedConnection); } void DebuggerPluginPrivate::updateActiveLanguages() { - if (!(activeDebugLanguages() & QmlLanguage)) - m_mainWindow->restorePerspective(CppPerspectiveId); - else - m_mainWindow->restorePerspective(QmlPerspectiveId); +// DebuggerLanguages languages = dd->m_currentEngine->runParameters().languages; +// Id perspective = (languages & QmlLanguage) && !(languages & CppLanguage) +// ? QmlPerspectiveId : CppPerspectiveId; +// m_mainWindow->restorePerspective(perspective); } -DebuggerLanguages DebuggerPluginPrivate::activeDebugLanguages() const +//bool DockWidgetEventFilter::eventFilter(QObject *obj, QEvent *event) +//{ +// switch (event->type()) { +// case QEvent::Resize: +// case QEvent::ZOrderChange: +// dd->updateDockWidgetSettings(); +// break; +// default: +// break; +// } +// return QObject::eventFilter(obj, event); +//} + +bool DebuggerPluginPrivate::showPromptDialog(const QString &title, const QString &text, + const QString &stopButtonText, const QString &cancelButtonText) const { - return dd->m_currentEngine->runParameters().languages; + CheckableMessageBox messageBox(ICore::mainWindow()); + messageBox.setWindowTitle(title); + messageBox.setText(text); + messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel); + if (!stopButtonText.isEmpty()) + messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText); + if (!cancelButtonText.isEmpty()) + messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText); + messageBox.setDefaultButton(QDialogButtonBox::Yes); + messageBox.setCheckBoxVisible(false); + messageBox.exec(); + return messageBox.clickedStandardButton() == QDialogButtonBox::Yes; } -void DebuggerPluginPrivate::createViewsMenuItems() +void DebuggerPluginPrivate::onModeChanged(IMode *mode) { - Context debugcontext(Constants::C_DEBUGMODE); - m_viewsMenu = ActionManager::actionContainer(Id(Core::Constants::M_WINDOW_VIEWS)); - QTC_ASSERT(m_viewsMenu, return); + // FIXME: This one gets always called, even if switching between modes + // different then the debugger mode. E.g. Welcome and Help mode and + // also on shutdown. - auto openMemoryEditorAction = new QAction(this); - openMemoryEditorAction->setText(DebuggerPluginPrivate::tr("Memory...")); - connect(openMemoryEditorAction, &QAction::triggered, - this, &Internal::openMemoryEditor); + if (mode && mode->id() == MODE_DEBUG) { + if (IEditor *editor = EditorManager::currentEditor()) + editor->widget()->setFocus(); - // Add menu items - Command *cmd = 0; - cmd = ActionManager::registerAction(openMemoryEditorAction, - "Debugger.Views.OpenMemoryEditor", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator1(), - "Debugger.Views.Separator1", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator2(), - "Debugger.Views.Separator2", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + m_toolTipManager.debugModeEntered(); + m_mainWindow->setDockActionsVisible(true); + m_mainWindow->restorePerspective({}); + +// static bool firstTime = true; +// if (firstTime) { + +// // Dock widgets +// connect(m_mainWindow->dockWidget(DOCKWIDGET_MODULES)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::modulesDockToggled, Qt::QueuedConnection); +// connect(m_mainWindow->dockWidget(DOCKWIDGET_OUTPUT)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::registerDockToggled, Qt::QueuedConnection); +// connect(m_mainWindow->dockWidget(DOCKWIDGET_SOURCE_FILES)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::sourceFilesDockToggled, Qt::QueuedConnection); + +// firstTime = false; +// } + updateActiveLanguages(); + } else { + m_toolTipManager.leavingDebugMode(); + m_mainWindow->setDockActionsVisible(false); + + // Hide dock widgets manually in case they are floating. + foreach (QDockWidget *dockWidget, m_mainWindow->dockWidgets()) { + if (dockWidget->isFloating()) + dockWidget->hide(); + } + } } -/*! - Keep track of dock widgets so they can be shown/hidden for different languages -*/ -QDockWidget *DebuggerPluginPrivate::createDockWidget(Core::Id dockId, QWidget *widget) +void DebuggerPluginPrivate::selectPerspective(const QByteArray &perspectiveId) +{ + m_mainWindow->restorePerspective(perspectiveId); +} + +void DebuggerPluginPrivate::registerAction(Id actionId, const ActionDescription &desc, QAction *startAction) { - m_mainWindow->registerDockWidget(dockId, widget); + auto action = new QAction(this); + action->setText(desc.text()); + action->setToolTip(desc.toolTip()); + m_actions.insert(actionId, action); + m_descriptions.insert(actionId, desc); - QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget->parentWidget()); + Id menuGroup = desc.menuGroup(); + if (menuGroup.isValid()) { + Command *command = ActionManager::registerAction(action, actionId); + m_menu->addAction(command, menuGroup); + } - QAction *toggleViewAction = dockWidget->toggleViewAction(); - Command *cmd = ActionManager::registerAction(toggleViewAction, - Id("Debugger.").withSuffix(widget->objectName())); - cmd->setAttribute(Command::CA_Hide); + connect(action, &QAction::triggered, this, [this, desc] { desc.startTool(); }); - //dockWidget->installEventFilter(&m_resizeEventFilter); - return dockWidget; + if (startAction) { + QObject::connect(startAction, &QAction::triggered, action, &QAction::triggered); + + QObject::connect(startAction, &QAction::changed, action, [action, startAction] { + action->setEnabled(startAction->isEnabled()); + }); + } } -QWidget *DebuggerPluginPrivate::createContents(IMode *mode) +} // namespace Internal + +bool ActionDescription::isRunnable(QString *reason) const { - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, - this, &DebuggerPluginPrivate::updateUiForProject); + if (m_customToolStarter) // Something special. Pretend we can always run it. + return true; - auto editorHolderLayout = new QVBoxLayout; - editorHolderLayout->setMargin(0); - editorHolderLayout->setSpacing(0); + return ProjectExplorerPlugin::canRun(SessionManager::startupProject(), m_runMode, reason); +} - auto editorAndFindWidget = new QWidget; - editorAndFindWidget->setLayout(editorHolderLayout); - auto editorManagerPlaceHolder = new EditorManagerPlaceHolder(mode); - editorHolderLayout->addWidget(editorManagerPlaceHolder); - editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); +static bool buildTypeAccepted(QFlags<ToolMode> toolMode, BuildConfiguration::BuildType buildType) +{ + if (buildType == BuildConfiguration::Unknown) + return true; + if (buildType == BuildConfiguration::Debug && (toolMode & DebugMode)) + return true; + if (buildType == BuildConfiguration::Release && (toolMode & ReleaseMode)) + return true; + if (buildType == BuildConfiguration::Profile && (toolMode & ProfileMode)) + return true; + return false; +} - auto documentAndRightPane = new MiniSplitter; - documentAndRightPane->addWidget(editorAndFindWidget); - documentAndRightPane->addWidget(new RightPanePlaceHolder(mode)); - documentAndRightPane->setStretchFactor(0, 1); - documentAndRightPane->setStretchFactor(1, 0); +void ActionDescription::startTool() const +{ + TaskHub::clearTasks(Constants::ANALYZERTASK_ID); + Debugger::selectPerspective(m_perspectiveId); - auto viewButton = new QToolButton(); - viewButton->setText(tr("Views")); - - auto debugToolBar = new Utils::StyledBar; - debugToolBar->setProperty("topBorder", true); - auto debugToolBarLayout = new QHBoxLayout(debugToolBar); - debugToolBarLayout->setMargin(0); - debugToolBarLayout->setSpacing(0); -// debugToolBarLayout->addWidget(m_mainWindow->toolBox()); - debugToolBarLayout->addWidget(m_mainWindow->controlsStack()); - debugToolBarLayout->addWidget(m_mainWindow->statusLabel()); - debugToolBarLayout->addWidget(new Utils::StyledSeparator); - debugToolBarLayout->addStretch(); - debugToolBarLayout->addWidget(viewButton); - - connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { - QMenu menu; - m_mainWindow->addDockActionsToMenu(&menu); - menu.exec(viewButton->mapToGlobal(QPoint())); - }); + if (m_toolPreparer && !m_toolPreparer()) + return; - auto dock = new QDockWidget(DebuggerPluginPrivate::tr("Debugger Toolbar")); - dock->setObjectName(QLatin1String("Debugger Toolbar")); - dock->setWidget(debugToolBar); - dock->setFeatures(QDockWidget::NoDockWidgetFeatures); - dock->setAllowedAreas(Qt::BottomDockWidgetArea); - dock->setTitleBarWidget(new QWidget(dock)); - dock->setProperty("managed_dockwidget", QLatin1String("true")); - m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock); - m_mainWindow->setToolBarDockWidget(dock); + // ### not sure if we're supposed to check if the RunConFiguration isEnabled + Project *pro = SessionManager::startupProject(); + RunConfiguration *rc = 0; + BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; + if (pro) { + if (const Target *target = pro->activeTarget()) { + // Build configuration is 0 for QML projects. + if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration()) + buildType = buildConfig->buildType(); + rc = target->activeRunConfiguration(); + } + } - auto centralWidget = new QWidget; - m_mainWindow->setCentralWidget(centralWidget); + // Custom start. + if (m_customToolStarter) { + if (rc) { + m_customToolStarter(rc); + } else { + QMessageBox *errorDialog = new QMessageBox(ICore::mainWindow()); + errorDialog->setIcon(QMessageBox::Warning); + errorDialog->setWindowTitle(m_text); + errorDialog->setText(tr("Cannot start %1 without a project. Please open the project " + "and try again.").arg(m_text)); + errorDialog->setStandardButtons(QMessageBox::Ok); + errorDialog->setDefaultButton(QMessageBox::Ok); + errorDialog->show(); + } + return; + } - auto centralLayout = new QVBoxLayout(centralWidget); - centralWidget->setLayout(centralLayout); - centralLayout->setMargin(0); - centralLayout->setSpacing(0); - centralLayout->addWidget(documentAndRightPane); - centralLayout->setStretch(0, 1); - centralLayout->setStretch(1, 0); + // Check the project for whether the build config is in the correct mode + // if not, notify the user and urge him to use the correct mode. + if (!buildTypeAccepted(m_toolMode, buildType)) { + QString currentMode; + switch (buildType) { + case BuildConfiguration::Debug: + currentMode = tr("Debug"); + break; + case BuildConfiguration::Profile: + currentMode = tr("Profile"); + break; + case BuildConfiguration::Release: + currentMode = tr("Release"); + break; + default: + QTC_CHECK(false); + } - // Right-side window with editor, output etc. - auto mainWindowSplitter = new MiniSplitter; - mainWindowSplitter->addWidget(m_mainWindow); - auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); - outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); - mainWindowSplitter->addWidget(outputPane); - mainWindowSplitter->setStretchFactor(0, 10); - mainWindowSplitter->setStretchFactor(1, 0); - mainWindowSplitter->setOrientation(Qt::Vertical); + QString toolModeString; + switch (m_toolMode) { + case DebugMode: + toolModeString = tr("in Debug mode"); + break; + case ProfileMode: + toolModeString = tr("in Profile mode"); + break; + case ReleaseMode: + toolModeString = tr("in Release mode"); + break; + case SymbolsMode: + toolModeString = tr("with debug symbols (Debug or Profile mode)"); + break; + case OptimizedMode: + toolModeString = tr("on optimized code (Profile or Release mode)"); + break; + default: + QTC_CHECK(false); + } + const QString toolName = m_text; // The action text is always the name of the tool + const QString title = tr("Run %1 in %2 Mode?").arg(toolName).arg(currentMode); + const QString message = tr("<html><head/><body><p>You are trying " + "to run the tool \"%1\" on an application in %2 mode. " + "The tool is designed to be used %3.</p><p>" + "Run-time characteristics differ significantly between " + "optimized and non-optimized binaries. Analytical " + "findings for one mode may or may not be relevant for " + "the other.</p><p>" + "Running tools that need debug symbols on binaries that " + "don't provide any may lead to missing function names " + "or otherwise insufficient output.</p><p>" + "Do you want to continue and run the tool in %2 mode?</p></body></html>") + .arg(toolName).arg(currentMode).arg(toolModeString); + if (Utils::CheckableMessageBox::doNotAskAgainQuestion(ICore::mainWindow(), + title, message, ICore::settings(), QLatin1String("AnalyzerCorrectModeWarning")) + != QDialogButtonBox::Yes) + return; + } - // Navigation and right-side window. - auto splitter = new MiniSplitter; - splitter->setFocusProxy(editorManagerPlaceHolder); - splitter->addWidget(new NavigationWidgetPlaceHolder(mode)); - splitter->addWidget(mainWindowSplitter); - splitter->setStretchFactor(0, 0); - splitter->setStretchFactor(1, 1); - splitter->setObjectName(QLatin1String("DebugModeWidget")); - return splitter; + ProjectExplorerPlugin::runStartupProject(m_runMode); } -//bool DockWidgetEventFilter::eventFilter(QObject *obj, QEvent *event) -//{ -// switch (event->type()) { -// case QEvent::Resize: -// case QEvent::ZOrderChange: -// dd->updateDockWidgetSettings(); -// break; -// default: -// break; -// } -// return QObject::eventFilter(obj, event); -//} +void registerAction(Id actionId, const ActionDescription &desc, QAction *startAction) +{ + dd->registerAction(actionId, desc, startAction); +} + +void registerToolbar(const QByteArray &perspectiveId, const ToolbarDescription &desc) +{ + auto toolbar = new QWidget; + toolbar->setObjectName(QString::fromLatin1(perspectiveId + ".Toolbar")); + auto hbox = new QHBoxLayout(toolbar); + hbox->setMargin(0); + hbox->setSpacing(0); + for (QWidget *widget : desc.widgets()) + hbox->addWidget(widget); + hbox->addStretch(); + toolbar->setLayout(hbox); + + dd->m_mainWindow->registerToolbar(perspectiveId, toolbar); +} +QAction *createStartAction() +{ + auto action = new QAction(DebuggerMainWindow::tr("Start"), 0); + action->setIcon(Debugger::Icons::ANALYZER_CONTROL_START.icon()); + action->setEnabled(true); + return action; +} + +QAction *createStopAction() +{ + auto action = new QAction(DebuggerMainWindow::tr("Stop"), 0); + action->setIcon(ProjectExplorer::Icons::STOP_SMALL.icon()); + action->setEnabled(true); + return action; +} + +void registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective) +{ + dd->m_mainWindow->registerPerspective(perspectiveId, perspective); +} + +void selectPerspective(const QByteArray &perspectiveId) +{ + ModeManager::activateMode(MODE_DEBUG); + dd->selectPerspective(perspectiveId); +} + +void runAction(Id actionId) +{ + ActionDescription desc = dd->m_descriptions.value(actionId); + desc.startTool(); +} + +void enableMainWindow(bool on) +{ + dd->m_mainWindow->setEnabled(on); +} + +void showStatusMessage(const QString &message, int timeoutMS) +{ + dd->m_mainWindow->showStatusMessage(message, timeoutMS); +} + +void showPermanentStatusMessage(const QString &message) +{ + dd->m_mainWindow->showStatusMessage(message, -1); +} + +AnalyzerRunControl *createAnalyzerRunControl(RunConfiguration *runConfiguration, Id runMode) +{ + foreach (const ActionDescription &action, dd->m_descriptions) { + if (action.runMode() == runMode) + return action.runControlCreator()(runConfiguration, runMode); + } + return 0; +} + +bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2) +{ + return c1.connParams == c2.connParams + && c1.analyzerHost == c2.analyzerHost + && c1.analyzerSocket == c2.analyzerSocket + && c1.analyzerPort == c2.analyzerPort; +} #ifdef WITH_TESTS void DebuggerPluginPrivate::testLoadProject(const QString &proFile, const TestCallBack &cb) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 8edb6b40778f0d173593db375cead3e1fbbe5336..f676fbfe9bc970538919fe856d660429c448011c 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -25,6 +25,7 @@ #include "debuggerruncontrol.h" +#include "analyzer/analyzermanager.h" #include "debuggeractions.h" #include "debuggercore.h" #include "debuggerengine.h" @@ -140,6 +141,7 @@ QString DebuggerRunControl::displayName() const void DebuggerRunControl::start() { + Debugger::selectPerspective(Debugger::Constants::CppPerspectiveId); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); diff --git a/src/plugins/ios/iosanalyzesupport.cpp b/src/plugins/ios/iosanalyzesupport.cpp index dc40be7f79db3648d352b39d629a454ecd9e7833..c9e7020af3590831db9d4a957278af8f64fa94c5 100644 --- a/src/plugins/ios/iosanalyzesupport.cpp +++ b/src/plugins/ios/iosanalyzesupport.cpp @@ -56,7 +56,7 @@ #include <io.h> #endif -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Ios { diff --git a/src/plugins/ios/iosanalyzesupport.h b/src/plugins/ios/iosanalyzesupport.h index 76c4da284d8546050be4cb74db755eb89bd7fa69..2b18c5f6936e5ba8b58f75d39523cb70dd69269f 100644 --- a/src/plugins/ios/iosanalyzesupport.h +++ b/src/plugins/ios/iosanalyzesupport.h @@ -33,7 +33,7 @@ #include <QProcess> #include <QObject> -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace Ios { namespace Internal { @@ -47,7 +47,7 @@ class IosAnalyzeSupport : public QObject public: IosAnalyzeSupport(IosRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl, bool cppDebug, bool qmlDebug); + Debugger::AnalyzerRunControl *runControl, bool cppDebug, bool qmlDebug); ~IosAnalyzeSupport(); private: @@ -59,7 +59,7 @@ private: void handleRemoteOutput(const QString &output); void handleRemoteErrorOutput(const QString &output); - Analyzer::AnalyzerRunControl *m_runControl; + Debugger::AnalyzerRunControl *m_runControl; IosRunner * const m_runner; QmlDebug::QmlOutputParser m_outputParser; int m_qmlPort; diff --git a/src/plugins/ios/iosrunfactories.cpp b/src/plugins/ios/iosrunfactories.cpp index bd5a0dbf5637fd1dd751b80bfd3c75aedca2200a..a8262b4abdd143cee757acab026394903700865f 100644 --- a/src/plugins/ios/iosrunfactories.cpp +++ b/src/plugins/ios/iosrunfactories.cpp @@ -48,7 +48,7 @@ #include <qtsupport/qtsupportconstants.h> #include <coreplugin/id.h> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace QmakeProjectManager; @@ -190,7 +190,7 @@ RunControl *IosRunControlFactory::create(RunConfiguration *runConfig, if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) res = new Ios::Internal::IosRunControl(rc); else if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, mode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); QTC_ASSERT(runControl, return 0); IDevice::ConstPtr device = DeviceKitInformation::device(target->kit()); if (device.isNull()) diff --git a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp index 7492ce0ff1564be81cd9d5649db7b0a5e82b48b1..b79aa79e927484ed07c0b4587022b769de2ea67f 100644 --- a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp +++ b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp @@ -74,7 +74,7 @@ LocalQmlProfilerRunner::LocalQmlProfilerRunner(const Configuration &configuratio engine, &QmlProfilerRunControl::notifyRemoteFinished); connect(this, &LocalQmlProfilerRunner::appendMessage, engine, &QmlProfilerRunControl::logApplicationMessage); - connect(engine, &Analyzer::AnalyzerRunControl::starting, + connect(engine, &Debugger::AnalyzerRunControl::starting, this, &LocalQmlProfilerRunner::start); connect(engine, &RunControl::finished, this, &LocalQmlProfilerRunner::stop); diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp index 4cad320dbf9edcbed7b5461ddc7fb390458a2809..be64b14a26ee4d781b4bae4f4c84a441a9101539 100644 --- a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp @@ -34,8 +34,6 @@ #include <QtPlugin> -using namespace Analyzer; - namespace QmlProfiler { namespace Internal { diff --git a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp index 27260698fe2d5d58bff33055ba9cedfda9e36c80..1522acba0d0ba03a48c6c66ac890ed23c750a413 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp @@ -53,7 +53,7 @@ ProjectExplorer::IRunConfigurationAspect *QmlProfilerRunConfigurationAspect::cre ProjectExplorer::RunConfigWidget *QmlProfilerRunConfigurationAspect::createConfigurationWidget() { - return new Analyzer::AnalyzerRunConfigWidget(this); + return new Debugger::AnalyzerRunConfigWidget(this); } } // Internal diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 4626072e9673305b9beff60a7c4542b1947ec889..48ca56a213e624e1b88cea509cf100a3b7823049 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -51,7 +51,7 @@ #include <QMessageBox> #include <QPushButton> -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace ProjectExplorer; @@ -102,16 +102,16 @@ QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration, QmlProfilerRunControl::~QmlProfilerRunControl() { if (d->m_profilerState) - stopEngine(); + stop(); delete d; } -bool QmlProfilerRunControl::startEngine() +void QmlProfilerRunControl::start() { d->m_tool->finalizeRunControl(this); - QTC_ASSERT(d->m_profilerState, return false); + QTC_ASSERT(d->m_profilerState, finished(); return); - QTC_ASSERT(connection().is<AnalyzerConnection>(), return false); + QTC_ASSERT(connection().is<AnalyzerConnection>(), finished(); return); auto conn = connection().as<AnalyzerConnection>(); if (conn.analyzerPort != 0) @@ -120,13 +120,14 @@ bool QmlProfilerRunControl::startEngine() d->m_noDebugOutputTimer.start(); d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning); + d->m_running = true; emit starting(); - return true; } -void QmlProfilerRunControl::stopEngine() +RunControl::StopResult QmlProfilerRunControl::stop() { - QTC_ASSERT(d->m_profilerState, return); + d->m_running = false; + QTC_ASSERT(d->m_profilerState, return RunControl::StoppedSynchronously); switch (d->m_profilerState->currentState()) { case QmlProfilerStateManager::AppRunning: @@ -147,6 +148,13 @@ void QmlProfilerRunControl::stopEngine() } break; } + + return RunControl::StoppedSynchronously; +} + +bool QmlProfilerRunControl::isRunning() const +{ + return d->m_running; } void QmlProfilerRunControl::notifyRemoteFinished() @@ -156,7 +164,6 @@ void QmlProfilerRunControl::notifyRemoteFinished() switch (d->m_profilerState->currentState()) { case QmlProfilerStateManager::AppRunning: d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying); - AnalyzerManager::stopTool(); emit finished(); break; case QmlProfilerStateManager::Idle: @@ -215,7 +222,6 @@ void QmlProfilerRunControl::wrongSetupMessageBox(const QString &errorMessage) // KILL d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying); d->m_noDebugOutputTimer.stop(); - AnalyzerManager::stopTool(); emit finished(); } @@ -270,12 +276,4 @@ void QmlProfilerRunControl::profilerStateChanged() } } -RunControl::StopResult QmlProfilerRunControl::stop() -{ - StopResult result = Analyzer::AnalyzerRunControl::stop(); - if (d->m_profilerState->currentState() != QmlProfilerStateManager::Idle) - m_isRunning = true; - return result; -} - } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index a7d42d7c34bed92a60986e015a8479fd4481dad7..a44e6c710a1e78b21fea38220a9647cecf0f5753 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -35,7 +35,7 @@ namespace QmlProfiler { namespace Internal { class QmlProfilerTool; } -class QmlProfilerRunControl : public Analyzer::AnalyzerRunControl +class QmlProfilerRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -47,25 +47,22 @@ public: void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); void notifyRemoteSetupDone(quint16 port) override; + void start() override; StopResult stop() override; - -signals: - void processRunning(quint16 port); - -public slots: - bool startEngine() override; - void stopEngine() override; + bool isRunning() const override; void cancelProcess(); void notifyRemoteFinished() override; void logApplicationMessage(const QString &msg, Utils::OutputFormat format) override; -private slots: +signals: + void processRunning(quint16 port); + +private: void wrongSetupMessageBox(const QString &errorMessage); void wrongSetupMessageBoxFinished(int); void processIsRunning(quint16 port); void profilerStateChanged(); -private: class QmlProfilerRunControlPrivate; QmlProfilerRunControlPrivate *d; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp index b6252f64b1864c1576a07df1c778fa5251fa4bf7..5803d2395760ce085471d2325e3880bae0882a46 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp @@ -45,7 +45,7 @@ #include <utils/qtcassert.h> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace QmlProfiler { @@ -94,7 +94,7 @@ RunControl *QmlProfilerRunControlFactory::create(RunConfiguration *runConfigurat } auto runControl = qobject_cast<QmlProfilerRunControl *> - (AnalyzerManager::createRunControl(runConfiguration, mode)); + (Debugger::createAnalyzerRunControl(runConfiguration, mode)); QTC_ASSERT(runControl, return 0); runControl->setRunnable(runnable); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index ed862ce019088bfed738c7c9caa09412cf2b5651..6cc38a234823a9e5baa4bf547958ae2f0b9528b4 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -82,8 +82,8 @@ using namespace Core; using namespace Core::Constants; -using namespace Analyzer; -using namespace Analyzer::Constants; +using namespace Debugger; +using namespace Debugger::Constants; using namespace QmlProfiler::Constants; using namespace QmlDebug; using namespace ProjectExplorer; @@ -103,6 +103,8 @@ public: QToolButton *m_recordButton = 0; QMenu *m_recordFeaturesMenu = 0; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QToolButton *m_clearButton = 0; // elapsed time display @@ -120,6 +122,8 @@ public: // save and load actions QAction *m_saveQmlTrace = 0; QAction *m_loadQmlTrace = 0; + + bool m_toolBusy = false; }; QmlProfilerTool::QmlProfilerTool(QObject *parent) @@ -176,8 +180,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_recordingTimer.setInterval(100); connect(&d->m_recordingTimer, &QTimer::timeout, this, &QmlProfilerTool::updateTimeDisplay); - - d->m_viewContainer = new QmlProfilerViewManager(this, d->m_profilerModelManager, d->m_profilerState); @@ -187,14 +189,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) // // Toolbar // - QWidget *toolbarWidget = new QWidget; - toolbarWidget->setObjectName(QLatin1String("QmlProfilerToolBarWidget")); - - QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - - d->m_recordButton = new QToolButton(toolbarWidget); + d->m_recordButton = new QToolButton; d->m_recordButton->setCheckable(true); connect(d->m_recordButton,&QAbstractButton::clicked, @@ -207,9 +202,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) this, &QmlProfilerTool::toggleRequestedFeature); setRecording(d->m_profilerState->clientRecording()); - layout->addWidget(d->m_recordButton); - d->m_clearButton = new QToolButton(toolbarWidget); + d->m_clearButton = new QToolButton; d->m_clearButton->setIcon(Icons::CLEAN_PANE.icon()); d->m_clearButton->setToolTip(tr("Discard data")); @@ -218,12 +212,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) clearData(); }); - layout->addWidget(d->m_clearButton); - d->m_searchButton = new QToolButton; d->m_searchButton->setIcon(Icons::ZOOM.icon()); d->m_searchButton->setToolTip(tr("Search timeline event notes.")); - layout->addWidget(d->m_searchButton); connect(d->m_searchButton, &QToolButton::clicked, this, &QmlProfilerTool::showTimeLineSearch); @@ -236,7 +227,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_displayFeaturesButton->setMenu(d->m_displayFeaturesMenu); connect(d->m_displayFeaturesMenu, &QMenu::triggered, this, &QmlProfilerTool::toggleVisibleFeature); - layout->addWidget(d->m_displayFeaturesButton); d->m_timeLabel = new QLabel(); QPalette palette; @@ -244,11 +234,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_timeLabel->setPalette(palette); d->m_timeLabel->setIndent(10); updateTimeDisplay(); - layout->addWidget(d->m_timeLabel); - layout->addStretch(); - - toolbarWidget->setLayout(layout); setAvailableFeatures(d->m_profilerModelManager->availableFeatures()); setRecordedFeatures(0); @@ -263,6 +249,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) QString description = tr("The QML Profiler can be used to find performance " "bottlenecks in applications using QML."); + d->m_startAction = Debugger::createStartAction(); + d->m_stopAction = Debugger::createStopAction(); + ActionDescription desc; desc.setText(tr("QML Profiler")); desc.setToolTip(description); @@ -270,8 +259,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) desc.setRunControlCreator(runControlCreator); desc.setToolPreparer([this] { return prepareTool(); }); desc.setRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(Constants::QmlProfilerLocalActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(Constants::QmlProfilerLocalActionId, desc, d->m_startAction); desc.setText(tr("QML Profiler (External)")); desc.setToolTip(description); @@ -280,10 +269,21 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) desc.setCustomToolStarter([this](RunConfiguration *rc) { startRemoteTool(rc); }); desc.setToolPreparer([this] { return prepareTool(); }); desc.setRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction(Constants::QmlProfilerRemoteActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction(Constants::QmlProfilerRemoteActionId, desc); + + Utils::ToolbarDescription toolbar; + toolbar.addAction(d->m_startAction); + toolbar.addAction(d->m_stopAction); + toolbar.addWidget(d->m_recordButton); + toolbar.addWidget(d->m_clearButton); + toolbar.addWidget(d->m_searchButton); + toolbar.addWidget(d->m_displayFeaturesButton); + toolbar.addWidget(d->m_timeLabel); + Debugger::registerToolbar(Constants::QmlProfilerPerspectiveId, toolbar); - AnalyzerManager::registerToolbar(Constants::QmlProfilerPerspectiveId, toolbarWidget); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &QmlProfilerTool::updateRunActions); } QmlProfilerTool::~QmlProfilerTool() @@ -291,6 +291,25 @@ QmlProfilerTool::~QmlProfilerTool() delete d; } +void QmlProfilerTool::updateRunActions() +{ + if (d->m_toolBusy) { + d->m_startAction->setEnabled(false); + d->m_startAction->setToolTip(tr("A Qml Profiler analysis is still in progress.")); + d->m_stopAction->setEnabled(true); + } else { + const bool projectUsable = SessionManager::startupProject() != 0; + d->m_startAction->setToolTip(tr("Start Qml Profiler.")); + if (projectUsable) { + d->m_startAction->setEnabled(true); + d->m_stopAction->setEnabled(false); + } else { + d->m_startAction->setEnabled(false); + d->m_stopAction->setEnabled(false); + } + } +} + static QString sysroot(RunConfiguration *runConfig) { QTC_ASSERT(runConfig, return QString()); @@ -302,6 +321,7 @@ static QString sysroot(RunConfiguration *runConfig) AnalyzerRunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfiguration) { + d->m_toolBusy = true; if (runConfiguration) { QmlProfilerRunConfigurationAspect *aspect = static_cast<QmlProfilerRunConfigurationAspect *>( runConfiguration->extraAspect(Constants::SETTINGS)); @@ -314,7 +334,16 @@ AnalyzerRunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfi } } - return new QmlProfilerRunControl(runConfiguration, this); + auto runControl = new QmlProfilerRunControl(runConfiguration, this); + connect(runControl, &RunControl::finished, [this, runControl] { + d->m_toolBusy = false; + updateRunActions(); + }); + + connect(d->m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + updateRunActions(); + return runControl; } void QmlProfilerTool::finalizeRunControl(QmlProfilerRunControl *runControl) @@ -503,8 +532,6 @@ bool QmlProfilerTool::prepareTool() void QmlProfilerTool::startRemoteTool(ProjectExplorer::RunConfiguration *rc) { - AnalyzerManager::showMode(); - Id kitId; quint16 port; Kit *kit = 0; @@ -596,7 +623,7 @@ void QmlProfilerTool::showSaveDialog() if (!filename.endsWith(QLatin1String(TraceFileExtension))) filename += QLatin1String(TraceFileExtension); saveLastTraceFile(filename); - AnalyzerManager::enableMainWindow(false); + Debugger::enableMainWindow(false); d->m_profilerModelManager->save(filename); } } @@ -606,10 +633,7 @@ void QmlProfilerTool::showLoadDialog() if (!checkForUnsavedNotes()) return; - if (ModeManager::currentMode()->id() != MODE_ANALYZE) - AnalyzerManager::showMode(); - - AnalyzerManager::selectAction(QmlProfilerRemoteActionId); + Debugger::selectPerspective(QmlProfilerPerspectiveId); QString filename = QFileDialog::getOpenFileName( ICore::mainWindow(), tr("Load QML Trace"), @@ -618,7 +642,7 @@ void QmlProfilerTool::showLoadDialog() if (!filename.isEmpty()) { saveLastTraceFile(filename); - AnalyzerManager::enableMainWindow(false); + Debugger::enableMainWindow(false); connect(d->m_profilerModelManager, &QmlProfilerModelManager::recordedFeaturesChanged, this, &QmlProfilerTool::setRecordedFeatures); d->m_profilerModelManager->load(filename); @@ -629,7 +653,7 @@ void QmlProfilerTool::onLoadSaveFinished() { disconnect(d->m_profilerModelManager, &QmlProfilerModelManager::recordedFeaturesChanged, this, &QmlProfilerTool::setRecordedFeatures); - AnalyzerManager::enableMainWindow(true); + Debugger::enableMainWindow(true); } /*! diff --git a/src/plugins/qmlprofiler/qmlprofilertool.h b/src/plugins/qmlprofiler/qmlprofilertool.h index 23f740e2d31f40464f2918c9296f920ab28c5344..34c7e21505147a4316a30661412243c1d8c116de 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.h +++ b/src/plugins/qmlprofiler/qmlprofilertool.h @@ -51,7 +51,7 @@ public: explicit QmlProfilerTool(QObject *parent); ~QmlProfilerTool(); - Analyzer::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); + Debugger::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); void finalizeRunControl(QmlProfilerRunControl *runControl); bool prepareTool(); @@ -96,6 +96,7 @@ private slots: void toggleVisibleFeature(QAction *action); private: + void updateRunActions(); void clearDisplay(); void populateFileFinder(QString projectDirectory = QString(), QString activeSysroot = QString()); template<QmlDebug::ProfileFeature feature> diff --git a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp index 9655734d9d23edb1b88a7f968526833be9375a1a..1c4a67e5b93574b15a7a66001ac2456eef13548d 100644 --- a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp @@ -40,7 +40,8 @@ #include <QDockWidget> -using namespace Analyzer; +using namespace Debugger; +using namespace Utils; namespace QmlProfiler { namespace Internal { @@ -80,7 +81,7 @@ void QmlProfilerViewManager::createViews() QTC_ASSERT(d->profilerModelManager, return); QTC_ASSERT(d->profilerState, return); - //Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow(); + //Utils::FancyMainWindow *mw = Debugger::mainWindow(); d->traceView = new QmlProfilerTraceView(0, this, d->profilerModelManager); d->traceView->setWindowTitle(tr("Timeline")); @@ -90,12 +91,12 @@ void QmlProfilerViewManager::createViews() this, &QmlProfilerViewManager::typeSelected); connect(this, &QmlProfilerViewManager::typeSelected, d->traceView, &QmlProfilerTraceView::selectByTypeId); - AnalyzerManager::registerDockWidget(Constants::QmlProfilerTimelineDockId, d->traceView); new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->traceView); - Perspective perspective; - perspective.addOperation({Constants::QmlProfilerTimelineDockId, Core::Id(), + Utils::Perspective perspective; + perspective.setName(tr("QML Profiler")); + perspective.addOperation({Constants::QmlProfilerTimelineDockId, d->traceView, {}, Perspective::SplitVertical}); d->eventsViews << new QmlProfilerStatisticsView(0, d->profilerModelManager); @@ -118,19 +119,17 @@ void QmlProfilerViewManager::createViews() this, &QmlProfilerViewManager::gotoSourceLocation); connect(view, &QmlProfilerEventsView::showFullRange, this, [this](){restrictEventsToRange(-1, -1);}); - Core::Id dockId = Core::Id::fromString(view->objectName()); - AnalyzerManager::registerDockWidget(dockId, view); - perspective.addOperation({dockId, Constants::QmlProfilerTimelineDockId, Perspective::AddToTab}); + QByteArray dockId = view->objectName().toLatin1(); + perspective.addOperation({dockId, view, Constants::QmlProfilerTimelineDockId, Perspective::AddToTab}); new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, view); - if (!settings->contains(view->parent()->objectName())) // parent() is QDockWidget. - settings->remove(QString()); +// if (!settings->contains(view->parent()->objectName())) // parent() is QDockWidget. +// settings->remove(QString()); } - AnalyzerManager::registerPerspective(Constants::QmlProfilerPerspectiveId, perspective); + perspective.addOperation({Constants::QmlProfilerTimelineDockId, 0, {}, Perspective::Raise}); + Debugger::registerPerspective(Constants::QmlProfilerPerspectiveId, perspective); settings->endGroup(); - QTC_ASSERT(qobject_cast<QDockWidget *>(d->traceView->parentWidget()), return); - d->traceView->parentWidget()->raise(); } bool QmlProfilerViewManager::hasValidSelection() const diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index e25dcd58550d57d44a06d60db78ab3359a0cc1e7..289d7d1756ac2ea8e33b1ca0961533924d0250e4 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -45,7 +45,7 @@ namespace Qnx { namespace Internal { QnxAnalyzeSupport::QnxAnalyzeSupport(QnxRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl) + Debugger::AnalyzerRunControl *runControl) : QnxAbstractRunSupport(runConfig, runControl) , m_runnable(runConfig->runnable().as<StandardRunnable>()) , m_runControl(runControl) @@ -65,7 +65,7 @@ QnxAnalyzeSupport::QnxAnalyzeSupport(QnxRunConfiguration *runConfig, connect(runner, &DeviceApplicationRunner::remoteStderr, this, &QnxAnalyzeSupport::handleRemoteOutput); - connect(m_runControl, &Analyzer::AnalyzerRunControl::starting, + connect(m_runControl, &Debugger::AnalyzerRunControl::starting, this, &QnxAnalyzeSupport::handleAdapterSetupRequested); connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, this, &QnxAnalyzeSupport::remoteIsRunning); diff --git a/src/plugins/qnx/qnxanalyzesupport.h b/src/plugins/qnx/qnxanalyzesupport.h index 6dbb23c09964abf199a283f4e06494fca01f908b..d1361fff3a82646bdb1b3e9f9413cf618f307a7b 100644 --- a/src/plugins/qnx/qnxanalyzesupport.h +++ b/src/plugins/qnx/qnxanalyzesupport.h @@ -32,7 +32,7 @@ #include <utils/outputformat.h> #include <qmldebug/qmloutputparser.h> -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace Qnx { namespace Internal { @@ -44,7 +44,7 @@ class QnxAnalyzeSupport : public QnxAbstractRunSupport { Q_OBJECT public: - QnxAnalyzeSupport(QnxRunConfiguration *runConfig, Analyzer::AnalyzerRunControl *engine); + QnxAnalyzeSupport(QnxRunConfiguration *runConfig, Debugger::AnalyzerRunControl *engine); public slots: void handleProfilingFinished(); @@ -66,7 +66,7 @@ private: void startExecution(); ProjectExplorer::StandardRunnable m_runnable; - Analyzer::AnalyzerRunControl *m_runControl; + Debugger::AnalyzerRunControl *m_runControl; QmlDebug::QmlOutputParser m_outputParser; int m_qmlPort; diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index cf38795e862a4b0bc95c65f2eda21e4cc81ddeb1..0b95af65b1ebfd202ff75b988c11c63538d2b80b 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -48,7 +48,6 @@ #include <qtsupport/qtkitinformation.h> #include <utils/portlist.h> -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; using namespace Qnx; @@ -142,7 +141,7 @@ RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, Core::Id m const IDevice::ConstPtr device = DeviceKitInformation::device(kit); if (device.isNull()) return 0; - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, mode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); QTC_ASSERT(runControl, return 0); runControl->setRunnable(runConfig->runnable()); AnalyzerConnection connection; diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp index 0e88bea8736944bb9fe275d3b302a142d4cb3b6e..e63baf8949cedb89afd3240fdedc9bdeab10815a 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp @@ -45,7 +45,7 @@ #include <QPointer> using namespace QSsh; -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.h b/src/plugins/remotelinux/remotelinuxanalyzesupport.h index 9f69296a16d46f95bfa0f88d5ac7dd755d621d57..de083d38bce35709f0307ae46b551d32fcf120e0 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.h +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.h @@ -33,7 +33,7 @@ #include <utils/outputformat.h> -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace RemoteLinux { @@ -44,7 +44,7 @@ class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public AbstractRemoteLinuxR Q_OBJECT public: RemoteLinuxAnalyzeSupport(ProjectExplorer::RunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *engine, Core::Id runMode); + Debugger::AnalyzerRunControl *engine, Core::Id runMode); ~RemoteLinuxAnalyzeSupport(); protected: diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 42158d461784f4fddeb7dcf4400edff854b118c7..3439c977b4b1714f98c79ae817129138726899a7 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -48,7 +48,6 @@ #include <utils/portlist.h> #include <utils/qtcassert.h> -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; @@ -139,7 +138,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Co } if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - auto runControl = AnalyzerManager::createRunControl(runConfig, mode); + auto runControl = Debugger::createAnalyzerRunControl(runConfig, mode); AnalyzerConnection connection; connection.connParams = DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index b3a9a183c0b792b900c4390f995e2172fb1a4702..cc7e41ac0dbf99c00ef003dbb8913458942d2e3b 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -35,7 +35,7 @@ #include <utils/qtcassert.h> -using namespace Analyzer; +using namespace Debugger; using namespace Valgrind; using namespace Valgrind::Internal; @@ -48,7 +48,7 @@ CallgrindRunControl::CallgrindRunControl(ProjectExplorer::RunConfiguration *runC connect(m_runner.parser(), &Callgrind::Parser::parserDataReady, this, &CallgrindRunControl::slotFinished); connect(&m_runner, &Callgrind::CallgrindRunner::statusMessage, - this, &AnalyzerManager::showPermanentStatusMessage); + this, &Debugger::showPermanentStatusMessage); } QStringList CallgrindRunControl::toolArguments() const @@ -89,10 +89,10 @@ ValgrindRunner * CallgrindRunControl::runner() return &m_runner; } -bool CallgrindRunControl::startEngine() +void CallgrindRunControl::start() { appendMessage(tr("Profiling %1").arg(executable()) + QLatin1Char('\n'), Utils::NormalMessageFormat); - return ValgrindRunControl::startEngine(); + return ValgrindRunControl::start(); } void CallgrindRunControl::dump() diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 87da36fd146ba0d635b05d828e4b84fba0e142e5..19e91a95b41db3a1a13c62279a5ceda7759d3104 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -41,7 +41,7 @@ class CallgrindRunControl : public ValgrindRunControl public: CallgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration); - bool startEngine() override; + void start() override; Valgrind::Callgrind::ParseData *takeParserData(); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 9a625113113a22438f8ae471163e83ca3858e8a0..ec67a51b8bec6c18873541ca0e681921799c7827 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -43,6 +43,7 @@ #include <valgrind/valgrindplugin.h> #include <valgrind/valgrindsettings.h> +#include <debugger/debuggerconstants.h> #include <debugger/analyzer/analyzerconstants.h> #include <debugger/analyzer/analyzericons.h> #include <debugger/analyzer/analyzermanager.h> @@ -90,11 +91,12 @@ #include <QToolBar> #include <QToolButton> -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace Valgrind::Callgrind; using namespace TextEditor; using namespace ProjectExplorer; +using namespace Utils; namespace Valgrind { namespace Internal { @@ -108,7 +110,6 @@ public: ~CallgrindTool(); ValgrindRunControl *createRunControl(RunConfiguration *runConfiguration); - void createWidgets(); void setParseData(ParseData *data); CostDelegate::CostFormat costFormat() const; @@ -164,6 +165,7 @@ public: void editorOpened(IEditor *); void requestContextMenu(TextEditorWidget *widget, int line, QMenu *menu); + void updateRunActions(); public: DataModel m_dataModel; @@ -200,15 +202,17 @@ public: QVector<CallgrindTextMark *> m_textMarks; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QAction *m_loadExternalLogFile; QAction *m_dumpAction = 0; QAction *m_resetAction = 0; QAction *m_pauseAction = 0; QString m_toggleCollectFunction; + bool m_toolBusy = false; }; - CallgrindTool::CallgrindTool(QObject *parent) : QObject(parent) { @@ -231,6 +235,9 @@ CallgrindTool::CallgrindTool(QObject *parent) connect(EditorManager::instance(), &EditorManager::editorOpened, this, &CallgrindTool::editorOpened); + m_startAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); + ActionDescription desc; desc.setToolTip(tr("Valgrind Function Profile uses the " "Callgrind tool to record function calls when a program runs.")); @@ -243,13 +250,13 @@ CallgrindTool::CallgrindTool(QObject *parent) }); desc.setToolMode(OptimizedMode); desc.setRunMode(CALLGRIND_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(CallgrindLocalActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(CallgrindLocalActionId, desc, m_startAction); } desc.setText(tr("Valgrind Function Profiler (External Application)")); desc.setPerspectiveId(CallgrindPerspectiveId); - desc.setCustomToolStarter([this](ProjectExplorer::RunConfiguration *runConfig) { + desc.setCustomToolStarter([this](RunConfiguration *runConfig) { StartRemoteDialog dlg; if (dlg.exec() != QDialog::Accepted) return; @@ -263,17 +270,17 @@ CallgrindTool::CallgrindTool(QObject *parent) rc->setDisplayName(runnable.executable); ProjectExplorerPlugin::startRunControl(rc, CALLGRIND_RUN_MODE); }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction(CallgrindRemoteActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction(CallgrindRemoteActionId, desc); // If there is a CppEditor context menu add our own context menu actions. if (ActionContainer *editorContextMenu = ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { - Context analyzerContext = Context(Analyzer::Constants::C_ANALYZEMODE); + Context analyzerContext = Context(Debugger::Constants::C_DEBUGMODE); editorContextMenu->addSeparator(analyzerContext); auto action = new QAction(tr("Profile Costs of This Function and Its Callees"), this); - action->setIcon(Analyzer::Icons::ANALYZER_CONTROL_START.icon()); + action->setIcon(Debugger::Icons::ANALYZER_CONTROL_START.icon()); connect(action, &QAction::triggered, this, &CallgrindTool::handleShowCostsOfFunction); Command *cmd = ActionManager::registerAction(action, "Analyzer.Callgrind.ShowCostsOfFunction", @@ -283,7 +290,214 @@ CallgrindTool::CallgrindTool(QObject *parent) cmd->setAttribute(Command::CA_NonConfigurable); } - createWidgets(); + QSettings *coreSettings = ICore::settings(); + + // + // DockWidgets + // + m_visualization = new Visualisation; + m_visualization->setFrameStyle(QFrame::NoFrame); + m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation")); + m_visualization->setWindowTitle(tr("Visualization")); + m_visualization->setModel(&m_dataModel); + connect(m_visualization, &Visualisation::functionActivated, + this, &CallgrindTool::visualisationFunctionSelected); + + m_callersView = new CostView; + m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView")); + m_callersView->setWindowTitle(tr("Callers")); + m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView"); + m_callersView->sortByColumn(CallModel::CostColumn); + m_callersView->setFrameStyle(QFrame::NoFrame); + // enable sorting + m_callersProxy.setSourceModel(&m_callersModel); + m_callersView->setModel(&m_callersProxy); + m_callersView->hideColumn(CallModel::CalleeColumn); + connect(m_callersView, &QAbstractItemView::activated, + this, &CallgrindTool::callerFunctionSelected); + + m_calleesView = new CostView; + m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView")); + m_calleesView->setWindowTitle(tr("Callees")); + m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView"); + m_calleesView->sortByColumn(CallModel::CostColumn); + m_calleesView->setFrameStyle(QFrame::NoFrame); + // enable sorting + m_calleesProxy.setSourceModel(&m_calleesModel); + m_calleesView->setModel(&m_calleesProxy); + m_calleesView->hideColumn(CallModel::CallerColumn); + connect(m_calleesView, &QAbstractItemView::activated, + this, &CallgrindTool::calleeFunctionSelected); + + m_flatView = new CostView; + m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView")); + m_flatView->setWindowTitle(tr("Functions")); + m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView"); + m_flatView->sortByColumn(DataModel::SelfCostColumn); + m_flatView->setFrameStyle(QFrame::NoFrame); + m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false); + m_flatView->setModel(&m_proxyModel); + connect(m_flatView, &QAbstractItemView::activated, + this, &CallgrindTool::dataFunctionSelected); + + updateCostFormat(); + + // + // Control Widget + // + + // load external log file + auto action = m_loadExternalLogFile = new QAction(this); + action->setIcon(Core::Icons::OPENFILE.icon()); + action->setToolTip(tr("Load External Log File")); + connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile); + + // dump action + m_dumpAction = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::REDO.icon()); + //action->setText(tr("Dump")); + action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization.")); + connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump); + + // reset action + m_resetAction = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::RELOAD.icon()); + //action->setText(tr("Reset")); + action->setToolTip(tr("Reset all event counters.")); + connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested); + + // pause action + m_pauseAction = action = new QAction(this); + action->setCheckable(true); + action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon()); + //action->setText(tr("Ignore")); + action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling.")); + connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled); + + // navigation + // go back + m_goBack = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::PREV.icon()); + action->setToolTip(tr("Go back one step in history. This will select the previously selected item.")); + connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack); + + // go forward + m_goNext = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::NEXT.icon()); + action->setToolTip(tr("Go forward one step in history.")); + connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext); + + // event selection + m_eventCombo = new QComboBox; + m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized.")); + connect(m_eventCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + this, &CallgrindTool::setCostEvent); + updateEventCombo(); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_loadExternalLogFile); + toolbar.addAction(m_dumpAction); + toolbar.addAction(m_resetAction); + toolbar.addAction(m_pauseAction); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + toolbar.addWidget(new Utils::StyledSeparator); + toolbar.addWidget(m_eventCombo); + + // Cost formatting + { + auto menu = new QMenu; + auto group = new QActionGroup(this); + + // Show costs as absolute numbers + m_costAbsolute = new QAction(tr("Absolute Costs"), this); + m_costAbsolute->setToolTip(tr("Show costs as absolute numbers.")); + m_costAbsolute->setCheckable(true); + m_costAbsolute->setChecked(true); + connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costAbsolute); + menu->addAction(m_costAbsolute); + + // Show costs in percentages + m_costRelative = new QAction(tr("Relative Costs"), this); + m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost.")); + m_costRelative->setCheckable(true); + connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costRelative); + menu->addAction(m_costRelative); + + // Show costs relative to parent + m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this); + m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost.")); + m_costRelativeToParent->setCheckable(true); + connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costRelativeToParent); + menu->addAction(m_costRelativeToParent); + + auto button = new QToolButton; + button->setMenu(menu); + button->setPopupMode(QToolButton::InstantPopup); + button->setText(QLatin1String("$")); + button->setToolTip(tr("Cost Format")); + toolbar.addWidget(button); + } + + ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); + + // Cycle detection + //action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon + action = m_cycleDetection = new QAction(QLatin1String("O"), this); ///FIXME: icon + action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls.")); + action->setCheckable(true); + connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection); + connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles); + + // Shorter template signature + action = m_shortenTemplates = new QAction(QLatin1String("<>"), this); + action->setToolTip(tr("This removes template parameter lists when displaying function names.")); + action->setCheckable(true); + connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates); + connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates); + + // Filtering + action = m_filterProjectCosts = new QAction(tr("Show Project Costs Only"), this); + action->setIcon(Core::Icons::FILTER.icon()); + action->setToolTip(tr("Show only profiling info that originated from this project source.")); + action->setCheckable(true); + connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts); + + // Filter + ///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247 + m_searchFilter = new QLineEdit; + m_searchFilter->setPlaceholderText(tr("Filter...")); + connect(m_searchFilter, &QLineEdit::textChanged, + &m_updateTimer, static_cast<void(QTimer::*)()>(&QTimer::start)); + + setCostFormat(settings->costFormat()); + enableCycleDetection(settings->detectCycles()); + + toolbar.addAction(m_cycleDetection); + toolbar.addAction(m_shortenTemplates); + toolbar.addAction(m_filterProjectCosts); + toolbar.addWidget(m_searchFilter); + Debugger::registerToolbar(CallgrindPerspectiveId, toolbar); + + Debugger::registerPerspective(CallgrindPerspectiveId, { tr("Callgrind"), { + { CallgrindFlatDockId, m_flatView, {}, Perspective::SplitVertical }, + { CallgrindCalleesDockId, m_calleesView, {}, Perspective::SplitVertical }, + { CallgrindCallersDockId, m_callersView, CallgrindCalleesDockId, Perspective::SplitHorizontal }, + { CallgrindVisualizationDockId, m_visualization, {}, Perspective::SplitVertical, + false, Qt::RightDockWidgetArea } + }}); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &CallgrindTool::updateRunActions); } CallgrindTool::~CallgrindTool() @@ -521,34 +735,28 @@ void CallgrindTool::updateEventCombo() m_eventCombo->addItem(ParseData::prettyStringForEvent(event)); } -static QToolButton *createToolButton(QAction *action) -{ - QToolButton *button = new QToolButton; - button->setDefaultAction(action); - //button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - return button; -} - ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfiguration) { - auto rc = new CallgrindRunControl(runConfiguration); + auto runControl = new CallgrindRunControl(runConfiguration); + + connect(runControl, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl); + connect(runControl, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting); + connect(runControl, &RunControl::finished, this, &CallgrindTool::engineFinished); - connect(rc, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl); - connect(rc, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting); - connect(rc, &RunControl::finished, this, &CallgrindTool::engineFinished); + connect(this, &CallgrindTool::dumpRequested, runControl, &CallgrindRunControl::dump); + connect(this, &CallgrindTool::resetRequested, runControl, &CallgrindRunControl::reset); + connect(this, &CallgrindTool::pauseToggled, runControl, &CallgrindRunControl::setPaused); - connect(this, &CallgrindTool::dumpRequested, rc, &CallgrindRunControl::dump); - connect(this, &CallgrindTool::resetRequested, rc, &CallgrindRunControl::reset); - connect(this, &CallgrindTool::pauseToggled, rc, &CallgrindRunControl::setPaused); + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); // initialize run control - rc->setPaused(m_pauseAction->isChecked()); + runControl->setPaused(m_pauseAction->isChecked()); // we may want to toggle collect for one function only in this run - rc->setToggleCollectFunction(m_toggleCollectFunction); + runControl->setToggleCollectFunction(m_toggleCollectFunction); m_toggleCollectFunction.clear(); - QTC_ASSERT(m_visualization, return rc); + QTC_ASSERT(m_visualization, return runControl); // apply project settings if (runConfiguration) { @@ -560,241 +768,32 @@ ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfigu } } } - return rc; -} - -void CallgrindTool::createWidgets() -{ - QTC_ASSERT(!m_visualization, return); - QSettings *coreSettings = ICore::settings(); - - // - // DockWidgets - // - m_visualization = new Visualisation; - m_visualization->setFrameStyle(QFrame::NoFrame); - m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation")); - m_visualization->setWindowTitle(tr("Visualization")); - m_visualization->setModel(&m_dataModel); - connect(m_visualization, &Visualisation::functionActivated, - this, &CallgrindTool::visualisationFunctionSelected); - - m_callersView = new CostView; - m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView")); - m_callersView->setWindowTitle(tr("Callers")); - m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView"); - m_callersView->sortByColumn(CallModel::CostColumn); - m_callersView->setFrameStyle(QFrame::NoFrame); - // enable sorting - m_callersProxy.setSourceModel(&m_callersModel); - m_callersView->setModel(&m_callersProxy); - m_callersView->hideColumn(CallModel::CalleeColumn); - connect(m_callersView, &QAbstractItemView::activated, - this, &CallgrindTool::callerFunctionSelected); - - m_calleesView = new CostView; - m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView")); - m_calleesView->setWindowTitle(tr("Callees")); - m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView"); - m_calleesView->sortByColumn(CallModel::CostColumn); - m_calleesView->setFrameStyle(QFrame::NoFrame); - // enable sorting - m_calleesProxy.setSourceModel(&m_calleesModel); - m_calleesView->setModel(&m_calleesProxy); - m_calleesView->hideColumn(CallModel::CallerColumn); - connect(m_calleesView, &QAbstractItemView::activated, - this, &CallgrindTool::calleeFunctionSelected); - - m_flatView = new CostView; - m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView")); - m_flatView->setWindowTitle(tr("Functions")); - m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView"); - m_flatView->sortByColumn(DataModel::SelfCostColumn); - m_flatView->setFrameStyle(QFrame::NoFrame); - m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false); - m_flatView->setModel(&m_proxyModel); - connect(m_flatView, &QAbstractItemView::activated, - this, &CallgrindTool::dataFunctionSelected); - - updateCostFormat(); - - // - // Control Widget - // - auto layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - - auto widget = new QWidget; - widget->setLayout(layout); - - // load external log file - auto action = new QAction(this); - action->setIcon(Core::Icons::OPENFILE.icon()); - action->setToolTip(tr("Load External Log File")); - connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile); - layout->addWidget(createToolButton(action)); - m_loadExternalLogFile = action; - - // dump action - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::REDO.icon()); - //action->setText(tr("Dump")); - action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization.")); - connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump); - layout->addWidget(createToolButton(action)); - m_dumpAction = action; - - // reset action - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::RELOAD.icon()); - //action->setText(tr("Reset")); - action->setToolTip(tr("Reset all event counters.")); - connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested); - layout->addWidget(createToolButton(action)); - m_resetAction = action; - - // pause action - action = new QAction(this); - action->setCheckable(true); - action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon()); - //action->setText(tr("Ignore")); - action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling.")); - connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled); - layout->addWidget(createToolButton(action)); - m_pauseAction = action; - - // navigation - // go back - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::PREV.icon()); - action->setToolTip(tr("Go back one step in history. This will select the previously selected item.")); - connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack); - layout->addWidget(createToolButton(action)); - m_goBack = action; + m_toolBusy = true; + updateRunActions(); - // go forward - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::NEXT.icon()); - action->setToolTip(tr("Go forward one step in history.")); - connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext); - layout->addWidget(createToolButton(action)); - m_goNext = action; - - layout->addWidget(new Utils::StyledSeparator); - - // event selection - m_eventCombo = new QComboBox; - m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized.")); - connect(m_eventCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - this, &CallgrindTool::setCostEvent); - updateEventCombo(); - layout->addWidget(m_eventCombo); - - // Cost formatting - { - auto menu = new QMenu(layout->parentWidget()); - auto group = new QActionGroup(this); - - // Show costs as absolute numbers - m_costAbsolute = new QAction(tr("Absolute Costs"), this); - m_costAbsolute->setToolTip(tr("Show costs as absolute numbers.")); - m_costAbsolute->setCheckable(true); - m_costAbsolute->setChecked(true); - connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costAbsolute); - menu->addAction(m_costAbsolute); - - // Show costs in percentages - m_costRelative = new QAction(tr("Relative Costs"), this); - m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost.")); - m_costRelative->setCheckable(true); - connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costRelative); - menu->addAction(m_costRelative); - - // Show costs relative to parent - m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this); - m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost.")); - m_costRelativeToParent->setCheckable(true); - connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costRelativeToParent); - menu->addAction(m_costRelativeToParent); + return runControl; +} - auto button = new QToolButton; - button->setMenu(menu); - button->setPopupMode(QToolButton::InstantPopup); - button->setText(QLatin1String("$")); - button->setToolTip(tr("Cost Format")); - layout->addWidget(button); +void CallgrindTool::updateRunActions() +{ + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("A Valgrind Callgrind analysis is still in progress.")); + m_stopAction->setEnabled(true); + } else { + const bool projectUsable = SessionManager::startupProject() != 0; + if (projectUsable) { + m_startAction->setEnabled(true); + m_startAction->setToolTip(tr("Start a Valgrind Callgrind analysis.")); + m_stopAction->setEnabled(false); + } else { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("Start a Valgrind Callgrind analysis.")); + m_stopAction->setEnabled(false); + } } - - ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); - - // Cycle detection - //action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon - action = new QAction(QLatin1String("O"), this); ///FIXME: icon - action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls.")); - action->setCheckable(true); - connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection); - connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles); - layout->addWidget(createToolButton(action)); - m_cycleDetection = action; - - // Shorter template signature - action = new QAction(QLatin1String("<>"), this); - action->setToolTip(tr("This removes template parameter lists when displaying function names.")); - action->setCheckable(true); - connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates); - connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates); - layout->addWidget(createToolButton(action)); - m_shortenTemplates = action; - - // Filtering - action = new QAction(tr("Show Project Costs Only"), this); - action->setIcon(Core::Icons::FILTER.icon()); - action->setToolTip(tr("Show only profiling info that originated from this project source.")); - action->setCheckable(true); - connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts); - layout->addWidget(createToolButton(action)); - m_filterProjectCosts = action; - - // Filter - ///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247 - auto filter = new QLineEdit; - filter->setPlaceholderText(tr("Filter...")); - connect(filter, &QLineEdit::textChanged, - &m_updateTimer, static_cast<void(QTimer::*)()>(&QTimer::start)); - layout->addWidget(filter); - m_searchFilter = filter; - - setCostFormat(settings->costFormat()); - enableCycleDetection(settings->detectCycles()); - - layout->addWidget(new Utils::StyledSeparator); - layout->addStretch(); - - AnalyzerManager::registerDockWidget(CallgrindCallersDockId, m_callersView); - AnalyzerManager::registerDockWidget(CallgrindFlatDockId, m_flatView); - AnalyzerManager::registerDockWidget(CallgrindCalleesDockId, m_calleesView); - AnalyzerManager::registerDockWidget(CallgrindVisualizationDockId, m_visualization); - - AnalyzerManager::registerPerspective(CallgrindPerspectiveId, { - { CallgrindFlatDockId, Id(), Perspective::SplitVertical }, - { CallgrindCalleesDockId, Id(), Perspective::SplitVertical }, - { CallgrindCallersDockId, CallgrindCalleesDockId, Perspective::SplitHorizontal }, - { CallgrindVisualizationDockId, Id(), Perspective::SplitVertical, - false, Qt::RightDockWidgetArea } - }); - - AnalyzerManager::registerToolbar(CallgrindPerspectiveId, widget); } - void CallgrindTool::clearTextMarks() { qDeleteAll(m_textMarks); @@ -813,6 +812,9 @@ void CallgrindTool::engineStarting() void CallgrindTool::engineFinished() { + m_toolBusy = false; + updateRunActions(); + // Enable/disable actions m_resetAction->setEnabled(false); m_dumpAction->setEnabled(false); @@ -822,7 +824,7 @@ void CallgrindTool::engineFinished() if (data) showParserResults(data); else - AnalyzerManager::showPermanentStatusMessage(tr("Profiling aborted.")); + Debugger::showPermanentStatusMessage(tr("Profiling aborted.")); setBusyCursor(false); } @@ -841,7 +843,7 @@ void CallgrindTool::showParserResults(const ParseData *data) } else { msg = tr("Parsing failed."); } - AnalyzerManager::showPermanentStatusMessage(msg); + Debugger::showPermanentStatusMessage(msg); } void CallgrindTool::editorOpened(IEditor *editor) @@ -878,8 +880,7 @@ void CallgrindTool::handleShowCostsOfFunction() const QString qualifiedFunctionName = view.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol)); m_toggleCollectFunction = qualifiedFunctionName + QLatin1String("()"); - - AnalyzerManager::selectAction(CallgrindLocalActionId, /* alsoRunIt = */ true); + m_startAction->trigger(); } void CallgrindTool::slotRequestDump() @@ -906,7 +907,7 @@ void CallgrindTool::loadExternalLogFile() return; } - AnalyzerManager::showPermanentStatusMessage(tr("Parsing Profile Data...")); + Debugger::showPermanentStatusMessage(tr("Parsing Profile Data...")); QCoreApplication::processEvents(); Parser parser; diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp index a40ffe9db2a8eb6834c68180e9461ff69fa7de2a..6d4a212c89174add378886afac1d5919b270a11a 100644 --- a/src/plugins/valgrind/memcheckengine.cpp +++ b/src/plugins/valgrind/memcheckengine.cpp @@ -44,7 +44,7 @@ #include <utils/qtcassert.h> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Valgrind::XmlProtocol; @@ -72,20 +72,20 @@ ValgrindRunner *MemcheckRunControl::runner() return &m_runner; } -bool MemcheckRunControl::startEngine() +void MemcheckRunControl::start() { m_runner.setParser(&m_parser); appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'), Utils::NormalMessageFormat); - return ValgrindRunControl::startEngine(); + ValgrindRunControl::start(); } -void MemcheckRunControl::stopEngine() +RunControl::StopResult MemcheckRunControl::stop() { disconnect(&m_parser, &ThreadedParser::internalError, this, &MemcheckRunControl::internalParserError); - ValgrindRunControl::stopEngine(); + return ValgrindRunControl::stop(); } QStringList MemcheckRunControl::toolArguments() const diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/valgrind/memcheckengine.h index a1ac1f8373dedd8227033bc5e733e494515da826..b619aa96694efea6a3d2ef1207fb4247d53c6ecd 100644 --- a/src/plugins/valgrind/memcheckengine.h +++ b/src/plugins/valgrind/memcheckengine.h @@ -43,8 +43,8 @@ public: MemcheckRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; QStringList suppressionFiles() const; diff --git a/src/plugins/valgrind/memcheckerrorview.cpp b/src/plugins/valgrind/memcheckerrorview.cpp index b3627965daa00e62e8ad9ca94a137509fb4b35e6..a15d7731337f9f574d7dc6dabf663bae0ec2c247 100644 --- a/src/plugins/valgrind/memcheckerrorview.cpp +++ b/src/plugins/valgrind/memcheckerrorview.cpp @@ -50,7 +50,7 @@ namespace Valgrind { namespace Internal { MemcheckErrorView::MemcheckErrorView(QWidget *parent) - : Analyzer::DetailedErrorView(parent), + : Debugger::DetailedErrorView(parent), m_settings(0) { m_suppressAction = new QAction(this); diff --git a/src/plugins/valgrind/memcheckerrorview.h b/src/plugins/valgrind/memcheckerrorview.h index 38f92fcf46f65b29b7c6f01d209ddf0de99ef392..205c7238415ffe2f2c9d3ae77e15e709e9f3fc85 100644 --- a/src/plugins/valgrind/memcheckerrorview.h +++ b/src/plugins/valgrind/memcheckerrorview.h @@ -36,7 +36,7 @@ namespace Internal { class ValgrindBaseSettings; -class MemcheckErrorView : public Analyzer::DetailedErrorView +class MemcheckErrorView : public Debugger::DetailedErrorView { Q_OBJECT diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 43f15739c8a6aa866bc941ac9e4738663b376101..07431252ebc2129d015ff6ce83614f0f6b5064ac 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -85,14 +85,60 @@ #include <QString> #include <QToolButton> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; +using namespace Utils; using namespace Valgrind::XmlProtocol; namespace Valgrind { namespace Internal { -class FrameFinder; +class FrameFinder : public ErrorListModel::RelevantFrameFinder +{ +public: + Frame findRelevant(const Error &error) const + { + const QVector<Stack> stacks = error.stacks(); + if (stacks.isEmpty()) + return Frame(); + const Stack &stack = stacks[0]; + const QVector<Frame> frames = stack.frames(); + if (frames.isEmpty()) + return Frame(); + + //find the first frame belonging to the project + if (!m_projectFiles.isEmpty()) { + foreach (const Frame &frame, frames) { + if (frame.directory().isEmpty() || frame.fileName().isEmpty()) + continue; + + //filepaths can contain "..", clean them: + const QString f = QFileInfo(frame.filePath()).absoluteFilePath(); + if (m_projectFiles.contains(f)) + return frame; + } + } + + //if no frame belonging to the project was found, return the first one that is not malloc/new + foreach (const Frame &frame, frames) { + if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc") + && !frame.functionName().startsWith(QLatin1String("operator new("))) + { + return frame; + } + } + + //else fallback to the first frame + return frames.first(); + } + void setFiles(const QStringList &files) + { + m_projectFiles = files; + } +private: + QStringList m_projectFiles; +}; + class MemcheckErrorFilterProxyModel : public QSortFilterProxyModel { @@ -203,12 +249,13 @@ class MemcheckTool : public QObject public: MemcheckTool(QObject *parent); - QWidget *createWidgets(); + void createWidgets(); MemcheckRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); private: + void updateRunActions(); void settingsDestroyed(QObject *settings); void maybeActiveRunConfigurationChanged(); @@ -240,10 +287,14 @@ private: QList<QAction *> m_errorFilterActions; QAction *m_filterProjectAction; QList<QAction *> m_suppressionActions; + QAction *m_startAction; + QAction *m_startWithGdbAction; + QAction *m_stopAction; QAction *m_suppressionSeparator; QAction *m_loadExternalLogFile; QAction *m_goBack; QAction *m_goNext; + bool m_toolBusy = false; }; MemcheckTool::MemcheckTool(QObject *parent) @@ -288,7 +339,79 @@ MemcheckTool::MemcheckTool(QObject *parent) using namespace std::placeholders; - AnalyzerManager::registerToolbar(MemcheckPerspectiveId, createWidgets()); + QTC_ASSERT(!m_errorView, return); + + m_errorView = new MemcheckErrorView; + m_errorView->setObjectName(QLatin1String("MemcheckErrorView")); + m_errorView->setFrameStyle(QFrame::NoFrame); + m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false); + m_errorModel = new ErrorListModel(m_errorView); + m_frameFinder = new Internal::FrameFinder; + m_errorModel->setRelevantFrameFinder(QSharedPointer<Internal::FrameFinder>(m_frameFinder)); + m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView); + m_errorProxyModel->setSourceModel(m_errorModel); + m_errorProxyModel->setDynamicSortFilter(true); + m_errorView->setModel(m_errorProxyModel); + m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection); + // make m_errorView->selectionModel()->selectedRows() return something + m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + m_errorView->setAutoScroll(false); + m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView")); + m_errorView->setWindowTitle(tr("Memory Issues")); + + Debugger::registerPerspective(MemcheckPerspectiveId, { tr("Memcheck"), { + { MemcheckErrorDockId, m_errorView, {}, Perspective::SplitVertical } + }}); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &MemcheckTool::maybeActiveRunConfigurationChanged); + + // + // The Control Widget. + // + + m_startAction = Debugger::createStartAction(); + m_startWithGdbAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); + + // Load external XML log file + auto action = new QAction(this); + action->setIcon(Core::Icons::OPENFILE.icon()); + action->setToolTip(tr("Load External XML Log File")); + connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile); + m_loadExternalLogFile = action; + + // Go to previous leak. + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::PREV.icon()); + action->setToolTip(tr("Go to previous leak.")); + connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack); + m_goBack = action; + + // Go to next leak. + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::NEXT.icon()); + action->setToolTip(tr("Go to next leak.")); + connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext); + m_goNext = action; + + auto filterButton = new QToolButton; + filterButton->setIcon(Core::Icons::FILTER.icon()); + filterButton->setText(tr("Error Filter")); + filterButton->setPopupMode(QToolButton::InstantPopup); + filterButton->setProperty("noArrow", true); + + m_filterMenu = new QMenu(filterButton); + foreach (QAction *filterAction, m_errorFilterActions) + m_filterMenu->addAction(filterAction); + m_filterMenu->addSeparator(); + m_filterMenu->addAction(m_filterProjectAction); + m_filterMenu->addAction(m_suppressionSeparator); + connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter); + filterButton->setMenu(m_filterMenu); ActionDescription desc; desc.setToolTip(tr("Valgrind Analyze Memory uses the " @@ -300,8 +423,8 @@ MemcheckTool::MemcheckTool(QObject *parent) desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2)); desc.setToolMode(DebugMode); desc.setRunMode(MEMCHECK_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction("Memcheck.Local", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction("Memcheck.Local", desc, m_startAction); desc.setText(tr("Valgrind Memory Analyzer with GDB")); desc.setToolTip(tr("Valgrind Analyze Memory with GDB uses the " @@ -311,8 +434,8 @@ MemcheckTool::MemcheckTool(QObject *parent) desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2)); desc.setToolMode(DebugMode); desc.setRunMode(MEMCHECK_WITH_GDB_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction("MemcheckWithGdb.Local", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction("MemcheckWithGdb.Local", desc, m_startWithGdbAction); } desc.setText(tr("Valgrind Memory Analyzer (External Application)")); @@ -331,8 +454,42 @@ MemcheckTool::MemcheckTool(QObject *parent) rc->setDisplayName(runnable.executable); ProjectExplorerPlugin::startRunControl(rc, MEMCHECK_RUN_MODE); }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction("Memcheck.Remote", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction("Memcheck.Remote", desc); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + //toolbar.addAction(m_startWithGdbAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_loadExternalLogFile); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + toolbar.addWidget(filterButton); + Debugger::registerToolbar(MemcheckPerspectiveId, toolbar); +} + +void MemcheckTool::updateRunActions() +{ + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress.")); + m_startWithGdbAction->setEnabled(false); + m_startWithGdbAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress.")); + m_stopAction->setEnabled(true); + } else { + const bool projectUsable = SessionManager::startupProject() != 0; + m_startAction->setToolTip(tr("Start a Valgrind Memcheck analysis.")); + m_startWithGdbAction->setToolTip(tr("Start a Valgrind Memcheck with GDB analysis.")); + if (projectUsable) { + m_startAction->setEnabled(true); + m_startWithGdbAction->setEnabled(true); + m_stopAction->setEnabled(false); + } else { + m_startAction->setEnabled(false); + m_startWithGdbAction->setEnabled(false); + m_stopAction->setEnabled(false); + } + } } void MemcheckTool::settingsDestroyed(QObject *settings) @@ -368,6 +525,8 @@ void MemcheckTool::updateFromSettings() void MemcheckTool::maybeActiveRunConfigurationChanged() { + updateRunActions(); + ValgrindBaseSettings *settings = 0; if (Project *project = SessionManager::startupProject()) if (Target *target = project->activeTarget()) @@ -395,150 +554,6 @@ void MemcheckTool::maybeActiveRunConfigurationChanged() updateFromSettings(); } -class FrameFinder : public ErrorListModel::RelevantFrameFinder -{ -public: - Frame findRelevant(const Error &error) const - { - const QVector<Stack> stacks = error.stacks(); - if (stacks.isEmpty()) - return Frame(); - const Stack &stack = stacks[0]; - const QVector<Frame> frames = stack.frames(); - if (frames.isEmpty()) - return Frame(); - - //find the first frame belonging to the project - if (!m_projectFiles.isEmpty()) { - foreach (const Frame &frame, frames) { - if (frame.directory().isEmpty() || frame.fileName().isEmpty()) - continue; - - //filepaths can contain "..", clean them: - const QString f = QFileInfo(frame.filePath()).absoluteFilePath(); - if (m_projectFiles.contains(f)) - return frame; - } - } - - //if no frame belonging to the project was found, return the first one that is not malloc/new - foreach (const Frame &frame, frames) { - if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc") - && !frame.functionName().startsWith(QLatin1String("operator new("))) - { - return frame; - } - } - - //else fallback to the first frame - return frames.first(); - } - void setFiles(const QStringList &files) - { - m_projectFiles = files; - } -private: - QStringList m_projectFiles; -}; - - -QWidget *MemcheckTool::createWidgets() -{ - QTC_ASSERT(!m_errorView, return 0); - - m_errorView = new MemcheckErrorView; - m_errorView->setObjectName(QLatin1String("MemcheckErrorView")); - m_errorView->setFrameStyle(QFrame::NoFrame); - m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false); - m_errorModel = new ErrorListModel(m_errorView); - m_frameFinder = new Internal::FrameFinder; - m_errorModel->setRelevantFrameFinder(QSharedPointer<Internal::FrameFinder>(m_frameFinder)); - m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView); - m_errorProxyModel->setSourceModel(m_errorModel); - m_errorProxyModel->setDynamicSortFilter(true); - m_errorView->setModel(m_errorProxyModel); - m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection); - // make m_errorView->selectionModel()->selectedRows() return something - m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - m_errorView->setAutoScroll(false); - m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView")); - m_errorView->setWindowTitle(tr("Memory Issues")); - - AnalyzerManager::registerDockWidget(MemcheckErrorDockId, m_errorView); - - AnalyzerManager::registerPerspective(MemcheckPerspectiveId, { - { MemcheckErrorDockId, Core::Id(), Perspective::SplitVertical } - }); - - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &MemcheckTool::maybeActiveRunConfigurationChanged); - - // - // The Control Widget. - // - QAction *action = 0; - QHBoxLayout *layout = new QHBoxLayout; - QToolButton *button = 0; - - layout->setMargin(0); - layout->setSpacing(0); - - // Load external XML log file - action = new QAction(this); - action->setIcon(Core::Icons::OPENFILE.icon()); - action->setToolTip(tr("Load External XML Log File")); - connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_loadExternalLogFile = action; - - // Go to previous leak. - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::PREV.icon()); - action->setToolTip(tr("Go to previous leak.")); - connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_goBack = action; - - // Go to next leak. - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::NEXT.icon()); - action->setToolTip(tr("Go to next leak.")); - connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_goNext = action; - - QToolButton *filterButton = new QToolButton; - filterButton->setIcon(Core::Icons::FILTER.icon()); - filterButton->setText(tr("Error Filter")); - filterButton->setPopupMode(QToolButton::InstantPopup); - filterButton->setProperty("noArrow", true); - - m_filterMenu = new QMenu(filterButton); - foreach (QAction *filterAction, m_errorFilterActions) - m_filterMenu->addAction(filterAction); - m_filterMenu->addSeparator(); - m_filterMenu->addAction(m_filterProjectAction); - m_filterMenu->addAction(m_suppressionSeparator); - connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter); - filterButton->setMenu(m_filterMenu); - layout->addWidget(filterButton); - - layout->addStretch(); - QWidget *widget = new QWidget; - widget->setObjectName(QLatin1String("MemCheckToolBarWidget")); - widget->setLayout(layout); - return widget; -} - MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, Core::Id runMode) { @@ -555,6 +570,12 @@ MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfigur connect(runControl, &MemcheckRunControl::parserError, this, &MemcheckTool::parserError); connect(runControl, &MemcheckRunControl::internalParserError, this, &MemcheckTool::internalParserError); connect(runControl, &MemcheckRunControl::finished, this, &MemcheckTool::engineFinished); + + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + m_toolBusy = true; + updateRunActions(); + return runControl; } @@ -673,18 +694,19 @@ int MemcheckTool::updateUiAfterFinishedHelper() void MemcheckTool::engineFinished() { + m_toolBusy = false; + updateRunActions(); + const int issuesFound = updateUiAfterFinishedHelper(); - AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 - ? AnalyzerManager::tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound) - : AnalyzerManager::tr("Memory Analyzer Tool finished, no issues were found.")); + Debugger::showPermanentStatusMessage( + tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound)); } void MemcheckTool::loadingExternalXmlLogFileFinished() { const int issuesFound = updateUiAfterFinishedHelper(); - AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 - ? AnalyzerManager::tr("Log file processed, %n issues were found.", 0, issuesFound) - : AnalyzerManager::tr("Log file processed, no issues were found.")); + Debugger::showPermanentStatusMessage( + tr("Log file processed, %n issues were found.", 0, issuesFound)); } void MemcheckTool::setBusyCursor(bool busy) diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 12c2215c4075c3a81e2f8fe9c3cc1ba601a57c71..2f3825d2b597f31d7b79a22152a57a603efa0ade 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -43,7 +43,7 @@ #define VALGRIND_DEBUG_OUTPUT 0 -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace Utils; using namespace ProjectExplorer; @@ -65,10 +65,8 @@ ValgrindRunControl::ValgrindRunControl(RunConfiguration *runConfiguration, Core: m_settings = ValgrindPlugin::globalSettings(); } -bool ValgrindRunControl::startEngine() +void ValgrindRunControl::start() { - emit starting(); - FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100); fp->setKeepOnFinish(FutureProgress::HideOnFinish); connect(fp, &FutureProgress::canceled, @@ -86,7 +84,6 @@ bool ValgrindRunControl::startEngine() ValgrindRunner *run = runner(); run->setValgrindExecutable(m_settings->valgrindExecutable()); run->setValgrindArguments(genericToolArguments() + toolArguments()); - QTC_ASSERT(!device().isNull(), return false); run->setDevice(device()); run->setDebuggee(runnable().as<StandardRunnable>()); @@ -99,15 +96,24 @@ bool ValgrindRunControl::startEngine() if (!run->start()) { m_progress.cancel(); - return false; + emit finished(); + return; } - return true; + + m_isRunning = true; + emit started(); } -void ValgrindRunControl::stopEngine() +RunControl::StopResult ValgrindRunControl::stop() { m_isStopping = true; runner()->stop(); + return AsynchronousStop; +} + +bool ValgrindRunControl::isRunning() const +{ + return m_isRunning; } QString ValgrindRunControl::executable() const @@ -139,7 +145,6 @@ QStringList ValgrindRunControl::genericToolArguments() const void ValgrindRunControl::handleProgressCanceled() { - AnalyzerManager::stopTool(); m_progress.reportCanceled(); m_progress.reportFinished(); } @@ -151,6 +156,8 @@ void ValgrindRunControl::handleProgressFinished() void ValgrindRunControl::runnerFinished() { + m_isRunning = false; + appendMessage(tr("Analyzing finished.") + QLatin1Char('\n'), NormalMessageFormat); emit finished(); diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index 302f3a7bdb4699a6222a7f282e2571bbe697cb9b..fa9ffcc91aabdc8bc5b5b30aa9f89aa22582ff06 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -38,7 +38,7 @@ namespace Valgrind { namespace Internal { -class ValgrindRunControl : public Analyzer::AnalyzerRunControl +class ValgrindRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -46,8 +46,9 @@ public: ValgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; + bool isRunning() const override; QString executable() const; @@ -70,6 +71,7 @@ private: QStringList genericToolArguments() const; private: + bool m_isRunning = false; bool m_isStopping = false; }; diff --git a/src/plugins/valgrind/valgrindruncontrolfactory.cpp b/src/plugins/valgrind/valgrindruncontrolfactory.cpp index 2db334b5845d73bf6ffaa26e286ee0df0b189caf..f1338b1665587e95640d35181bb7ec616ef33de9 100644 --- a/src/plugins/valgrind/valgrindruncontrolfactory.cpp +++ b/src/plugins/valgrind/valgrindruncontrolfactory.cpp @@ -36,7 +36,7 @@ #include <utils/qtcassert.h> -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Valgrind { @@ -56,7 +56,7 @@ bool ValgrindRunControlFactory::canRun(RunConfiguration *runConfiguration, Core: RunControl *ValgrindRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) { Q_UNUSED(errorMessage); - return AnalyzerManager::createRunControl(runConfiguration, mode); + return Debugger::createAnalyzerRunControl(runConfiguration, mode); } class ValgrindRunConfigurationAspect : public IRunConfigurationAspect diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index 763e7110261baf0a4638f7bc202707abd9384754..420b5e88775e44cd2493ab0f71ce9586fec11152 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -188,8 +188,8 @@ QString ValgrindRunner::errorString() const void ValgrindRunner::stop() { - if (d->process) - d->process->close(); + QTC_ASSERT(d->process, finished(); return); + d->process->close(); } ValgrindProcess *ValgrindRunner::valgrindProcess() const diff --git a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp index c625a58920a4930633de4b0e4ba6570ad6524889..915b0ab4e88f1a9e05e23fea56f1e5a2f101763c 100644 --- a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp +++ b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp @@ -191,8 +191,8 @@ ErrorItem::ErrorItem(const ErrorListModelPrivate *modelPrivate, const Error &err static QVariant location(const Frame &frame, int role) { switch (role) { - case Analyzer::DetailedErrorView::LocationRole: - return QVariant::fromValue(Analyzer::DiagnosticLocation(frame.filePath(), frame.line(), 0)); + case Debugger::DetailedErrorView::LocationRole: + return QVariant::fromValue(Debugger::DiagnosticLocation(frame.filePath(), frame.line(), 0)); case Qt::ToolTipRole: return frame.filePath().isEmpty() ? QVariant() : QVariant(frame.filePath()); default: @@ -202,14 +202,14 @@ static QVariant location(const Frame &frame, int role) QVariant ErrorItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) { + if (column == Debugger::DetailedErrorView::LocationColumn) { const Frame frame = m_modelPrivate->findRelevantFrame(m_error); return location(frame, role); } // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: { + case Debugger::DetailedErrorView::FullTextRole: { QString content; QTextStream stream(&content); @@ -257,7 +257,7 @@ StackItem::StackItem(const Stack &stack) : m_stack(stack) QVariant StackItem::data(int column, int role) const { const ErrorItem * const errorItem = getErrorItem(); - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return location(errorItem->modelPrivate()->findRelevantFrame(errorItem->error()), role); // DiagnosticColumn @@ -285,7 +285,7 @@ FrameItem::FrameItem(const Frame &frame) : m_frame(frame) QVariant FrameItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return location(m_frame, role); // DiagnosticColumn diff --git a/src/plugins/valgrind/xmlprotocol/errorlistmodel.h b/src/plugins/valgrind/xmlprotocol/errorlistmodel.h index 9db79252b3cfdc015001edde7260cee37b3552f4..ec7f5de61c67c8291c121fa6ef0d3c14e4119f50 100644 --- a/src/plugins/valgrind/xmlprotocol/errorlistmodel.h +++ b/src/plugins/valgrind/xmlprotocol/errorlistmodel.h @@ -45,7 +45,7 @@ class ErrorListModel : public Utils::TreeModel public: enum Role { - ErrorRole = Analyzer::DetailedErrorView::FullTextRole + 1, + ErrorRole = Debugger::DetailedErrorView::FullTextRole + 1, }; class RelevantFrameFinder diff --git a/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp b/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp index e8050c514ed218ae4f325869a0af761b759cf638..076f576e82bf5c8cee71e0b8abe32a303f59cdff 100644 --- a/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp +++ b/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp @@ -31,7 +31,7 @@ enum { debug = 0 }; -using namespace Analyzer; +using namespace Debugger; using namespace ClangStaticAnalyzer::Internal; namespace {