aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cpptools/clangdiagnosticconfigswidget.cpp')
-rw-r--r--src/plugins/cpptools/clangdiagnosticconfigswidget.cpp604
1 files changed, 499 insertions, 105 deletions
diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp
index fb683a07aef..fc157352eec 100644
--- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp
+++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp
@@ -27,6 +27,7 @@
#include "cppcodemodelsettings.h"
#include "cpptools_clangtidychecks.h"
+#include "cpptools_clazychecks.h"
#include "cpptoolsconstants.h"
#include "cpptoolsreuse.h"
#include "ui_clangdiagnosticconfigswidget.h"
@@ -45,10 +46,14 @@
#include <QDialogButtonBox>
#include <QInputDialog>
#include <QPushButton>
+#include <QSortFilterProxyModel>
+#include <QStringListModel>
#include <QUuid>
namespace CppTools {
+using namespace Constants;
+
static constexpr const char CLANG_STATIC_ANALYZER_URL[]
= "https://clang-analyzer.llvm.org/available_checks.html";
@@ -75,13 +80,99 @@ static bool needsLink(ProjectExplorer::Tree *node) {
return !node->isDir && !node->fullPath.toString().startsWith("clang-analyzer-");
}
-class TidyChecksTreeModel final : public ProjectExplorer::SelectableFilesModel
+static void selectAll(QAbstractItemView *view)
+{
+ view->setSelectionMode(QAbstractItemView::MultiSelection);
+ view->selectAll();
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+}
+
+class BaseChecksTreeModel : public ProjectExplorer::SelectableFilesModel
{
Q_OBJECT
public:
- TidyChecksTreeModel()
+ enum Roles { LinkRole = Qt::UserRole + 1 };
+ enum Columns { NameColumn, LinkColumn };
+
+ BaseChecksTreeModel()
: ProjectExplorer::SelectableFilesModel(nullptr)
+ {}
+
+ int columnCount(const QModelIndex &) const override { return 2; }
+
+ QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const override
+ {
+ if (fullIndex.column() == LinkColumn) {
+ switch (role) {
+ case Qt::DisplayRole:
+ return tr("Web Page");
+ case Qt::FontRole: {
+ QFont font = QApplication::font();
+ font.setUnderline(true);
+ return font;
+ }
+ case Qt::ForegroundRole:
+ return QApplication::palette().link().color();
+ }
+ return QVariant();
+ }
+ return QVariant();
+ }
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
+ {
+ if (role == Qt::CheckStateRole && !m_enabled)
+ return false;
+ ProjectExplorer::SelectableFilesModel::setData(index, value, role);
+ return true;
+ }
+
+ void setEnabled(bool enabled)
+ {
+ m_enabled = enabled;
+ }
+
+ // TODO: Remove/replace this method after base class refactoring is done.
+ void traverse(const QModelIndex &index,
+ const std::function<bool(const QModelIndex &)> &visit) const
+ {
+ if (!index.isValid())
+ return;
+
+ if (!visit(index))
+ return;
+
+ if (!hasChildren(index))
+ return;
+
+ const int rows = rowCount(index);
+ const int cols = columnCount(index);
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j)
+ traverse(this->index(i, j, index), visit);
+ }
+ }
+
+protected:
+ bool m_enabled = true;
+};
+
+static void openUrl(QAbstractItemModel *model, const QModelIndex &index)
+{
+ const QString link = model->data(index, BaseChecksTreeModel::LinkRole).toString();
+ if (link.isEmpty())
+ return;
+
+ QDesktopServices::openUrl(QUrl(link));
+};
+
+class TidyChecksTreeModel final : public BaseChecksTreeModel
+{
+ Q_OBJECT
+
+public:
+ TidyChecksTreeModel()
{
buildTree(nullptr, m_root, Constants::CLANG_TIDY_CHECKS_ROOT);
}
@@ -119,11 +210,7 @@ public:
}
}
- int columnCount(const QModelIndex &/*parent*/) const override
- {
- return 2;
- }
-
+private:
QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const final
{
if (!fullIndex.isValid() || role == Qt::DecorationRole)
@@ -134,25 +221,16 @@ public:
if (fullIndex.column() == 1) {
if (!needsLink(node))
return QVariant();
- switch (role) {
- case Qt::DisplayRole:
- return tr("Web Page");
- case Qt::FontRole: {
- QFont font = QApplication::font();
- font.setUnderline(true);
- return font;
- }
- case Qt::ForegroundRole:
- return QApplication::palette().link().color();
- case Qt::UserRole: {
+
+ if (role == LinkRole) {
// 'clang-analyzer-' group
if (node->isDir)
return QString::fromUtf8(CLANG_STATIC_ANALYZER_URL);
return QString::fromUtf8(Constants::TIDY_DOCUMENTATION_URL_TEMPLATE)
.arg(node->fullPath.toString());
}
- }
- return QVariant();
+
+ return BaseChecksTreeModel::data(fullIndex, role);
}
if (role == Qt::DisplayRole)
@@ -161,39 +239,218 @@ public:
return ProjectExplorer::SelectableFilesModel::data(index, role);
}
- void setEnabled(bool enabled)
+ QModelIndex indexForCheck(const QString &check) const {
+ if (check == "*")
+ return index(0, 0, QModelIndex());
+
+ QModelIndex result;
+ traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
+ using ProjectExplorer::Tree;
+ if (result.isValid())
+ return false;
+
+ auto *node = static_cast<Tree *>(index.internalPointer());
+ const QString nodeName = node->fullPath.toString();
+ if ((check.endsWith("*") && nodeName.startsWith(check.left(check.length() - 1)))
+ || (!node->isDir && nodeName == check)) {
+ result = index;
+ return false;
+ }
+
+ return check.startsWith(nodeName);
+ });
+ return result;
+ }
+
+ static void collectChecks(const ProjectExplorer::Tree *root, QString &checks)
{
- m_enabled = enabled;
+ if (root->checked == Qt::Unchecked)
+ return;
+ if (root->checked == Qt::Checked) {
+ checks += "," + root->fullPath.toString();
+ if (root->isDir)
+ checks += "*";
+ return;
+ }
+ for (const ProjectExplorer::Tree *t : root->childDirectories)
+ collectChecks(t, checks);
}
+};
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
+class ClazyChecksTree : public ProjectExplorer::Tree
+{
+public:
+ enum Kind { TopLevelNode, LevelNode, CheckNode };
+ ClazyChecksTree(const QString &name, Kind kind)
{
- if (role == Qt::CheckStateRole && !m_enabled)
- return false;
- return ProjectExplorer::SelectableFilesModel::setData(index, value, role);
+ this->name = name;
+ this->kind = kind;
+ this->isDir = kind == TopLevelNode || kind == LevelNode;
}
-private:
+ static ClazyChecksTree *fromIndex(const QModelIndex &index)
+ {
+ return static_cast<ClazyChecksTree *>(index.internalPointer());
+ }
- // TODO: Remove/replace this method after base class refactoring is done.
- void traverse(const QModelIndex &index,
- const std::function<bool(const QModelIndex &)> &visit) const
+public:
+ ClazyCheckInfo checkInfo;
+ Kind kind = TopLevelNode;
+};
+
+class ClazyChecksTreeModel final : public BaseChecksTreeModel
+{
+ Q_OBJECT
+
+public:
+ ClazyChecksTreeModel() { buildTree(); }
+
+ QStringList enabledChecks() const
{
- if (!index.isValid())
- return;
+ QStringList checks;
+ collectChecks(m_root, checks);
+ return checks;
+ }
- if (!visit(index))
- return;
+ void enableChecks(const QStringList &checks)
+ {
+ // Unselect all
+ m_root->checked = Qt::Unchecked;
+ propagateDown(index(0, 0, QModelIndex()));
- if (!hasChildren(index))
+ // <= Qt Creator 4.8 settings provide specific levels: {"level0"}
+ if (checks.size() == 1 && checks.first().startsWith("level")) {
+ bool ok = false;
+ const int level = checks.first().mid(5).toInt(&ok);
+ QTC_ASSERT(ok, return);
+ enableChecksByLevel(level);
return;
+ }
- const int rows = rowCount(index);
- const int cols = columnCount(index);
- for (int i = 0; i < rows; ++i) {
- for (int j = 0; j < cols; ++j)
- traverse(this->index(i, j, index), visit);
+ // >= Qt Creator 4.9 settings provide specific checks: {c1, c2, ...}
+ for (const QString &check : checks) {
+ const QModelIndex index = indexForCheck(check);
+ if (!index.isValid())
+ continue;
+ ClazyChecksTree::fromIndex(index)->checked = Qt::Checked;
+ propagateUp(index);
+ propagateDown(index);
+ }
+ }
+
+ bool hasEnabledButNotVisibleChecks(
+ const std::function<bool(const QModelIndex &index)> &isHidden) const
+ {
+ bool enabled = false;
+ traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
+ if (enabled)
+ return false;
+ const auto *node = ClazyChecksTree::fromIndex(index);
+ if (node->kind == ClazyChecksTree::CheckNode && index.column() == NameColumn) {
+ const bool isChecked = data(index, Qt::CheckStateRole).toInt() == Qt::Checked;
+ const bool isVisible = isHidden(index);
+ if (isChecked && isVisible) {
+ enabled = true;
+ return false;
+ }
+ }
+ return true;
+ });
+
+ return enabled;
+ }
+
+ bool enableLowerLevels() const { return m_enableLowerLevels; }
+ void setEnableLowerLevels(bool enable) { m_enableLowerLevels = enable; }
+
+ QSet<QString> topics() const { return m_topics; }
+
+private:
+ void buildTree()
+ {
+ // Top level node
+ m_root = new ClazyChecksTree("*", ClazyChecksTree::TopLevelNode);
+
+ for (const ClazyCheckInfo &check : CLAZY_CHECKS) {
+ // Level node
+ ClazyChecksTree *&levelNode = m_levelNodes[check.level];
+ if (!levelNode) {
+ levelNode = new ClazyChecksTree(levelDescription(check.level), ClazyChecksTree::LevelNode);
+ levelNode->parent = m_root;
+ levelNode->checkInfo.level = check.level; // Pass on the level for sorting
+ m_root->childDirectories << levelNode;
+ }
+
+ // Check node
+ auto checkNode = new ClazyChecksTree(check.name, ClazyChecksTree::CheckNode);
+ checkNode->parent = levelNode;
+ checkNode->checkInfo = check;
+
+ levelNode->childDirectories.append(checkNode);
+
+ m_topics.unite(check.topics.toSet());
+ }
+ }
+
+ QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const override final
+ {
+ if (!fullIndex.isValid() || role == Qt::DecorationRole)
+ return QVariant();
+ const QModelIndex index = this->index(fullIndex.row(), 0, fullIndex.parent());
+ const auto *node = ClazyChecksTree::fromIndex(index);
+
+ if (fullIndex.column() == LinkColumn) {
+ if (role == LinkRole) {
+ if (node->checkInfo.name.isEmpty())
+ return QVariant();
+ return QString::fromUtf8(Constants::CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(node->name);
+ }
+ if (role == Qt::DisplayRole && node->kind != ClazyChecksTree::CheckNode)
+ return QVariant();
+
+ return BaseChecksTreeModel::data(fullIndex, role);
}
+
+ if (role == Qt::DisplayRole)
+ return node->name;
+
+ return ProjectExplorer::SelectableFilesModel::data(index, role);
+ }
+
+ static QString levelDescription(int level)
+ {
+ switch (level) {
+ case -1:
+ return tr("Manual Level: Very few false positives");
+ case 0:
+ return tr("Level 0: No false positives");
+ case 1:
+ return tr("Level 1: Very few false positives");
+ case 2:
+ return tr("Level 2: More false positives");
+ case 3:
+ return tr("Level 3: Experimental checks");
+ default:
+ QTC_CHECK(false && "No clazy level description");
+ return tr("Level %1").arg(QString::number(level));
+ }
+ }
+
+ void enableChecksByLevel(int level)
+ {
+ if (level < 0)
+ return;
+
+ ClazyChecksTree *node = m_levelNodes.value(level);
+ QTC_ASSERT(node, return);
+ const QModelIndex index = indexForTree(node);
+ QTC_ASSERT(index.isValid(), return);
+
+ node->checked = Qt::Checked;
+ propagateUp(index);
+ propagateDown(index);
+
+ enableChecksByLevel(--level);
}
QModelIndex indexForCheck(const QString &check) const {
@@ -202,38 +459,137 @@ private:
QModelIndex result;
traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
- using ProjectExplorer::Tree;
if (result.isValid())
return false;
-
- auto *node = static_cast<Tree *>(index.internalPointer());
- const QString nodeName = node->fullPath.toString();
- if ((check.endsWith("*") && nodeName.startsWith(check.left(check.length() - 1)))
- || (!node->isDir && nodeName == check)) {
+ const auto *node = ClazyChecksTree::fromIndex(index);
+ if (node->kind == ClazyChecksTree::CheckNode && node->checkInfo.name == check) {
result = index;
return false;
}
+ return true;
+ });
+ return result;
+ }
- return check.startsWith(nodeName);
+ QModelIndex indexForTree(const ClazyChecksTree *tree) const {
+ if (!tree)
+ return QModelIndex();
+
+ QModelIndex result;
+ traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
+ if (result.isValid())
+ return false;
+ if (index.internalPointer() == tree) {
+ result = index;
+ return false;
+ }
+ return true;
});
return result;
}
- static void collectChecks(const ProjectExplorer::Tree *root, QString &checks)
+ static void collectChecks(const ProjectExplorer::Tree *root, QStringList &checks)
{
if (root->checked == Qt::Unchecked)
return;
- if (root->checked == Qt::Checked) {
- checks += "," + root->fullPath.toString();
- if (root->isDir)
- checks += "*";
+ if (root->checked == Qt::Checked && !root->isDir) {
+ checks.append(root->name);
return;
}
for (const ProjectExplorer::Tree *t : root->childDirectories)
collectChecks(t, checks);
}
- bool m_enabled = true;
+ static QStringList toStringList(const QVariantList &variantList)
+ {
+ QStringList list;
+ for (auto &item : variantList)
+ list.append(item.toString());
+ return list;
+ }
+
+private:
+ QHash<int, ClazyChecksTree *> m_levelNodes;
+ QSet<QString> m_topics;
+ bool m_enableLowerLevels = true;
+};
+
+class ClazyChecksSortFilterModel : public QSortFilterProxyModel
+{
+public:
+ ClazyChecksSortFilterModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ {}
+
+ void setTopics(const QStringList &value)
+ {
+ m_topics = value;
+ invalidateFilter();
+ }
+
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
+ {
+ const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+ if (!index.isValid())
+ return false;
+
+ const auto *node = ClazyChecksTree::fromIndex(index);
+ if (node->kind == ClazyChecksTree::CheckNode) {
+ const QStringList topics = node->checkInfo.topics;
+ return Utils::anyOf(m_topics, [this, topics](const QString &topic) {
+ return topics.contains(topic);
+ });
+ }
+
+ return true;
+ }
+
+private:
+ // Note that sort order of levels is important for "enableLowerLevels" mode, see setData().
+ bool lessThan(const QModelIndex &l, const QModelIndex &r) const override
+ {
+ const int leftLevel = adaptLevel(ClazyChecksTree::fromIndex(l)->checkInfo.level);
+ const int rightLevel = adaptLevel(ClazyChecksTree::fromIndex(r)->checkInfo.level);
+
+ if (leftLevel == rightLevel)
+ return sourceModel()->data(l).toString() < sourceModel()->data(r).toString();
+ return leftLevel < rightLevel;
+ }
+
+ static bool adaptLevel(int level)
+ {
+ if (level == -1) // "Manual Level"
+ return 1000;
+ return level;
+ }
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
+ {
+ if (!index.isValid())
+ return false;
+
+ if (role == Qt::CheckStateRole
+ && static_cast<ClazyChecksTreeModel *>(sourceModel())->enableLowerLevels()
+ && QSortFilterProxyModel::setData(index, value, role)) {
+ const auto *node = ClazyChecksTree::fromIndex(mapToSource(index));
+ if (node->kind == ClazyChecksTree::LevelNode && node->checkInfo.level >= 0) {
+ // Rely on the sort order to find the lower level index/node
+ const auto previousIndex = this->index(index.row() - 1,
+ index.column(),
+ index.parent());
+ if (previousIndex.isValid()
+ && ClazyChecksTree::fromIndex(mapToSource(previousIndex))->checkInfo.level
+ >= 0) {
+ setData(previousIndex, value, role);
+ }
+ }
+ }
+
+ return QSortFilterProxyModel::setData(index, value, role);
+ }
+
+private:
+ QStringList m_topics;
};
ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &configToSelect,
@@ -241,6 +597,7 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
: QWidget(parent)
, m_ui(new Ui::ClangDiagnosticConfigsWidget)
, m_diagnosticConfigsModel(codeModelSettings()->clangCustomDiagnosticConfigs())
+ , m_clazyTreeModel(new ClazyChecksTreeModel())
, m_tidyTreeModel(new TidyChecksTreeModel())
{
m_ui->setupUi(this);
@@ -256,14 +613,12 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked);
connectDiagnosticOptionsChanged();
- connect(m_tidyChecks->checksPrefixesTree, &QTreeView::clicked,
- [this](const QModelIndex &index) {
- const QString link = m_tidyTreeModel->data(index, Qt::UserRole).toString();
- if (link.isEmpty())
- return;
-
- QDesktopServices::openUrl(QUrl(link));
- });
+ connect(m_tidyChecks->checksPrefixesTree,
+ &QTreeView::clicked,
+ [model = m_tidyTreeModel.get()](const QModelIndex &index) { openUrl(model, index); });
+ connect(m_clazyChecks->checksView,
+ &QTreeView::clicked,
+ [model = m_clazySortFilterProxyModel](const QModelIndex &index) { openUrl(model, index); });
syncWidgetsToModel(configToSelect);
}
@@ -344,25 +699,12 @@ void ClangDiagnosticConfigsWidget::onClangTidyTreeChanged()
updateConfig(config);
}
-void ClangDiagnosticConfigsWidget::onClazyRadioButtonChanged(bool checked)
+void ClangDiagnosticConfigsWidget::onClazyTreeChanged()
{
- if (!checked)
- return;
-
- QString checks;
- if (m_clazyChecks->clazyRadioDisabled->isChecked())
- checks = QString();
- else if (m_clazyChecks->clazyRadioLevel0->isChecked())
- checks = "level0";
- else if (m_clazyChecks->clazyRadioLevel1->isChecked())
- checks = "level1";
- else if (m_clazyChecks->clazyRadioLevel2->isChecked())
- checks = "level2";
- else if (m_clazyChecks->clazyRadioLevel3->isChecked())
- checks = "level3";
+ syncClazyChecksGroupBox();
ClangDiagnosticConfig config = selectedConfig();
- config.setClazyChecks(checks);
+ config.setClazyChecks(m_clazyTreeModel->enabledChecks().join(","));
updateConfig(config);
}
@@ -518,22 +860,35 @@ void ClangDiagnosticConfigsWidget::syncTidyChecksToTree(const ClangDiagnosticCon
void ClangDiagnosticConfigsWidget::syncClazyWidgets(const ClangDiagnosticConfig &config)
{
+ disconnectClazyItemChanged();
+
const QString clazyChecks = config.clazyChecks();
- QRadioButton *button = m_clazyChecks->clazyRadioDisabled;
- if (clazyChecks.isEmpty())
- button = m_clazyChecks->clazyRadioDisabled;
- else if (clazyChecks == "level0")
- button = m_clazyChecks->clazyRadioLevel0;
- else if (clazyChecks == "level1")
- button = m_clazyChecks->clazyRadioLevel1;
- else if (clazyChecks == "level2")
- button = m_clazyChecks->clazyRadioLevel2;
- else if (clazyChecks == "level3")
- button = m_clazyChecks->clazyRadioLevel3;
+ m_clazyTreeModel->enableChecks(clazyChecks.split(',', QString::SkipEmptyParts));
+
+ syncClazyChecksGroupBox();
- button->setChecked(true);
- m_clazyChecksWidget->setEnabled(!config.isReadOnly());
+ const bool enabled = !config.isReadOnly();
+ m_clazyChecks->topicsResetButton->setEnabled(enabled);
+ m_clazyChecks->enableLowerLevelsCheckBox->setEnabled(enabled);
+ selectAll(m_clazyChecks->topicsView);
+ m_clazyChecks->topicsView->setEnabled(enabled);
+ m_clazyTreeModel->setEnabled(enabled);
+
+ connectClazyItemChanged();
+}
+
+void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox()
+{
+ const auto isHidden = [this](const QModelIndex &index) {
+ return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent());
+ };
+ const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden);
+ const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)")
+ : tr("Checks (%1 enabled)");
+
+ const QStringList checks = m_clazyTreeModel->enabledChecks();
+ m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count()));
}
void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config)
@@ -599,12 +954,16 @@ void ClangDiagnosticConfigsWidget::disconnectClangTidyItemChanged()
this, &ClangDiagnosticConfigsWidget::onClangTidyTreeChanged);
}
-void ClangDiagnosticConfigsWidget::connectClazyRadioButtonClicked(QRadioButton *button)
+void ClangDiagnosticConfigsWidget::connectClazyItemChanged()
{
- connect(button,
- &QRadioButton::clicked,
- this,
- &ClangDiagnosticConfigsWidget::onClazyRadioButtonChanged);
+ connect(m_clazyTreeModel.get(), &ClazyChecksTreeModel::dataChanged,
+ this, &ClangDiagnosticConfigsWidget::onClazyTreeChanged);
+}
+
+void ClangDiagnosticConfigsWidget::disconnectClazyItemChanged()
+{
+ disconnect(m_clazyTreeModel.get(), &ClazyChecksTreeModel::dataChanged,
+ this, &ClangDiagnosticConfigsWidget::onClazyTreeChanged);
}
void ClangDiagnosticConfigsWidget::connectConfigChooserCurrentIndex()
@@ -644,6 +1003,15 @@ ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const
});
}
+static void setupTreeView(QTreeView *view, QAbstractItemModel *model, int expandToDepth = 0)
+{
+ view->setModel(model);
+ view->expandToDepth(expandToDepth);
+ view->header()->setStretchLastSection(false);
+ view->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+ view->setHeaderHidden(true);
+}
+
void ClangDiagnosticConfigsWidget::setupTabs()
{
m_clangBaseChecks.reset(new CppTools::Ui::ClangBaseChecks);
@@ -653,20 +1021,45 @@ void ClangDiagnosticConfigsWidget::setupTabs()
m_clazyChecks.reset(new CppTools::Ui::ClazyChecks);
m_clazyChecksWidget = new QWidget();
m_clazyChecks->setupUi(m_clazyChecksWidget);
-
- connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioDisabled);
- connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel0);
- connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel1);
- connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel2);
- connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel3);
+ m_clazySortFilterProxyModel = new ClazyChecksSortFilterModel(this);
+ m_clazySortFilterProxyModel->setSourceModel(m_clazyTreeModel.get());
+ setupTreeView(m_clazyChecks->checksView, m_clazySortFilterProxyModel, 2);
+ m_clazyChecks->checksView->setSortingEnabled(true);
+ m_clazyChecks->checksView->sortByColumn(0, Qt::AscendingOrder);
+ auto topicsModel = new QStringListModel(m_clazyTreeModel->topics().toList(), this);
+ topicsModel->sort(0);
+ m_clazyChecks->topicsView->setModel(topicsModel);
+ connect(m_clazyChecks->topicsResetButton, &QPushButton::clicked, [this](){
+ selectAll(m_clazyChecks->topicsView);
+ });
+ connect(m_clazyChecks->topicsView->selectionModel(),
+ &QItemSelectionModel::selectionChanged,
+ [this, topicsModel](const QItemSelection &, const QItemSelection &) {
+ const auto indexes = m_clazyChecks->topicsView->selectionModel()->selectedIndexes();
+ const QStringList topics
+ = Utils::transform(indexes, [topicsModel](const QModelIndex &index) {
+ return topicsModel->data(index).toString();
+ });
+ m_clazySortFilterProxyModel->setTopics(topics);
+ this->syncClazyChecksGroupBox();
+ });
+
+ selectAll(m_clazyChecks->topicsView);
+ connect(m_clazyChecks->enableLowerLevelsCheckBox, &QCheckBox::stateChanged, [this](int) {
+ const bool enable = m_clazyChecks->enableLowerLevelsCheckBox->isChecked();
+ m_clazyTreeModel->setEnableLowerLevels(enable);
+ codeModelSettings()->setEnableLowerClazyLevels(
+ m_clazyChecks->enableLowerLevelsCheckBox->isChecked());
+ });
+ const Qt::CheckState checkEnableLowerClazyLevels
+ = codeModelSettings()->enableLowerClazyLevels() ? Qt::Checked : Qt::Unchecked;
+ m_clazyChecks->enableLowerLevelsCheckBox->setCheckState(checkEnableLowerClazyLevels);
m_tidyChecks.reset(new CppTools::Ui::TidyChecks);
m_tidyChecksWidget = new QWidget();
m_tidyChecks->setupUi(m_tidyChecksWidget);
- m_tidyChecks->checksPrefixesTree->setModel(m_tidyTreeModel.get());
- m_tidyChecks->checksPrefixesTree->expandToDepth(0);
- m_tidyChecks->checksPrefixesTree->header()->setStretchLastSection(false);
- m_tidyChecks->checksPrefixesTree->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+ setupTreeView(m_tidyChecks->checksPrefixesTree, m_tidyTreeModel.get());
+
connect(m_tidyChecks->plainTextEditButton, &QPushButton::clicked, this, [this]() {
const bool readOnly = selectedConfig().isReadOnly();
@@ -702,6 +1095,7 @@ void ClangDiagnosticConfigsWidget::setupTabs()
});
connectClangTidyItemChanged();
+ connectClazyItemChanged();
m_ui->tabWidget->addTab(m_clangBaseChecksWidget, tr("Clang"));
m_ui->tabWidget->addTab(m_tidyChecksWidget, tr("Clang-Tidy"));