Changeset View
Changeset View
Standalone View
Standalone View
plugins/clazy/config/checks_widget.cpp
- This file was added.
1 | /* This file is part of KDevelop | ||||
---|---|---|---|---|---|
2 | | ||||
3 | Copyright 2018 Anton Anikin <anton@anikin.xyz> | ||||
4 | | ||||
5 | This program is free software; you can redistribute it and/or | ||||
6 | modify it under the terms of the GNU General Public | ||||
7 | License as published by the Free Software Foundation; either | ||||
8 | version 2 of the License, or (at your option) any later version. | ||||
9 | | ||||
10 | This program is distributed in the hope that it will be useful, | ||||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
13 | General Public License for more details. | ||||
14 | | ||||
15 | You should have received a copy of the GNU General Public License | ||||
16 | along with this program; see the file COPYING. If not, write to | ||||
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
18 | Boston, MA 02110-1301, USA. | ||||
19 | */ | ||||
20 | | ||||
21 | #include "checks_widget.h" | ||||
22 | | ||||
23 | #include "checks_db.h" | ||||
24 | #include "debug.h" | ||||
25 | #include "job_parameters.h" | ||||
26 | | ||||
27 | #include <QDesktopServices> | ||||
28 | #include <QHeaderView> | ||||
29 | #include <QLabel> | ||||
30 | #include <QTreeWidget> | ||||
31 | #include <QVBoxLayout> | ||||
32 | | ||||
33 | namespace Clazy | ||||
34 | { | ||||
35 | | ||||
36 | enum DataRole { | ||||
37 | CheckNameRole = Qt::UserRole + 1 | ||||
38 | }; | ||||
39 | | ||||
40 | ChecksWidget::ChecksWidget(QSharedPointer<const ChecksDB> db, QWidget* parent) | ||||
41 | : QWidget(parent) | ||||
42 | { | ||||
43 | auto mainLayout = new QVBoxLayout(this); | ||||
44 | | ||||
45 | m_treeWidget = new QTreeWidget; | ||||
46 | m_treeWidget->setColumnCount(2); | ||||
47 | m_treeWidget->header()->setStretchLastSection(false); | ||||
48 | m_treeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch); | ||||
49 | m_treeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); | ||||
50 | m_treeWidget->header()->hide(); | ||||
51 | mainLayout->addWidget(m_treeWidget); | ||||
52 | | ||||
53 | auto linkActivated = [](const QString & link) { | ||||
54 | QDesktopServices::openUrl(QUrl(link)); | ||||
55 | }; | ||||
56 | | ||||
57 | for (auto level : db->levels()) { | ||||
58 | auto levelItem = new QTreeWidgetItem(m_treeWidget, { level->displayName }); | ||||
59 | levelItem->setData(0, CheckNameRole, level->name); | ||||
60 | levelItem->setToolTip(0, level->description); | ||||
61 | levelItem->setCheckState(0, Qt::Unchecked); | ||||
62 | | ||||
63 | m_items[level->name] = levelItem; | ||||
64 | | ||||
65 | for (auto check : qAsConst(level->checks)) { | ||||
66 | auto checkItem = new QTreeWidgetItem(levelItem, { check->name }); | ||||
67 | checkItem->setData(0, CheckNameRole, check->name); | ||||
68 | checkItem->setToolTip(0, check->description); | ||||
69 | checkItem->setCheckState(0, Qt::Unchecked); | ||||
70 | | ||||
71 | auto urlLabel = new QLabel; | ||||
72 | urlLabel->setText(QStringLiteral("<a href=\"%1\">Web Page</a>").arg(check->url.toDisplayString())); | ||||
73 | urlLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); | ||||
74 | m_treeWidget->setItemWidget(checkItem, 1, urlLabel); | ||||
75 | | ||||
76 | connect(urlLabel, &QLabel::linkActivated, this, linkActivated); | ||||
77 | | ||||
78 | m_items[check->name] = checkItem; | ||||
79 | } | ||||
80 | } | ||||
81 | | ||||
82 | connect(m_treeWidget, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* item) { | ||||
83 | setState(item, item->checkState(0)); | ||||
84 | updateChecks(); | ||||
85 | }); | ||||
86 | } | ||||
87 | | ||||
88 | ChecksWidget::~ChecksWidget() | ||||
89 | { | ||||
90 | } | ||||
91 | | ||||
92 | QString ChecksWidget::checks() const | ||||
93 | { | ||||
94 | return m_checks; | ||||
95 | } | ||||
96 | | ||||
97 | void ChecksWidget::setChecks(const QString& checks) | ||||
98 | { | ||||
99 | if (m_checks == checks) { | ||||
100 | return; | ||||
101 | } | ||||
102 | | ||||
103 | for (int i = 0 ; i < m_treeWidget->topLevelItemCount(); ++i) { | ||||
104 | setState(m_treeWidget->topLevelItem(i), Qt::Unchecked); | ||||
105 | } | ||||
106 | | ||||
107 | const QStringList checksList = checks.split(',', QString::SkipEmptyParts); | ||||
108 | for (auto checkName : checksList) { | ||||
109 | checkName = checkName.trimmed(); | ||||
110 | | ||||
111 | if (checkName == QStringLiteral("manual")) { | ||||
112 | // FIXME add qwarn | ||||
113 | continue; | ||||
114 | } | ||||
115 | | ||||
116 | auto state = Qt::Checked; | ||||
117 | if (checkName.startsWith(QStringLiteral("no-"))) { | ||||
118 | checkName = checkName.mid(3); | ||||
119 | state = Qt::Unchecked; | ||||
120 | } | ||||
121 | | ||||
122 | if (auto checkItem = m_items.value(checkName, nullptr)) { | ||||
123 | setState(checkItem, state); | ||||
124 | } | ||||
125 | } | ||||
126 | | ||||
127 | updateChecks(); | ||||
128 | } | ||||
129 | | ||||
130 | QStringList levelChecks(const QTreeWidgetItem* levelItem, QString& topLevel) | ||||
131 | { | ||||
132 | Q_ASSERT(levelItem); | ||||
133 | | ||||
134 | if (levelItem->checkState(0) == Qt::Unchecked) { | ||||
135 | return {}; | ||||
136 | } | ||||
137 | | ||||
138 | auto levelName = levelItem->data(0, CheckNameRole).toString(); | ||||
139 | | ||||
140 | if (levelItem->checkState(0) == Qt::Checked && | ||||
141 | levelName != QStringLiteral("manual") && | ||||
142 | topLevel.isEmpty()) { | ||||
143 | | ||||
144 | topLevel = levelName; | ||||
145 | return {}; | ||||
146 | } | ||||
147 | | ||||
148 | QStringList enabled; | ||||
149 | QStringList disabled; | ||||
150 | | ||||
151 | for (int j = 0 ; j < levelItem->childCount(); ++j) { | ||||
152 | auto checkItem = levelItem->child(j); | ||||
153 | auto checkName = checkItem->data(0, CheckNameRole).toString(); | ||||
154 | | ||||
155 | if (checkItem->checkState(0) == Qt::Checked) { | ||||
156 | enabled += checkName; | ||||
157 | } else { | ||||
158 | disabled += QStringLiteral("no-%1").arg(checkName); | ||||
159 | } | ||||
160 | } | ||||
161 | | ||||
162 | if (levelName == QStringLiteral("manual") || enabled.size() < disabled.size()) { | ||||
163 | return enabled; | ||||
164 | } | ||||
165 | | ||||
166 | if (topLevel.isEmpty()) { | ||||
167 | topLevel = levelName; | ||||
168 | } | ||||
169 | | ||||
170 | return disabled; | ||||
171 | } | ||||
172 | | ||||
173 | void ChecksWidget::updateChecks() | ||||
174 | { | ||||
175 | QStringList checksList; | ||||
176 | QString topLevel; | ||||
177 | | ||||
178 | for (int i = m_treeWidget->topLevelItemCount() - 1; i >= 0; --i) { | ||||
179 | checksList += levelChecks(m_treeWidget->topLevelItem(i), topLevel); | ||||
180 | } | ||||
181 | | ||||
182 | checksList.sort(); | ||||
183 | if (!topLevel.isEmpty()) { | ||||
184 | checksList.prepend(topLevel); | ||||
185 | } | ||||
186 | | ||||
187 | auto checks = checksList.join(','); | ||||
188 | | ||||
189 | if (checks.isEmpty()) { | ||||
190 | checks = JobParameters::defaultChecks(); | ||||
191 | } | ||||
192 | | ||||
193 | if (checks != m_checks) { | ||||
194 | m_checks = checks; | ||||
195 | emit checksChanged(m_checks); | ||||
196 | } | ||||
197 | } | ||||
198 | | ||||
199 | void ChecksWidget::setState(QTreeWidgetItem* item, Qt::CheckState state) | ||||
200 | { | ||||
201 | Q_ASSERT(item); | ||||
202 | | ||||
203 | QSignalBlocker blocker(m_treeWidget); | ||||
204 | | ||||
205 | item->setCheckState(0, state); | ||||
206 | for (int i = 0; i < item->childCount(); ++i) { | ||||
207 | item->child(i)->setCheckState(0, state); | ||||
208 | } | ||||
209 | | ||||
210 | auto parent = item->parent(); | ||||
211 | if (!parent) { | ||||
212 | return; | ||||
213 | } | ||||
214 | | ||||
215 | const int childCount = parent->childCount(); | ||||
216 | int checkedCount = 0; | ||||
217 | | ||||
218 | for (int i = 0; i < childCount; ++i) { | ||||
219 | if (parent->child(i)->checkState(0) == Qt::Checked) { | ||||
220 | ++checkedCount; | ||||
221 | } | ||||
222 | } | ||||
223 | | ||||
224 | if (checkedCount == 0) { | ||||
225 | parent->setCheckState(0, Qt::Unchecked); | ||||
226 | } else if (checkedCount == childCount) { | ||||
227 | parent->setCheckState(0, Qt::Checked); | ||||
228 | } else { | ||||
229 | parent->setCheckState(0, Qt::PartiallyChecked); | ||||
230 | } | ||||
231 | } | ||||
232 | | ||||
233 | } |