Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qhelpfiltersettingswidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
8#include "ui_qhelpfiltersettingswidget.h"
9
10#include <QtCore/qmap.h>
11#include <QtCore/qversionnumber.h>
12#include <QtHelp/qhelpfilterdata.h>
13#include <QtHelp/qhelpfilterengine.h>
14#include <QtWidgets/qmessagebox.h>
15
17
18using namespace Qt::StringLiterals;
19
20class QHelpFilterSettings final
21{
22public:
23 void setFilter(const QString &filterName, const QHelpFilterData &filterData)
24 {
25 m_filterToData.insert(filterName, filterData);
26 }
27 void removeFilter(const QString &filterName) { m_filterToData.remove(filterName); }
28 QHelpFilterData filterData(const QString &filterName) const
29 {
30 return m_filterToData.value(filterName);
31 }
32 QMap<QString, QHelpFilterData> filters() const { return m_filterToData; }
33
34 void setCurrentFilter(const QString &filterName) { m_currentFilter = filterName; }
35 QString currentFilter() const { return m_currentFilter; }
36
37private:
38 QMap<QString, QHelpFilterData> m_filterToData;
39 QString m_currentFilter;
40};
41
42static QHelpFilterSettings readSettingsHelper(const QHelpFilterEngine *filterEngine)
43{
44 QHelpFilterSettings filterSettings;
45
46 const QStringList allFilters = filterEngine->filters();
47 for (const QString &filter : allFilters)
48 filterSettings.setFilter(filter, filterEngine->filterData(filter));
49
50 filterSettings.setCurrentFilter(filterEngine->activeFilter());
51 return filterSettings;
52}
53
54static QMap<QString, QHelpFilterData> subtract(const QMap<QString, QHelpFilterData> &minuend,
55 const QMap<QString, QHelpFilterData> &subtrahend)
56{
57 QMap<QString, QHelpFilterData> result = minuend;
58
59 for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) {
60 auto itResult = result.constFind(itSubtrahend.key());
61 if (itResult != result.constEnd() && itSubtrahend.value() == itResult.value())
62 result.erase(itResult);
63 }
64 return result;
65}
66
67static bool applySettingsHelper(QHelpFilterEngine *filterEngine, const QHelpFilterSettings &settings)
68{
69 bool changed = false;
70 const QHelpFilterSettings oldSettings = readSettingsHelper(filterEngine);
71
72 const auto filtersToRemove = subtract(oldSettings.filters(), settings.filters());
73 const auto filtersToAdd = subtract(settings.filters(), oldSettings.filters());
74
75 const QString &currentFilter = filterEngine->activeFilter();
76
77 for (auto it = filtersToRemove.cbegin(); it != filtersToRemove.cend(); ++it) {
78 filterEngine->removeFilter(it.key());
79 if (currentFilter == it.key() && !filtersToAdd.contains(it.key()))
80 filterEngine->setActiveFilter({});
81 changed = true;
82 }
83
84 for (auto it = filtersToAdd.cbegin(); it != filtersToAdd.cend(); ++it) {
85 filterEngine->setFilterData(it.key(), it.value());
86 changed = true;
87 }
88
89 if (changed)
90 filterEngine->setActiveFilter(settings.currentFilter());
91 return changed;
92}
93
94static QStringList versionsToStringList(const QList<QVersionNumber> &versions)
95{
96 QStringList versionList;
97 for (const QVersionNumber &version : versions)
98 versionList.append(version.isNull() ? QString() : version.toString());
99 return versionList;
100}
101
102static QList<QVersionNumber> stringListToVersions(const QStringList &versionList)
103{
104 QList<QVersionNumber> versions;
105 for (const QString &versionString : versionList)
106 versions.append(QVersionNumber::fromString(versionString));
107 return versions;
108}
109
111{
112 QHelpFilterSettingsWidget *q_ptr;
113 Q_DECLARE_PUBLIC(QHelpFilterSettingsWidget) // TODO: remove Q_DECLARE_PUBLIC
114public:
116
117 QHelpFilterSettings filterSettings() const { return m_filterSettings; }
118 void setFilterSettings(const QHelpFilterSettings &settings);
119
121 void componentsChanged(const QStringList &components);
122 void versionsChanged(const QStringList &versions);
126 void addFilter(const QString &filterName, const QHelpFilterData &filterData = {});
127 void removeFilter(const QString &filterName);
128 QString getUniqueFilterName(const QString &windowTitle, const QString &initialFilterName);
129 QString suggestedNewFilterName(const QString &initialFilterName) const;
130
133
137 QHelpFilterSettings m_filterSettings;
138};
139
140void QHelpFilterSettingsWidgetPrivate::setFilterSettings(const QHelpFilterSettings &settings)
141{
142 QString currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
143 if (currentFilter.isEmpty()) {
144 if (!m_filterSettings.currentFilter().isEmpty())
145 currentFilter = m_filterSettings.currentFilter();
146 else
147 currentFilter = settings.currentFilter();
148 }
149
150 m_filterSettings = settings;
151
152 m_ui.filterWidget->clear();
153 m_ui.componentWidget->clear();
154 m_ui.versionWidget->clear();
155 m_itemToFilter.clear();
156 m_filterToItem.clear();
157
158 const auto filters = m_filterSettings.filters();
159 for (auto it = filters.cbegin(); it != filters.cend(); ++it) {
160 const QString &filterName = it.key();
161 QListWidgetItem *item = new QListWidgetItem(filterName);
162 m_ui.filterWidget->addItem(item);
163 m_itemToFilter.insert(item, filterName);
164 m_filterToItem.insert(filterName, item);
165 if (filterName == currentFilter)
166 m_ui.filterWidget->setCurrentItem(item);
167 }
168
169 if (!m_ui.filterWidget->currentItem() && !m_filterToItem.isEmpty())
170 m_ui.filterWidget->setCurrentItem(m_filterToItem.first());
171
173}
174
176{
177 const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
178
179 const bool filterSelected = !currentFilter.isEmpty();
180 m_ui.componentWidget->setEnabled(filterSelected);
181 m_ui.versionWidget->setEnabled(filterSelected);
182 m_ui.renameButton->setEnabled(filterSelected);
183 m_ui.removeButton->setEnabled(filterSelected);
184
185 m_ui.componentWidget->setOptions(m_components,
186 m_filterSettings.filterData(currentFilter).components());
187 m_ui.versionWidget->setOptions(versionsToStringList(m_versions),
188 versionsToStringList(m_filterSettings.filterData(currentFilter).versions()));
189}
190
191void QHelpFilterSettingsWidgetPrivate::componentsChanged(const QStringList &components)
192{
193 const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
194 if (currentFilter.isEmpty())
195 return;
196
197 QHelpFilterData filterData = m_filterSettings.filterData(currentFilter);
198 filterData.setComponents(components);
199 m_filterSettings.setFilter(currentFilter, filterData);
200}
201
202void QHelpFilterSettingsWidgetPrivate::versionsChanged(const QStringList &versions)
203{
204 const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
205 if (currentFilter.isEmpty())
206 return;
207
208 QHelpFilterData filterData = m_filterSettings.filterData(currentFilter);
209 filterData.setVersions(stringListToVersions(versions));
210 m_filterSettings.setFilter(currentFilter, filterData);
211}
212
214{
215 const QString newFilterName = getUniqueFilterName(QHelpFilterSettingsWidget::tr("Add Filter"),
216 suggestedNewFilterName(QHelpFilterSettingsWidget::tr("New Filter")));
217 if (newFilterName.isEmpty())
218 return;
219
220 addFilter(newFilterName);
221}
222
224{
225 const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
226 if (currentFilter.isEmpty())
227 return;
228
229 const QString newFilterName = getUniqueFilterName(QHelpFilterSettingsWidget::tr("Rename Filter"), currentFilter);
230 if (newFilterName.isEmpty())
231 return;
232
233 const QHelpFilterData oldFilterData = m_filterSettings.filterData(currentFilter);
234 removeFilter(currentFilter);
235 addFilter(newFilterName, oldFilterData);
236
237 if (m_filterSettings.currentFilter() == currentFilter)
238 m_filterSettings.setCurrentFilter(newFilterName);
239}
240
242{
243 Q_Q(QHelpFilterSettingsWidget);
244
245 const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
246 if (currentFilter.isEmpty())
247 return;
248
249 if (QMessageBox::question(q, QHelpFilterSettingsWidget::tr("Remove Filter"),
250 QHelpFilterSettingsWidget::tr("Are you sure you want to remove the \"%1\" filter?")
251 .arg(currentFilter), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
252 return;
253 }
254
255 removeFilter(currentFilter);
256
257 if (m_filterSettings.currentFilter() == currentFilter)
258 m_filterSettings.setCurrentFilter({});
259}
260
261void QHelpFilterSettingsWidgetPrivate::addFilter(const QString &filterName,
262 const QHelpFilterData &filterData)
263{
264 QListWidgetItem *item = new QListWidgetItem(filterName);
265 m_filterSettings.setFilter(filterName, filterData);
266 m_filterToItem.insert(filterName, item);
267 m_itemToFilter.insert(item, filterName);
268 m_ui.filterWidget->insertItem(m_filterToItem.keys().indexOf(filterName), item);
269
270 m_ui.filterWidget->setCurrentItem(item);
272}
273
274void QHelpFilterSettingsWidgetPrivate::removeFilter(const QString &filterName)
275{
276 QListWidgetItem *item = m_filterToItem.value(filterName);
277 m_itemToFilter.remove(item);
278 m_filterToItem.remove(filterName);
279 delete item;
280 m_filterSettings.removeFilter(filterName);
281}
282
284 const QString &initialFilterName)
285{
286 Q_Q(QHelpFilterSettingsWidget);
287
288 QString newFilterName = initialFilterName;
289 while (true) {
290 QFilterNameDialog dialog(q);
291 dialog.setWindowTitle(windowTitle);
292 dialog.setFilterName(newFilterName);
293 if (dialog.exec() == QDialog::Rejected)
294 return {};
295
296 newFilterName = dialog.filterName();
297 if (!m_filterToItem.contains(newFilterName))
298 break;
299
300 if (QMessageBox::warning(q, QHelpFilterSettingsWidget::tr("Filter Exists"),
301 QHelpFilterSettingsWidget::tr("The filter \"%1\" already exists.").arg(newFilterName),
302 QMessageBox::Retry | QMessageBox::Cancel) == QMessageBox::Cancel) {
303 return {};
304 }
305 }
306 return newFilterName;
307}
308
310{
311 QString newFilterName = initialFilterName;
312 int counter = 1;
313 while (m_filterToItem.contains(newFilterName))
314 newFilterName = initialFilterName + u' ' + QString::number(++counter);
315 return newFilterName;
316}
317
318/*!
319 \class QHelpFilterSettingsWidget
320 \inmodule QtHelp
321 \since 5.15
322 \brief The QHelpFilterSettingsWidget class provides a widget that allows
323 for creating, editing and removing filters.
324
325 The instance of QHelpFilterSettingsWidget may be a part of
326 a preferences dialog. Before showing the dialog, \l setAvailableComponents()
327 and \l setAvailableVersions() should be called, otherwise the filter
328 settings widget will only offer a creation of empty filters,
329 which wouldn't be useful. In addition, \l readSettings should also
330 be called to fill up the filter settings widget with the list of filters
331 already stored in the filter engine. The creation of new filters,
332 modifications to existing filters and removal of unneeded filters are
333 handled by the widget automatically. If you want to store the current
334 state of the widget and apply it to the filter engine e.g. after
335 the user clicked the apply button - call \l applySettings().
336*/
337
338/*!
339 Constructs a filter settings widget with \a parent as parent widget.
340*/
341QHelpFilterSettingsWidget::QHelpFilterSettingsWidget(QWidget *parent)
342 : QWidget(parent)
343 , d_ptr(new QHelpFilterSettingsWidgetPrivate())
344{
345 Q_D(QHelpFilterSettingsWidget);
346 d->q_ptr = this;
347 d->m_ui.setupUi(this);
348
349 // TODO: make resources configurable
350 QString resourcePath = ":/qt-project.org/assistant/images/"_L1;
351#ifdef Q_OS_MACOS
352 resourcePath.append("mac"_L1);
353#else
354 resourcePath.append("win"_L1);
355#endif
356 d->m_ui.addButton->setIcon(QIcon(resourcePath + "/plus.png"_L1));
357 d->m_ui.removeButton->setIcon(QIcon(resourcePath + "/minus.png"_L1));
358
359 connect(d->m_ui.componentWidget, &QOptionsWidget::optionSelectionChanged,
360 this, [this](const QStringList &options) {
361 Q_D(QHelpFilterSettingsWidget);
362 d->componentsChanged(options);
363 });
364 connect(d->m_ui.versionWidget, &QOptionsWidget::optionSelectionChanged,
365 this, [this](const QStringList &options) {
366 Q_D(QHelpFilterSettingsWidget);
367 d->versionsChanged(options);
368 });
369 connect(d->m_ui.filterWidget, &QListWidget::currentItemChanged,
370 this, [this](QListWidgetItem *) {
371 Q_D(QHelpFilterSettingsWidget);
372 d->updateCurrentFilter();
373 });
374 connect(d->m_ui.filterWidget, &QListWidget::itemDoubleClicked,
375 this, [this](QListWidgetItem *) {
376 Q_D(QHelpFilterSettingsWidget);
377 d->renameFilterClicked();
378 });
379
380 // TODO: repeat these actions on context menu
381 connect(d->m_ui.addButton, &QAbstractButton::clicked, this, [this] {
382 Q_D(QHelpFilterSettingsWidget);
383 d->addFilterClicked();
384 });
385 connect(d->m_ui.renameButton, &QAbstractButton::clicked, this, [this] {
386 Q_D(QHelpFilterSettingsWidget);
387 d->renameFilterClicked();
388 });
389 connect(d->m_ui.removeButton, &QAbstractButton::clicked, this, [this] {
390 Q_D(QHelpFilterSettingsWidget);
391 d->removeFilterClicked();
392 });
393
394 d->m_ui.componentWidget->setNoOptionText(tr("No Component"));
395 d->m_ui.componentWidget->setInvalidOptionText(tr("Invalid Component"));
396 d->m_ui.versionWidget->setNoOptionText(tr("No Version"));
397 d->m_ui.versionWidget->setInvalidOptionText(tr("Invalid Version"));
398}
399
400/*!
401 Destroys the filter settings widget.
402*/
403QHelpFilterSettingsWidget::~QHelpFilterSettingsWidget() = default;
404
405/*!
406 Sets the list of all available components to \a components.
407 \sa QHelpFilterEngine::availableComponents()
408*/
409void QHelpFilterSettingsWidget::setAvailableComponents(const QStringList &components)
410{
411 Q_D(QHelpFilterSettingsWidget);
412 d->m_components = components;
413 d->updateCurrentFilter();
414}
415
416/*!
417 Sets the list of all available version numbers to \a versions.
418 \sa QHelpFilterEngine::availableVersions()
419*/
420void QHelpFilterSettingsWidget::setAvailableVersions(const QList<QVersionNumber> &versions)
421{
422 Q_D(QHelpFilterSettingsWidget);
423 d->m_versions = versions;
424 d->updateCurrentFilter();
425}
426
427/*!
428 Reads the filter settings stored inside \a filterEngine and sets up
429 this filter settings widget accordingly.
430*/
431void QHelpFilterSettingsWidget::readSettings(const QHelpFilterEngine *filterEngine)
432{
433 Q_D(QHelpFilterSettingsWidget);
434 const QHelpFilterSettings settings = readSettingsHelper(filterEngine);
435 d->setFilterSettings(settings);
436}
437
438/*!
439 Writes the filter settings, currently presented in this filter settings
440 widget, to the \a filterEngine. The old settings stored in the filter
441 engine will be overwritten. Returns \c true on success.
442*/
443bool QHelpFilterSettingsWidget::applySettings(QHelpFilterEngine *filterEngine) const
444{
445 Q_D(const QHelpFilterSettingsWidget);
446 return applySettingsHelper(filterEngine, d->filterSettings());
447}
448
449QT_END_NAMESPACE
void removeFilter(const QString &filterName)
void componentsChanged(const QStringList &components)
QString suggestedNewFilterName(const QString &initialFilterName) const
QMap< QString, QListWidgetItem * > m_filterToItem
void versionsChanged(const QStringList &versions)
void setFilterSettings(const QHelpFilterSettings &settings)
QString getUniqueFilterName(const QString &windowTitle, const QString &initialFilterName)
QHash< QListWidgetItem *, QString > m_itemToFilter
void addFilter(const QString &filterName, const QHelpFilterData &filterData={})
void setFilter(const QString &filterName, const QHelpFilterData &filterData)
void setCurrentFilter(const QString &filterName)
QMap< QString, QHelpFilterData > filters() const
QHelpFilterData filterData(const QString &filterName) const
void removeFilter(const QString &filterName)
Combined button and popup list for selecting options.
static QList< QVersionNumber > stringListToVersions(const QStringList &versionList)
static QHelpFilterSettings readSettingsHelper(const QHelpFilterEngine *filterEngine)
static QStringList versionsToStringList(const QList< QVersionNumber > &versions)
static QMap< QString, QHelpFilterData > subtract(const QMap< QString, QHelpFilterData > &minuend, const QMap< QString, QHelpFilterData > &subtrahend)
static bool applySettingsHelper(QHelpFilterEngine *filterEngine, const QHelpFilterSettings &settings)