ClangTools: Allow multi-selection in diagnostics view

This enables users to suppress or copy several issues at once.

Fixes: QTCREATORBUG-24396
Change-Id: Ib9019fd6a495b967627bf1ce53dead4d168e99da
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2020-10-01 10:27:17 +02:00
parent 751c0dbc98
commit efce9b04fc
6 changed files with 48 additions and 19 deletions

View File

@@ -538,6 +538,12 @@ void DiagnosticFilterModel::setProject(ProjectExplorer::Project *project)
handleSuppressedDiagnosticsChanged(); handleSuppressedDiagnosticsChanged();
} }
void DiagnosticFilterModel::addSuppressedDiagnostics(const SuppressedDiagnosticsList &diags)
{
m_suppressedDiagnostics << diags;
invalidate();
}
void DiagnosticFilterModel::addSuppressedDiagnostic(const SuppressedDiagnostic &diag) void DiagnosticFilterModel::addSuppressedDiagnostic(const SuppressedDiagnostic &diag)
{ {
QTC_ASSERT(!m_project, return); QTC_ASSERT(!m_project, return);

View File

@@ -157,6 +157,7 @@ public:
DiagnosticFilterModel(QObject *parent = nullptr); DiagnosticFilterModel(QObject *parent = nullptr);
void setProject(ProjectExplorer::Project *project); void setProject(ProjectExplorer::Project *project);
void addSuppressedDiagnostics(const SuppressedDiagnosticsList &diags);
void addSuppressedDiagnostic(const SuppressedDiagnostic &diag); void addSuppressedDiagnostic(const SuppressedDiagnostic &diag);
ProjectExplorer::Project *project() const { return m_project; } ProjectExplorer::Project *project() const { return m_project; }

View File

@@ -44,6 +44,7 @@
#include <QDebug> #include <QDebug>
#include <QHeaderView> #include <QHeaderView>
#include <QPainter> #include <QPainter>
#include <QSet>
using namespace Debugger; using namespace Debugger;
@@ -127,6 +128,7 @@ DiagnosticView::DiagnosticView(QWidget *parent)
, m_delegate(new DiagnosticViewDelegate(m_style, this)) , m_delegate(new DiagnosticViewDelegate(m_style, this))
{ {
header()->hide(); header()->hide();
setSelectionMode(ExtendedSelection);
const QIcon filterIcon = Utils::Icon({{":/utils/images/filtericon.png", const QIcon filterIcon = Utils::Icon({{":/utils/images/filtericon.png",
Utils::Theme::PanelTextColorMid}}, Utils::Theme::PanelTextColorMid}},
@@ -160,7 +162,7 @@ DiagnosticView::DiagnosticView(QWidget *parent)
connect(m_help, &QAction::triggered, connect(m_help, &QAction::triggered,
this, &DiagnosticView::showHelp); this, &DiagnosticView::showHelp);
m_suppressAction = new QAction(tr("Suppress This Diagnostic"), this); m_suppressAction = new QAction(this);
connect(m_suppressAction, &QAction::triggered, connect(m_suppressAction, &QAction::triggered,
this, &DiagnosticView::suppressCurrentDiagnostic); this, &DiagnosticView::suppressCurrentDiagnostic);
@@ -194,27 +196,36 @@ DiagnosticView::~DiagnosticView()
void DiagnosticView::suppressCurrentDiagnostic() void DiagnosticView::suppressCurrentDiagnostic()
{ {
const QModelIndexList indexes = selectionModel()->selectedRows(); const QModelIndexList indexes = selectionModel()->selectedRows();
QTC_ASSERT(indexes.count() == 1, return);
const Diagnostic diag = model()->data(indexes.first(),
ClangToolsDiagnosticModel::DiagnosticRole)
.value<Diagnostic>();
QTC_ASSERT(diag.isValid(), return);
// If the original project was closed, we work directly on the filter model, otherwise // If the original project was closed, we work directly on the filter model, otherwise
// we go via the project settings. // we go via the project settings.
auto * const filterModel = static_cast<DiagnosticFilterModel *>(model()); const auto filterModel = static_cast<DiagnosticFilterModel *>(model());
ProjectExplorer::Project * const project = filterModel->project(); ProjectExplorer::Project * const project = filterModel->project();
if (project) {
SuppressedDiagnosticsList diags;
for (const QModelIndex &index : indexes) {
const Diagnostic diag = model()->data(index, ClangToolsDiagnosticModel::DiagnosticRole)
.value<Diagnostic>();
if (!diag.isValid())
continue;
if (!project) {
diags << diag;
continue;
}
Utils::FilePath filePath = Utils::FilePath::fromString(diag.location.filePath); Utils::FilePath filePath = Utils::FilePath::fromString(diag.location.filePath);
const Utils::FilePath relativeFilePath const Utils::FilePath relativeFilePath
= filePath.relativeChildPath(project->projectDirectory()); = filePath.relativeChildPath(project->projectDirectory());
if (!relativeFilePath.isEmpty()) if (!relativeFilePath.isEmpty())
filePath = relativeFilePath; filePath = relativeFilePath;
const SuppressedDiagnostic supDiag(filePath, diag.description, diag.explainingSteps.count()); const SuppressedDiagnostic supDiag(filePath, diag.description,
ClangToolsProjectSettings::getSettings(project)->addSuppressedDiagnostic(supDiag); diag.explainingSteps.count());
} else { diags << SuppressedDiagnostic(filePath, diag.description, diag.explainingSteps.count());
filterModel->addSuppressedDiagnostic(SuppressedDiagnostic(diag));
} }
if (project)
ClangToolsProjectSettings::getSettings(project)->addSuppressedDiagnostics(diags);
else
filterModel->addSuppressedDiagnostics(diags);
} }
void DiagnosticView::goNext() void DiagnosticView::goNext()
@@ -269,13 +280,16 @@ QList<QAction *> DiagnosticView::customActions() const
{ {
const QModelIndex currentIndex = selectionModel()->currentIndex(); const QModelIndex currentIndex = selectionModel()->currentIndex();
const bool hasMultiSelection = selectionModel()->selectedIndexes().size() > 1;
const bool isDiagnosticItem = currentIndex.parent().isValid(); const bool isDiagnosticItem = currentIndex.parent().isValid();
const QString docUrl const QString docUrl
= model()->data(currentIndex, ClangToolsDiagnosticModel::DocumentationUrlRole).toString(); = model()->data(currentIndex, ClangToolsDiagnosticModel::DocumentationUrlRole).toString();
m_help->setEnabled(isDiagnosticItem && !docUrl.isEmpty()); m_help->setEnabled(isDiagnosticItem && !docUrl.isEmpty() && !hasMultiSelection);
m_filterForCurrentKind->setEnabled(isDiagnosticItem); m_filterForCurrentKind->setEnabled(isDiagnosticItem && !hasMultiSelection);
m_filterOutCurrentKind->setEnabled(isDiagnosticItem); m_filterOutCurrentKind->setEnabled(isDiagnosticItem && !hasMultiSelection);
m_suppressAction->setEnabled(isDiagnosticItem); m_suppressAction->setEnabled(isDiagnosticItem || hasMultiSelection);
m_suppressAction->setText(hasMultiSelection ? tr("Suppress Selected Diagnostics")
: tr("Suppress This Diagnostic"));
return { return {
m_help, m_help,

View File

@@ -93,6 +93,12 @@ void ClangToolsProjectSettings::setSelectedFiles(const QSet<Utils::FilePath> &va
emit changed(); emit changed();
} }
void ClangToolsProjectSettings::addSuppressedDiagnostics(const SuppressedDiagnosticsList &diags)
{
m_suppressedDiagnostics << diags;
emit suppressedDiagnosticsChanged();
}
void ClangToolsProjectSettings::addSuppressedDiagnostic(const SuppressedDiagnostic &diag) void ClangToolsProjectSettings::addSuppressedDiagnostic(const SuppressedDiagnostic &diag)
{ {
QTC_ASSERT(!m_suppressedDiagnostics.contains(diag), return); QTC_ASSERT(!m_suppressedDiagnostics.contains(diag), return);

View File

@@ -82,6 +82,7 @@ public:
void setSelectedFiles(const QSet<Utils::FilePath> &value); void setSelectedFiles(const QSet<Utils::FilePath> &value);
SuppressedDiagnosticsList suppressedDiagnostics() const { return m_suppressedDiagnostics; } SuppressedDiagnosticsList suppressedDiagnostics() const { return m_suppressedDiagnostics; }
void addSuppressedDiagnostics(const SuppressedDiagnosticsList &diags);
void addSuppressedDiagnostic(const SuppressedDiagnostic &diag); void addSuppressedDiagnostic(const SuppressedDiagnostic &diag);
void removeSuppressedDiagnostic(const SuppressedDiagnostic &diag); void removeSuppressedDiagnostic(const SuppressedDiagnostic &diag);
void removeAllSuppressedDiagnostics(); void removeAllSuppressedDiagnostics();

View File

@@ -56,9 +56,10 @@ DetailedErrorView::DetailedErrorView(QWidget *parent) :
m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(m_copyAction, &QAction::triggered, [this] { connect(m_copyAction, &QAction::triggered, [this] {
const QModelIndexList selectedRows = selectionModel()->selectedRows(); const QModelIndexList selectedRows = selectionModel()->selectedRows();
QTC_ASSERT(selectedRows.count() == 1, return); QStringList data;
QApplication::clipboard()->setText(model()->data(selectedRows.first(), for (const QModelIndex &index : selectedRows)
FullTextRole).toString()); data << model()->data(index, FullTextRole).toString();
QApplication::clipboard()->setText(data.join('\n'));
}); });
connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) { connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) {
if (index.column() == LocationColumn) { if (index.column() == LocationColumn) {