1 /*
2     SPDX-FileCopyrightText: 2018 Friedrich W. H. Kossebau <kossebau@kde.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "checkselection.h"
8 
9 // plugin
10 #include "checklistfilterproxysearchline.h"
11 #include "checklistitemproxystyle.h"
12 #include "checklistmodel.h"
13 #include <checkset.h>
14 #include <debug.h>
15 // KF
16 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
17 #include <KRecursiveFilterProxyModel>
18 #endif
19 // Qt
20 #include <QEvent>
21 #include <QVBoxLayout>
22 #include <QTreeView>
23 #include <QHeaderView>
24 #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
25 #include <QSortFilterProxyModel>
26 #endif
27 
28 namespace ClangTidy
29 {
30 
CheckSelection(QWidget * parent)31 CheckSelection::CheckSelection(QWidget* parent)
32     : QWidget(parent)
33     , m_checkListModel(new CheckListModel(this))
34 {
35     auto* layout = new QVBoxLayout;
36     layout->setContentsMargins(0, 0, 0, 0);
37 
38     auto* checkFilterEdit = new CheckListFilterProxySearchLine(this);
39     layout->addWidget(checkFilterEdit);
40 
41     m_checkListView = new QTreeView(this);
42     m_checkListView->setAllColumnsShowFocus(true);
43     m_checkListView->setRootIsDecorated(true);
44     m_checkListView->setHeaderHidden(true);
45     m_checkListView->setUniformRowHeights(true);
46     m_proxyStyle = new CheckListItemProxyStyle;
47     m_proxyStyle->setParent(this);
48     m_checkListView->setStyle(m_proxyStyle);
49     layout->addWidget(m_checkListView);
50 
51     setLayout(layout);
52 
53 #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
54     m_checksFilterProxyModel = new QSortFilterProxyModel(this);
55     m_checksFilterProxyModel->setRecursiveFilteringEnabled(true);
56 #else
57     m_checksFilterProxyModel = new KRecursiveFilterProxyModel(this);
58 #endif
59     checkFilterEdit->setFilterProxyModel(m_checksFilterProxyModel);
60     m_checksFilterProxyModel->setSourceModel(m_checkListModel);
61     m_checksFilterProxyModel->setFilterKeyColumn(CheckListModel::NameColumnId);
62     m_checksFilterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
63 
64     m_checkListView->setModel(m_checksFilterProxyModel);
65     auto* header = m_checkListView->header();
66     header->setStretchLastSection(false);
67     header->setSectionResizeMode(CheckListModel::NameColumnId, QHeaderView::Stretch);
68     header->setSectionResizeMode(CheckListModel::CountColumnId, QHeaderView::ResizeToContents);
69 
70     connect(m_checkListModel, &CheckListModel::enabledChecksChanged,
71             this, &CheckSelection::onEnabledChecksChanged);
72 }
73 
74 CheckSelection::~CheckSelection() = default;
75 
setEditable(bool editable)76 void CheckSelection::setEditable(bool editable)
77 {
78     m_checkListModel->setEditable(editable);
79 }
80 
setCheckSet(const CheckSet * checkSet)81 void CheckSelection::setCheckSet(const CheckSet* checkSet)
82 {
83     m_checkListModel->setCheckSet(checkSet);
84     expandSubGroupsWithExplicitlyEnabledStates();
85 }
86 
expandSubGroupsWithExplicitlyEnabledStates()87 void CheckSelection::expandSubGroupsWithExplicitlyEnabledStates()
88 {
89     const QModelIndex allChecksIndex = m_checksFilterProxyModel->index(0, 0, QModelIndex());
90     expandSubGroupsWithExplicitlyEnabledStates(allChecksIndex);
91 }
92 
expandSubGroupsWithExplicitlyEnabledStates(const QModelIndex & groupIndex)93 void CheckSelection::expandSubGroupsWithExplicitlyEnabledStates(const QModelIndex& groupIndex)
94 {
95     if (groupIndex.data(CheckListModel::HasExplicitEnabledStateRole).toBool()) {
96         m_checkListView->setExpanded(groupIndex, true);
97         const int rowCount = m_checksFilterProxyModel->rowCount(groupIndex);
98         for (int c = 0; c < rowCount; ++c) {
99             const auto childIndex = m_checksFilterProxyModel->index(c, 0, groupIndex);
100             if (m_checksFilterProxyModel->hasChildren(childIndex)) {
101                 expandSubGroupsWithExplicitlyEnabledStates(childIndex);
102             }
103         }
104     }
105 }
106 
setChecks(const QString & checks)107 void CheckSelection::setChecks(const QString& checks)
108 {
109 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
110     m_checkListModel->setEnabledChecks(checks.split(QLatin1Char(','), Qt::SkipEmptyParts));
111 #else
112     m_checkListModel->setEnabledChecks(checks.split(QLatin1Char(','), QString::SkipEmptyParts));
113 #endif
114     expandSubGroupsWithExplicitlyEnabledStates();
115 }
116 
checks() const117 QString CheckSelection::checks() const
118 {
119     return m_checkListModel->enabledChecks().join(QLatin1Char(','));
120 }
121 
122 
event(QEvent * event)123 bool CheckSelection::event(QEvent* event)
124 {
125     if (event->type() == QEvent::StyleChange) {
126         // no recursion protection needed as the style is set on the subchild only
127         m_checkListView->setStyle(nullptr);
128         delete m_proxyStyle;
129         m_proxyStyle = new CheckListItemProxyStyle;
130         m_proxyStyle->setParent(this);
131         m_checkListView->setStyle(m_proxyStyle);
132     }
133 
134     return QWidget::event(event);
135 }
136 
onEnabledChecksChanged()137 void CheckSelection::onEnabledChecksChanged()
138 {
139     emit checksChanged(checks());
140 }
141 
142 }
143