ClangTools: Introduce an info bar

...displaying status information and errors.

Change-Id: I4f86b440b28e82786299700dee572e77de7334f3
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Nikolai Kosjar
2019-10-28 16:25:07 +01:00
parent 7bb333f15a
commit fbd350f31f
9 changed files with 618 additions and 230 deletions

View File

@@ -59,13 +59,17 @@
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
#include <utils/fancylineedit.h>
#include <utils/fancymainwindow.h>
#include <utils/progressindicator.h>
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QCheckBox>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QSortFilterProxyModel>
#include <QToolButton>
@@ -81,6 +85,145 @@ namespace Internal {
static ClangTool *s_instance;
static QString makeLink(const QString &text)
{
return QString("<a href=t>%1</a>").arg(text);
}
class IconAndLabel : public QWidget
{
Q_OBJECT
public:
IconAndLabel(const QPixmap &pixmap, const QString &text = {})
: m_icon(new QLabel)
, m_label(new QLabel)
{
QSizePolicy minSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
minSizePolicy.setHorizontalStretch(0);
m_icon->setPixmap(pixmap);
m_icon->setSizePolicy(minSizePolicy);
m_label->setSizePolicy(minSizePolicy);
m_label->setText(text);
m_label->setTextInteractionFlags(Qt::TextBrowserInteraction);
QHBoxLayout *layout = new QHBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_icon);
layout->addWidget(m_label);
setLayout(layout);
connect(m_label, &QLabel::linkActivated, this, &IconAndLabel::linkActivated);
}
void setIcon(const QPixmap &pixmap) {
m_icon->setPixmap(pixmap);
m_icon->setVisible(!pixmap.isNull());
}
QString text() const { return m_label->text(); }
void setText(const QString &text)
{
m_label->setText(text);
setVisible(!text.isEmpty());
}
signals:
void linkActivated(const QString &link);
private:
QLabel *m_icon;
QLabel *m_label;
};
class InfoBarWidget : public QFrame
{
Q_OBJECT
public:
InfoBarWidget()
: m_progressIndicator(new Utils::ProgressIndicator(ProgressIndicatorSize::Small))
, m_info(new IconAndLabel(Utils::Icons::INFO.pixmap()))
, m_error(new IconAndLabel(Utils::Icons::WARNING.pixmap()))
, m_diagStats(new QLabel)
{
m_diagStats->setTextInteractionFlags(Qt::TextBrowserInteraction);
QHBoxLayout *layout = new QHBoxLayout;
layout->setContentsMargins(5, 5, 5, 5);
layout->addWidget(m_progressIndicator);
layout->addWidget(m_info);
layout->addWidget(m_error);
layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
layout->addWidget(m_diagStats);
setLayout(layout);
QPalette pal;
pal.setColor(QPalette::Window, Utils::creatorTheme()->color(Utils::Theme::InfoBarBackground));
pal.setColor(QPalette::WindowText, Utils::creatorTheme()->color(Utils::Theme::InfoBarText));
setPalette(pal);
setAutoFillBackground(true);
}
// Info
enum InfoIconType { ProgressIcon, InfoIcon };
void setInfoIcon(InfoIconType type)
{
const bool showProgress = type == ProgressIcon;
m_progressIndicator->setVisible(showProgress);
m_info->setIcon(showProgress ? QPixmap() : Utils::Icons::INFO.pixmap());
}
QString infoText() const { return m_info->text(); }
void setInfoText(const QString &text)
{
m_info->setText(text);
evaluateVisibility();
}
// Error
using OnLinkActivated = std::function<void()>;
enum IssueType { Warning, Error };
QString errorText() const { return m_error->text(); }
void setError(IssueType type,
const QString &text,
const OnLinkActivated &linkAction = OnLinkActivated())
{
m_error->setText(text);
m_error->setIcon(type == Warning ? Utils::Icons::WARNING.pixmap()
: Utils::Icons::CRITICAL.pixmap());
m_error->disconnect();
if (linkAction)
connect(m_error, &IconAndLabel::linkActivated, this, linkAction);
evaluateVisibility();
}
// Diag stats
void setDiagText(const QString &text) { m_diagStats->setText(text); }
void reset()
{
setInfoIcon(InfoIcon);
setInfoText({});
setError(Warning, {}, {});
setDiagText({});
}
void evaluateVisibility()
{
setVisible(!infoText().isEmpty() || !errorText().isEmpty());
}
private:
Utils::ProgressIndicator *m_progressIndicator;
IconAndLabel *m_info;
IconAndLabel *m_error;
QLabel *m_diagStats;
};
class SelectFixitsCheckBox : public QCheckBox
{
Q_OBJECT
@@ -257,11 +400,12 @@ static FileInfos sortedFileInfos(const QVector<CppTools::ProjectPart::Ptr> &proj
static RunSettings runSettings()
{
Project *project = SessionManager::startupProject();
auto *projectSettings = ClangToolsProjectSettingsManager::getSettings(project);
if (projectSettings->useGlobalSettings())
return ClangToolsSettings::instance()->runSettings();
return projectSettings->runSettings();
if (Project *project = SessionManager::startupProject()) {
auto *projectSettings = ClangToolsProjectSettingsManager::getSettings(project);
if (!projectSettings->useGlobalSettings())
return projectSettings->runSettings();
}
return ClangToolsSettings::instance()->runSettings();
}
static ClangDiagnosticConfig diagnosticConfig(const Core::Id &diagConfigId)
@@ -310,25 +454,25 @@ ClangTool::ClangTool()
m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
m_diagnosticFilterModel->setDynamicSortFilter(true);
m_infoBarWidget = new InfoBarWidget;
m_diagnosticView = new DiagnosticView;
initDiagnosticView();
m_diagnosticView->setModel(m_diagnosticFilterModel);
m_diagnosticView->setSortingEnabled(true);
m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn,
Qt::AscendingOrder);
m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView"));
m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Diagnostics"));
foreach (auto * const model,
QList<QAbstractItemModel *>({m_diagnosticModel, m_diagnosticFilterModel})) {
connect(model, &QAbstractItemModel::rowsInserted,
this, &ClangTool::handleStateUpdate);
this, &ClangTool::updateForCurrentState);
connect(model, &QAbstractItemModel::rowsRemoved,
this, &ClangTool::handleStateUpdate);
this, &ClangTool::updateForCurrentState);
connect(model, &QAbstractItemModel::modelReset,
this, &ClangTool::handleStateUpdate);
this, &ClangTool::updateForCurrentState);
connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate()
this, &ClangTool::handleStateUpdate);
this, &ClangTool::updateForCurrentState);
}
// Go to previous diagnostic
@@ -359,10 +503,9 @@ ClangTool::ClangTool()
action->setDisabled(true);
action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
action->setToolTip(tr("Clear"));
connect(action, &QAction::triggered, [this](){
m_clear->setEnabled(false);
m_diagnosticModel->clear();
Debugger::showPermanentStatusMessage(QString());
connect(action, &QAction::triggered, this, [this]() {
reset();
update();
});
m_clear = action;
@@ -410,18 +553,20 @@ ClangTool::ClangTool()
connect(m_diagnosticModel, &ClangToolsDiagnosticModel::fixitStatusChanged,
m_diagnosticFilterModel, &DiagnosticFilterModel::onFixitStatusChanged);
connect(m_diagnosticFilterModel, &DiagnosticFilterModel::fixitStatisticsChanged,
connect(m_diagnosticFilterModel, &DiagnosticFilterModel::fixitCountersChanged,
this,
[this](int scheduled, int scheduableTotal){
m_selectFixitsCheckBox->setEnabled(scheduableTotal > 0);
[this](int scheduled, int scheduable){
m_selectFixitsCheckBox->setEnabled(scheduable > 0);
m_applyFixitsButton->setEnabled(scheduled > 0);
if (scheduled == 0)
m_selectFixitsCheckBox->setCheckState(Qt::Unchecked);
else if (scheduled == scheduableTotal)
else if (scheduled == scheduable)
m_selectFixitsCheckBox->setCheckState(Qt::Checked);
else
m_selectFixitsCheckBox->setCheckState(Qt::PartiallyChecked);
updateForCurrentState();
});
connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
QVector<DiagnosticItem *> diagnosticItems;
@@ -445,7 +590,17 @@ ClangTool::ClangTool()
const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the "
"Clang project to search for diagnostics.");
m_perspective.addWindow(m_diagnosticView, Perspective::SplitVertical, nullptr);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(1);
mainLayout->addWidget(m_infoBarWidget);
mainLayout->addWidget(m_diagnosticView);
auto mainWidget = new QWidget;
mainWidget->setObjectName("ClangTidyClazyIssuesView");
mainWidget->setWindowTitle(tr("Clang-Tidy and Clazy"));
mainWidget->setLayout(mainLayout);
m_perspective.addWindow(mainWidget, Perspective::SplitVertical, nullptr);
action = new QAction(tr("Clang-Tidy and Clazy..."), this);
action->setToolTip(toolTip);
@@ -479,10 +634,14 @@ ClangTool::ClangTool()
m_perspective.addToolBarWidget(m_selectFixitsCheckBox);
m_perspective.addToolBarWidget(m_applyFixitsButton);
updateRunActions();
update();
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
this, &ClangTool::updateRunActions);
this, &ClangTool::update);
connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated,
this, &ClangTool::update);
connect(ClangToolsSettings::instance(), &ClangToolsSettings::changed,
this, &ClangTool::update);
}
ClangTool::~ClangTool()
@@ -501,6 +660,33 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection)
startTool(fileSelection, theRunSettings, diagnosticConfig(theRunSettings.diagnosticConfigId()));
}
static bool continueDespiteReleaseBuild(const QString &toolName)
{
const QString wrongMode = ClangTool::tr("Release");
const QString title = ClangTool::tr("Run %1 in %2 Mode?").arg(toolName, wrongMode);
const QString problem
= ClangTool::tr(
"You are trying to run the tool \"%1\" on an application in %2 mode. The tool is "
"designed to be used in Debug mode since enabled assertions can reduce the number of "
"false positives.")
.arg(toolName, wrongMode);
const QString question = ClangTool::tr(
"Do you want to continue and run the tool in %1 mode?")
.arg(wrongMode);
const QString message = QString("<html><head/><body>"
"<p>%1</p>"
"<p>%2</p>"
"</body></html>")
.arg(problem, question);
return CheckableMessageBox::doNotAskAgainQuestion(ICore::mainWindow(),
title,
message,
ICore::settings(),
"ClangToolsCorrectModeWarning")
== QDialogButtonBox::Yes;
}
void ClangTool::startTool(ClangTool::FileSelection fileSelection,
const RunSettings &runSettings,
const CppTools::ClangDiagnosticConfig &diagnosticConfig)
@@ -509,51 +695,58 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection,
QTC_ASSERT(project, return);
QTC_ASSERT(project->activeTarget(), return);
auto runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE);
runControl->setDisplayName(tr("Clang-Tidy and Clazy"));
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setTarget(project->activeTarget());
// Continue despite release mode?
if (BuildConfiguration *bc = project->activeTarget()->activeBuildConfiguration()) {
if (bc->buildType() == BuildConfiguration::Release)
if (!continueDespiteReleaseBuild(m_name))
return;
}
// Collect files to analyze
const FileInfos fileInfos = collectFileInfos(project, fileSelection);
if (fileInfos.empty())
return;
const bool preventBuild = fileSelection == FileSelection::CurrentFile;
auto clangTool = new ClangToolRunWorker(runControl,
runSettings,
diagnosticConfig,
fileInfos,
preventBuild);
// Reset
reset();
// Run control
m_runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE);
m_runControl->setDisplayName(tr("Clang-Tidy and Clazy"));
m_runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
m_runControl->setTarget(project->activeTarget());
m_stopAction->disconnect();
connect(m_stopAction, &QAction::triggered, runControl, [runControl] {
runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."),
NormalMessageFormat);
runControl->initiateStop();
connect(m_stopAction, &QAction::triggered, m_runControl, [this] {
m_runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."),
NormalMessageFormat);
m_runControl->initiateStop();
setState(State::StoppedByUser);
});
connect(m_runControl, &RunControl::stopped, this, &ClangTool::onRunControlStopped);
connect(runControl, &RunControl::stopped, this, [this, clangTool] {
bool success = clangTool->success();
setToolBusy(false);
m_running = false;
handleStateUpdate();
updateRunActions();
emit finished(success);
});
m_perspective.select();
m_diagnosticModel->clear();
// Run worker
const bool preventBuild = fileSelection == FileSelection::CurrentFile;
const bool buildBeforeAnalysis = !preventBuild && runSettings.buildBeforeAnalysis();
m_runWorker = new ClangToolRunWorker(m_runControl,
runSettings,
diagnosticConfig,
fileInfos,
buildBeforeAnalysis);
connect(m_runWorker, &ClangToolRunWorker::buildFailed,this, &ClangTool::onBuildFailed);
connect(m_runWorker, &ClangToolRunWorker::startFailed, this, &ClangTool::onStartFailed);
connect(m_runWorker, &ClangToolRunWorker::started, this, &ClangTool::onStarted);
connect(m_runWorker, &ClangToolRunWorker::runnerFinished,
this, &ClangTool::updateForCurrentState);
// More init and UI update
m_diagnosticFilterModel->setProject(project);
m_selectFixitsCheckBox->setEnabled(false);
m_applyFixitsButton->setEnabled(false);
m_running = true;
m_perspective.select();
if (buildBeforeAnalysis)
m_infoBarWidget->setInfoText("Waiting for build to finish...");
setState(State::PreparationStarted);
setToolBusy(true);
handleStateUpdate();
updateRunActions();
ProjectExplorerPlugin::startRunControl(runControl);
// Start
ProjectExplorerPlugin::startRunControl(m_runControl);
}
Diagnostics ClangTool::read(OutputFileFormat outputFileFormat,
@@ -656,12 +849,145 @@ void ClangTool::loadDiagnosticsFromFiles()
}
// Show errors
if (!errors.isEmpty())
if (!errors.isEmpty()) {
AsynchronousMessageBox::critical(tr("Error Loading Diagnostics"), errors);
return;
}
// Show imported
m_diagnosticModel->clear();
reset();
onNewDiagnosticsAvailable(diagnostics);
setState(State::ImportFinished);
}
void ClangTool::showOutputPane()
{
ProjectExplorerPlugin::showOutputPaneForRunControl(m_runControl);
}
void ClangTool::reset()
{
m_clear->setEnabled(false);
m_selectFixitsCheckBox->setEnabled(false);
m_applyFixitsButton->setEnabled(false);
m_diagnosticModel->clear();
m_diagnosticFilterModel->resetCounters();
m_infoBarWidget->reset();
m_state = State::Initial;
m_runControl = nullptr;
m_runWorker = nullptr;
}
static bool canAnalyzeProject(Project *project)
{
if (const Target *target = project->activeTarget()) {
const Core::Id c = ProjectExplorer::Constants::C_LANGUAGE_ID;
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
const bool projectSupportsLanguage = project->projectLanguages().contains(c)
|| project->projectLanguages().contains(cxx);
return projectSupportsLanguage
&& CppModelManager::instance()->projectInfo(project).isValid()
&& ToolChainKitAspect::toolChain(target->kit(), cxx);
}
return false;
}
struct CheckResult {
enum {
InvalidTidyExecutable,
InvalidClazyExecutable,
ProjectNotOpen,
ProjectNotSuitable,
ReadyToAnalyze,
} kind;
QString errorText;
};
static CheckResult canAnalyze()
{
const ClangDiagnosticConfig config = diagnosticConfig(runSettings().diagnosticConfigId());
if (config.isClangTidyEnabled() && !isFileExecutable(clangTidyExecutable())) {
return {CheckResult::InvalidTidyExecutable,
ClangTool::tr("Set a valid Clang-Tidy executable.")};
}
if (config.isClazyEnabled() && !isFileExecutable(clazyStandaloneExecutable())) {
return {CheckResult::InvalidClazyExecutable,
ClangTool::tr("Set a valid Clazy-Standalone executable.")};
}
if (Project *project = SessionManager::startupProject()) {
if (!canAnalyzeProject(project)) {
return {CheckResult::ProjectNotSuitable,
ClangTool::tr("Project \"%1\" is not a C/C++ project.")
.arg(project->displayName())};
}
} else {
return {CheckResult::ProjectNotOpen,
ClangTool::tr("Open a C/C++ project to start analyzing.")};
}
return {CheckResult::ReadyToAnalyze, {}};
}
void ClangTool::updateForInitialState()
{
if (m_state != State::Initial)
return;
m_infoBarWidget->reset();
const CheckResult result = canAnalyze();
switch (result.kind)
case CheckResult::InvalidTidyExecutable: {
case CheckResult::InvalidClazyExecutable:
m_infoBarWidget->setError(InfoBarWidget::Warning,
makeLink(result.errorText),
[](){ ICore::showOptionsDialog(Constants::SETTINGS_PAGE_ID); });
break;
case CheckResult::ProjectNotSuitable:
case CheckResult::ProjectNotOpen:
case CheckResult::ReadyToAnalyze:
break;
}
}
void ClangTool::onBuildFailed()
{
m_infoBarWidget->setError(InfoBarWidget::Error,
tr("Failed to build the project."),
[this]() { showOutputPane(); });
setState(State::PreparationFailed);
}
void ClangTool::onStartFailed()
{
m_infoBarWidget->setError(InfoBarWidget::Error,
makeLink(tr("Failed to start the analyzer.")),
[this]() { showOutputPane(); });
setState(State::PreparationFailed);
}
void ClangTool::onStarted()
{
setState(State::AnalyzerRunning);
}
void ClangTool::onRunControlStopped()
{
if (m_state != State::StoppedByUser && m_state != State::PreparationFailed)
setState(State::AnalyzerFinished);
emit finished(m_runWorker->success());
}
void ClangTool::update()
{
updateForInitialState();
updateForCurrentState();
}
using DocumentPredicate = std::function<bool(Core::IDocument *)>;
@@ -726,6 +1052,12 @@ FileInfoProviders ClangTool::fileInfoProviders(ProjectExplorer::Project *project
};
}
void ClangTool::setState(ClangTool::State state)
{
m_state = state;
updateForCurrentState();
}
QSet<Diagnostic> ClangTool::diagnostics() const
{
return Utils::filtered(m_diagnosticModel->diagnostics(), [](const Diagnostic &diagnostic) {
@@ -742,82 +1074,98 @@ void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics)
m_diagnosticFilterModel->invalidateFilter();
}
void ClangTool::updateRunActions()
void ClangTool::updateForCurrentState()
{
if (m_toolBusy) {
QString tooltipText = tr("Clang-Tidy and Clazy are still running.");
m_startAction->setEnabled(false);
m_startAction->setToolTip(tooltipText);
m_startOnCurrentFileAction->setEnabled(false);
m_startOnCurrentFileAction->setToolTip(tooltipText);
m_stopAction->setEnabled(true);
m_loadExported->setEnabled(false);
m_clear->setEnabled(false);
} else {
QString toolTipStart = m_startAction->text();
QString toolTipStartOnCurrentFile = m_startOnCurrentFileAction->text();
Project *project = SessionManager::startupProject();
Target *target = project ? project->activeTarget() : nullptr;
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
bool canRun = target && project->projectLanguages().contains(cxx)
&& ToolChainKitAspect::toolChain(target->kit(), cxx);
if (!canRun)
toolTipStart = toolTipStartOnCurrentFile = tr("This is not a C/C++ project.");
m_startAction->setEnabled(canRun);
m_startAction->setToolTip(toolTipStart);
m_startOnCurrentFileAction->setEnabled(canRun);
m_startOnCurrentFileAction->setToolTip(toolTipStartOnCurrentFile);
m_stopAction->setEnabled(false);
m_loadExported->setEnabled(true);
m_clear->setEnabled(m_diagnosticModel->diagnostics().count());
// Actions
bool canStart = false;
const bool isPreparing = m_state == State::PreparationStarted;
const bool isRunning = m_state == State::AnalyzerRunning;
QString startActionToolTip = m_startAction->text();
QString startOnCurrentToolTip = m_startOnCurrentFileAction->text();
if (!isRunning) {
const CheckResult result = canAnalyze();
canStart = result.kind == CheckResult::ReadyToAnalyze;
if (!canStart) {
startActionToolTip = result.errorText;
startOnCurrentToolTip = result.errorText;
}
}
}
void ClangTool::handleStateUpdate()
{
QTC_ASSERT(m_goBack, return);
QTC_ASSERT(m_goNext, return);
QTC_ASSERT(m_diagnosticModel, return);
QTC_ASSERT(m_diagnosticFilterModel, return);
m_startAction->setEnabled(canStart);
m_startAction->setToolTip(startActionToolTip);
m_startOnCurrentFileAction->setEnabled(canStart);
m_startOnCurrentFileAction->setToolTip(startOnCurrentToolTip);
m_stopAction->setEnabled(isPreparing || isRunning);
const int issuesFound = m_diagnosticModel->diagnostics().count();
const int issuesVisible = m_diagnosticFilterModel->rowCount();
const int issuesVisible = m_diagnosticFilterModel->diagnostics();
m_goBack->setEnabled(issuesVisible > 1);
m_goNext->setEnabled(issuesVisible > 1);
m_clear->setEnabled(issuesFound > 0);
m_clear->setEnabled(!isRunning);
m_expandCollapse->setEnabled(issuesVisible);
m_loadExported->setEnabled(!isRunning);
m_loadExported->setEnabled(!m_running);
// Diagnostic view
m_diagnosticView->setCursor(isRunning ? Qt::BusyCursor : Qt::ArrowCursor);
QString message;
if (m_running) {
if (issuesFound)
message = tr("Running - %n diagnostics", nullptr, issuesFound);
else
message = tr("Running - No diagnostics");
} else {
if (issuesFound)
message = tr("Finished - %n diagnostics", nullptr, issuesFound);
else
message = tr("Finished - No diagnostics");
// Info bar: errors
const bool hasErrorText = !m_infoBarWidget->errorText().isEmpty();
const bool hasErrors = m_runWorker && m_runWorker->filesNotAnalyzed() > 0;
if (hasErrors && !hasErrorText) {
const QString text = makeLink( tr("Failed to analyze %1 files.").arg(m_runWorker->filesNotAnalyzed()));
m_infoBarWidget->setError(InfoBarWidget::Warning, text, [this]() { showOutputPane(); });
}
Debugger::showPermanentStatusMessage(message);
}
// Info bar: info
bool showProgressIcon = false;
QString infoText;
switch (m_state) {
case State::Initial:
infoText = m_infoBarWidget->infoText();
break;
case State::AnalyzerRunning:
showProgressIcon = true;
if (m_runWorker->totalFilesToAnalyze() == 0) {
infoText = tr("Analyzing..."); // Not yet fully started/initialized
} else {
infoText = tr("Analyzing... %1 of %2 files processed.")
.arg(m_runWorker->filesAnalyzed() + m_runWorker->filesNotAnalyzed())
.arg(m_runWorker->totalFilesToAnalyze());
}
break;
case State::PreparationStarted:
showProgressIcon = true;
infoText = m_infoBarWidget->infoText();
break;
case State::PreparationFailed:
break; // OK, we just show an error.
case State::StoppedByUser:
infoText = tr("Analysis stopped by user.");
break;
case State::AnalyzerFinished:
infoText = tr("Finished processing %1 files.").arg(m_runWorker->totalFilesToAnalyze());
break;
case State::ImportFinished:
infoText = tr("Diagnostics imported.");
break;
}
m_infoBarWidget->setInfoText(infoText);
m_infoBarWidget->setInfoIcon(showProgressIcon ? InfoBarWidget::ProgressIcon
: InfoBarWidget::InfoIcon);
void ClangTool::setToolBusy(bool busy)
{
QTC_ASSERT(m_diagnosticView, return);
QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
m_diagnosticView->setCursor(cursor);
m_toolBusy = busy;
// Info bar: diagnostic stats
QString diagText;
if (issuesFound) {
diagText = tr("%1 diagnostics. %2 fixits, %4 selected.")
.arg(issuesVisible)
.arg(m_diagnosticFilterModel->fixitsScheduable())
.arg(m_diagnosticFilterModel->fixitsScheduled());
} else if (m_state != State::AnalyzerRunning
&& m_state != State::Initial
&& m_state != State::PreparationStarted
&& m_state != State::PreparationFailed) {
diagText = tr("No diagnostics.");
}
m_infoBarWidget->setDiagText(diagText);
}
} // namespace Internal