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