diff --git a/src/plugins/projectexplorer/kitchooser.h b/src/plugins/projectexplorer/kitchooser.h index bd7b8ce5cf2..0f23baa5378 100644 --- a/src/plugins/projectexplorer/kitchooser.h +++ b/src/plugins/projectexplorer/kitchooser.h @@ -56,6 +56,7 @@ public: void setKitPredicate(const Kit::Predicate &predicate); Kit *currentKit() const; + bool hasStartupKit() const { return m_hasStartupKit; } signals: void currentIndexChanged(); diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp new file mode 100644 index 00000000000..5b6015b5a53 --- /dev/null +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** 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 "parseissuesdialog.h" + +#include "ioutputparser.h" +#include "kitinformation.h" +#include "kitchooser.h" +#include "kitmanager.h" +#include "projectexplorerconstants.h" +#include "taskhub.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace ProjectExplorer { +namespace Internal { + +class ParseIssuesDialog::Private +{ +public: + QPlainTextEdit compileOutputEdit; + QCheckBox stderrCheckBox; + QCheckBox clearTasksCheckBox; + KitChooser kitChooser; +}; + +ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new Private) +{ + setWindowTitle(tr("Parse Build Output")); + + d->stderrCheckBox.setText(tr("Output went to stderr")); + d->stderrCheckBox.setChecked(true); + + d->clearTasksCheckBox.setText(tr("Clear existing tasks")); + d->clearTasksCheckBox.setChecked(true); + + const auto loadFileButton = new QPushButton(tr("Load from file...")); + connect(loadFileButton, &QPushButton::clicked, this, [this] { + const QString filePath = QFileDialog::getOpenFileName(this, tr("Choose File")); + if (filePath.isEmpty()) + return; + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("Could not open file"), + tr("Could not open file: \"%1\": %2") + .arg(filePath, file.errorString())); + return; + } + d->compileOutputEdit.setPlainText(QString::fromLocal8Bit(file.readAll())); + }); + + d->kitChooser.populate(); + if (!d->kitChooser.hasStartupKit()) { + for (const Kit * const k : KitManager::kits()) { + if (DeviceTypeKitAspect::deviceTypeId(k) == Constants::DESKTOP_DEVICE_TYPE) { + d->kitChooser.setCurrentKitId(k->id()); + break; + } + } + } + + const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + buttonBox->button(QDialogButtonBox::Ok)->setEnabled(d->kitChooser.currentKit()); + + const auto layout = new QVBoxLayout(this); + const auto outputGroupBox = new QGroupBox(tr("Build Output")); + layout->addWidget(outputGroupBox); + const auto outputLayout = new QHBoxLayout(outputGroupBox); + outputLayout->addWidget(&d->compileOutputEdit); + const auto buttonsWidget = new QWidget; + const auto outputButtonsLayout = new QVBoxLayout(buttonsWidget); + outputLayout->addWidget(buttonsWidget); + outputButtonsLayout->addWidget(loadFileButton); + outputButtonsLayout->addWidget(&d->stderrCheckBox); + outputButtonsLayout->addStretch(1); + + // TODO: Only very few parsers are available from a Kit (basically just the Toolchain one). + // If we introduced factories for IOutputParsers, we could offer the user + // to combine arbitrary parsers here. + const auto parserGroupBox = new QGroupBox(tr("Parsing options")); + layout->addWidget(parserGroupBox); + const auto parserLayout = new QVBoxLayout(parserGroupBox); + const auto kitChooserWidget = new QWidget; + const auto kitChooserLayout = new QHBoxLayout(kitChooserWidget); + kitChooserLayout->setContentsMargins(0, 0, 0, 0); + kitChooserLayout->addWidget(new QLabel(tr("Use parsers from kit:"))); + kitChooserLayout->addWidget(&d->kitChooser); + parserLayout->addWidget(kitChooserWidget); + parserLayout->addWidget(&d->clearTasksCheckBox); + + layout->addWidget(buttonBox); +} + +ParseIssuesDialog::~ParseIssuesDialog() +{ + delete d; +} + +static void parse(QFutureInterface &future, const QString &output, + const std::unique_ptr &parser, bool isStderr) +{ + const QStringList lines = output.split('\n'); + future.setProgressRange(0, lines.count()); + const auto parserFunc = isStderr ? &IOutputParser::stdError : &IOutputParser::stdOutput; + for (const QString &line : lines) { + (parser.get()->*parserFunc)(line); + future.setProgressValue(future.progressValue() + 1); + if (future.isCanceled()) + return; + } +} + +void ParseIssuesDialog::accept() +{ + std::unique_ptr parser(d->kitChooser.currentKit()->createOutputParser()); + if (!parser) { + QMessageBox::critical(this, tr("Cannot parse"), tr("Cannot parse: The chosen kit does " + "not provide an output parser.")); + return; + } + if (d->clearTasksCheckBox.isChecked()) + TaskHub::clearTasks(); + connect(parser.get(), &IOutputParser::addTask, [](const Task &t) { TaskHub::addTask(t); }); + const QFuture f = Utils::runAsync(&parse, d->compileOutputEdit.toPlainText(), + std::move(parser), d->stderrCheckBox.isChecked()); + Core::ProgressManager::addTask(f, tr("Parsing build output"), + "ProgressExplorer.ParseExternalBuildOutput"); + QDialog::accept(); +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/parseissuesdialog.h b/src/plugins/projectexplorer/parseissuesdialog.h new file mode 100644 index 00000000000..555727c3b99 --- /dev/null +++ b/src/plugins/projectexplorer/parseissuesdialog.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** 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. +** +****************************************************************************/ + +#pragma once + +#include + +namespace ProjectExplorer { +namespace Internal { + +class ParseIssuesDialog : public QDialog +{ + Q_OBJECT +public: + ParseIssuesDialog(QWidget *parent = nullptr); + ~ParseIssuesDialog() override; + +private: + void accept() override; + + class Private; + Private * const d; +}; + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 83536065cc2..5b3227fabbe 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -50,6 +50,7 @@ #include "kitfeatureprovider.h" #include "kitmanager.h" #include "kitoptionspage.h" +#include "parseissuesdialog.h" #include "target.h" #include "toolchainmanager.h" #include "toolchainoptionspage.h" @@ -1813,6 +1814,16 @@ void ProjectExplorerPlugin::extensionsInitialized() }; QSsh::SshSettings::setExtraSearchPathRetriever(searchPathRetriever); + const auto parseIssuesAction = new QAction(tr("Parse Build Output..."), this); + ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS); + Command * const cmd = ActionManager::registerAction(parseIssuesAction, + "ProjectExplorer.ParseIssuesAction"); + connect(parseIssuesAction, &QAction::triggered, this, [] { + ParseIssuesDialog dlg(ICore::mainWindow()); + dlg.exec(); + }); + mtools->addAction(cmd); + // delay restoring kits until UI is shown for improved perceived startup performance QTimer::singleShot(0, this, &ProjectExplorerPlugin::restoreKits); } diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 5ea0b2b9962..097fcb6da50 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -160,6 +160,7 @@ HEADERS += projectexplorer.h \ customexecutablerunconfiguration.h \ projectmacro.h \ makestep.h \ + parseissuesdialog.h \ projectconfigurationaspects.h \ treescanner.h @@ -303,6 +304,7 @@ SOURCES += projectexplorer.cpp \ customexecutablerunconfiguration.cpp \ projectmacro.cpp \ makestep.cpp \ + parseissuesdialog.cpp \ projectconfigurationaspects.cpp \ treescanner.cpp diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 9e65565e966..395c1cced90 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -99,6 +99,7 @@ Project { "namedwidget.cpp", "namedwidget.h", "osparser.cpp", "osparser.h", "panelswidget.cpp", "panelswidget.h", + "parseissuesdialog.cpp", "parseissuesdialog.h", "processparameters.cpp", "processparameters.h", "processstep.cpp", "processstep.h", "project.cpp", "project.h",