Files
qt-creator/src/plugins/projectexplorer/parseissuesdialog.cpp

172 lines
6.5 KiB
C++
Raw Normal View History

/****************************************************************************
**
** 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 <coreplugin/progressmanager/progressmanager.h>
#include <utils/runextensions.h>
#include <QButtonGroup>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QFile>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <memory>
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<void> &future, const QString &output,
const std::unique_ptr<IOutputParser> &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<IOutputParser> 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<void> 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