summaryrefslogtreecommitdiff
path: root/src/assistant
diff options
context:
space:
mode:
Diffstat (limited to 'src/assistant')
-rw-r--r--src/assistant/help/help.pro17
-rw-r--r--src/assistant/help/helpsystem.qrc4
-rw-r--r--src/assistant/help/images/mac/minus.pngbin0 -> 488 bytes
-rw-r--r--src/assistant/help/images/mac/plus.pngbin0 -> 810 bytes
-rw-r--r--src/assistant/help/images/win/minus.pngbin0 -> 429 bytes
-rw-r--r--src/assistant/help/images/win/plus.pngbin0 -> 709 bytes
-rw-r--r--src/assistant/help/qfilternamedialog.cpp65
-rw-r--r--src/assistant/help/qfilternamedialog.ui55
-rw-r--r--src/assistant/help/qfilternamedialog_p.h56
-rw-r--r--src/assistant/help/qhelpfiltersettings.cpp170
-rw-r--r--src/assistant/help/qhelpfiltersettings_p.h85
-rw-r--r--src/assistant/help/qhelpfiltersettingswidget.cpp428
-rw-r--r--src/assistant/help/qhelpfiltersettingswidget.h78
-rw-r--r--src/assistant/help/qhelpfiltersettingswidget.ui83
-rw-r--r--src/assistant/help/qoptionswidget.cpp229
-rw-r--r--src/assistant/help/qoptionswidget_p.h76
16 files changed, 1344 insertions, 2 deletions
diff --git a/src/assistant/help/help.pro b/src/assistant/help/help.pro
index cd7781dde..ff7a81374 100644
--- a/src/assistant/help/help.pro
+++ b/src/assistant/help/help.pro
@@ -12,10 +12,13 @@ DEFINES -= QT_ASCII_CAST_WARNINGS
RESOURCES += helpsystem.qrc
SOURCES += \
qcompressedhelpinfo.cpp \
+ qfilternamedialog.cpp \
qhelpenginecore.cpp \
qhelpengine.cpp \
qhelpfilterdata.cpp \
qhelpfilterengine.cpp \
+ qhelpfiltersettings.cpp \
+ qhelpfiltersettingswidget.cpp \
qhelpdbreader.cpp \
qhelpcontentwidget.cpp \
qhelpindexwidget.cpp \
@@ -26,15 +29,19 @@ SOURCES += \
qhelpsearchindexwriter_default.cpp \
qhelpsearchindexreader_default.cpp \
qhelpsearchindexreader.cpp \
- qhelp_global.cpp
+ qhelp_global.cpp \
+ qoptionswidget.cpp
HEADERS += \
qcompressedhelpinfo.h \
+ qfilternamedialog_p.h \
qhelpenginecore.h \
qhelpengine.h \
qhelpengine_p.h \
qhelpfilterdata.h \
qhelpfilterengine.h \
+ qhelpfiltersettings_p.h \
+ qhelpfiltersettingswidget.h \
qhelp_global.h \
qhelpdbreader_p.h \
qhelpcontentwidget.h \
@@ -45,6 +52,12 @@ HEADERS += \
qhelpsearchresultwidget.h \
qhelpsearchindexwriter_default_p.h \
qhelpsearchindexreader_default_p.h \
- qhelpsearchindexreader_p.h
+ qhelpsearchindexreader_p.h \
+ qoptionswidget_p.h
+
+FORMS += \
+ qhelpfiltersettingswidget.ui \
+ qfilternamedialog.ui
+
load(qt_module)
diff --git a/src/assistant/help/helpsystem.qrc b/src/assistant/help/helpsystem.qrc
index 785923aad..611008639 100644
--- a/src/assistant/help/helpsystem.qrc
+++ b/src/assistant/help/helpsystem.qrc
@@ -4,5 +4,9 @@
<file>images/1rightarrow.png</file>
<file>images/3leftarrow.png</file>
<file>images/3rightarrow.png</file>
+ <file>images/mac/minus.png</file>
+ <file>images/mac/plus.png</file>
+ <file>images/win/minus.png</file>
+ <file>images/win/plus.png</file>
</qresource>
</RCC>
diff --git a/src/assistant/help/images/mac/minus.png b/src/assistant/help/images/mac/minus.png
new file mode 100644
index 000000000..8d2eaed52
--- /dev/null
+++ b/src/assistant/help/images/mac/minus.png
Binary files differ
diff --git a/src/assistant/help/images/mac/plus.png b/src/assistant/help/images/mac/plus.png
new file mode 100644
index 000000000..1ee45423e
--- /dev/null
+++ b/src/assistant/help/images/mac/plus.png
Binary files differ
diff --git a/src/assistant/help/images/win/minus.png b/src/assistant/help/images/win/minus.png
new file mode 100644
index 000000000..c0dc274bb
--- /dev/null
+++ b/src/assistant/help/images/win/minus.png
Binary files differ
diff --git a/src/assistant/help/images/win/plus.png b/src/assistant/help/images/win/plus.png
new file mode 100644
index 000000000..ecf058941
--- /dev/null
+++ b/src/assistant/help/images/win/plus.png
Binary files differ
diff --git a/src/assistant/help/qfilternamedialog.cpp b/src/assistant/help/qfilternamedialog.cpp
new file mode 100644
index 000000000..8563a3355
--- /dev/null
+++ b/src/assistant/help/qfilternamedialog.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets/QPushButton>
+
+#include "qfilternamedialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QFilterNameDialog::QFilterNameDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ m_ui.setupUi(this);
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked,
+ this, &QDialog::accept);
+ connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked,
+ this, &QDialog::reject);
+ connect(m_ui.lineEdit, &QLineEdit::textChanged,
+ this, &QFilterNameDialog::updateOkButton);
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
+}
+
+void QFilterNameDialog::setFilterName(const QString &filter)
+{
+ m_ui.lineEdit->setText(filter);
+ m_ui.lineEdit->selectAll();
+}
+
+QString QFilterNameDialog::filterName() const
+{
+ return m_ui.lineEdit->text();
+}
+
+void QFilterNameDialog::updateOkButton()
+{
+ m_ui.buttonBox->button(QDialogButtonBox::Ok)
+ ->setDisabled(m_ui.lineEdit->text().isEmpty());
+}
+
+QT_END_NAMESPACE
diff --git a/src/assistant/help/qfilternamedialog.ui b/src/assistant/help/qfilternamedialog.ui
new file mode 100644
index 000000000..1da584a80
--- /dev/null
+++ b/src/assistant/help/qfilternamedialog.ui
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FilterNameDialogClass</class>
+ <widget class="QDialog" name="FilterNameDialogClass">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>312</width>
+ <height>77</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add Filter</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Filter Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/assistant/help/qfilternamedialog_p.h b/src/assistant/help/qfilternamedialog_p.h
new file mode 100644
index 000000000..f805e9308
--- /dev/null
+++ b/src/assistant/help/qfilternamedialog_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILTERNAMEDIALOG_H
+#define QFILTERNAMEDIALOG_H
+
+#include <QtWidgets/QDialog>
+#include "ui_qfilternamedialog.h"
+
+QT_BEGIN_NAMESPACE
+
+class QFilterNameDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ QFilterNameDialog(QWidget *parent = nullptr);
+
+ void setFilterName(const QString &filter);
+ QString filterName() const;
+
+private slots:
+ void updateOkButton();
+
+private:
+ Ui::FilterNameDialogClass m_ui;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFILTERNAMEDIALOG_H
diff --git a/src/assistant/help/qhelpfiltersettings.cpp b/src/assistant/help/qhelpfiltersettings.cpp
new file mode 100644
index 000000000..e9a1c3f4e
--- /dev/null
+++ b/src/assistant/help/qhelpfiltersettings.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhelpfiltersettings_p.h"
+#include "qhelpfilterdata.h"
+
+#include <QtCore/QMap>
+#include <QtHelp/QHelpFilterEngine>
+
+QT_BEGIN_NAMESPACE
+
+class QHelpFilterSettingsPrivate : public QSharedData
+{
+public:
+ QHelpFilterSettingsPrivate() = default;
+ QHelpFilterSettingsPrivate(const QHelpFilterSettingsPrivate &other) = default;
+ ~QHelpFilterSettingsPrivate() = default;
+
+ QMap<QString, QHelpFilterData> m_filterToData;
+ QString m_currentFilter;
+};
+
+QHelpFilterSettings::QHelpFilterSettings()
+ : d(new QHelpFilterSettingsPrivate)
+{
+}
+
+QHelpFilterSettings::QHelpFilterSettings(const QHelpFilterSettings &) = default;
+
+QHelpFilterSettings::QHelpFilterSettings(QHelpFilterSettings &&) = default;
+
+QHelpFilterSettings::~QHelpFilterSettings() = default;
+
+QHelpFilterSettings &QHelpFilterSettings::operator=(const QHelpFilterSettings &) = default;
+
+QHelpFilterSettings &QHelpFilterSettings::operator=(QHelpFilterSettings &&) = default;
+
+void QHelpFilterSettings::setFilter(const QString &filterName,
+ const QHelpFilterData &filterData)
+{
+ d->m_filterToData.insert(filterName, filterData);
+}
+
+void QHelpFilterSettings::removeFilter(const QString &filterName)
+{
+ d->m_filterToData.remove(filterName);
+}
+
+QStringList QHelpFilterSettings::filterNames() const
+{
+ return d->m_filterToData.keys();
+}
+
+QHelpFilterData QHelpFilterSettings::filterData(const QString &filterName) const
+{
+ return d->m_filterToData.value(filterName);
+}
+
+QMap<QString, QHelpFilterData> QHelpFilterSettings::filters() const
+{
+ return d->m_filterToData;
+}
+
+void QHelpFilterSettings::setCurrentFilter(const QString &filterName)
+{
+ d->m_currentFilter = filterName;
+}
+
+QString QHelpFilterSettings::currentFilter() const
+{
+ return d->m_currentFilter;
+}
+
+QHelpFilterSettings QHelpFilterSettings::readSettings(QHelpFilterEngine *filterEngine)
+{
+ QHelpFilterSettings filterSettings;
+
+ const QStringList allFilters = filterEngine->filters();
+ for (const QString &filter : allFilters)
+ filterSettings.setFilter(filter, filterEngine->filterData(filter));
+
+ filterSettings.setCurrentFilter(filterEngine->activeFilter());
+
+ return filterSettings;
+}
+
+static QMap<QString, QHelpFilterData> subtract(const QMap<QString, QHelpFilterData> &minuend,
+ const QMap<QString, QHelpFilterData> &subtrahend)
+{
+ QMap<QString, QHelpFilterData> result = minuend;
+
+ for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) {
+ auto itResult = result.find(itSubtrahend.key());
+ if (itResult != result.end() && itSubtrahend.value() == itResult.value())
+ result.erase(itResult);
+ }
+
+ return result;
+}
+
+bool QHelpFilterSettings::applySettings(QHelpFilterEngine *filterEngine,
+ const QHelpFilterSettings &settings)
+{
+ bool changed = false;
+ const QHelpFilterSettings oldSettings = readSettings(filterEngine);
+
+ const QMap<QString, QHelpFilterData> filtersToRemove = subtract(
+ oldSettings.filters(),
+ settings.filters());
+ const QMap<QString, QHelpFilterData> filtersToAdd = subtract(
+ settings.filters(),
+ oldSettings.filters());
+
+ const QString &currentFilter = filterEngine->activeFilter();
+
+ for (const QString &filter : filtersToRemove.keys()) {
+ filterEngine->removeFilter(filter);
+ if (currentFilter == filter && !filtersToAdd.contains(filter))
+ filterEngine->setActiveFilter(QString());
+ changed = true;
+ }
+
+ for (auto it = filtersToAdd.cbegin(); it != filtersToAdd.cend(); ++it) {
+ filterEngine->setFilterData(it.key(), it.value());
+ changed = true;
+ }
+
+ if (changed)
+ filterEngine->setActiveFilter(settings.currentFilter());
+
+ return changed;
+}
+
+QT_END_NAMESPACE
diff --git a/src/assistant/help/qhelpfiltersettings_p.h b/src/assistant/help/qhelpfiltersettings_p.h
new file mode 100644
index 000000000..50e30e492
--- /dev/null
+++ b/src/assistant/help/qhelpfiltersettings_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHELPFILTERSETTINGS_H
+#define QHELPFILTERSETTINGS_H
+
+#include <QtCore/QSharedDataPointer>
+
+QT_BEGIN_NAMESPACE
+
+template <class K, class T>
+class QMap;
+class QHelpFilterData;
+class QHelpFilterEngine;
+class QHelpFilterSettingsPrivate;
+
+class QHelpFilterSettings final
+{
+public:
+ QHelpFilterSettings();
+ QHelpFilterSettings(const QHelpFilterSettings &other);
+ QHelpFilterSettings(QHelpFilterSettings &&other);
+ ~QHelpFilterSettings();
+
+ QHelpFilterSettings &operator=(const QHelpFilterSettings &other);
+ QHelpFilterSettings &operator=(QHelpFilterSettings &&other);
+
+ void swap(QHelpFilterSettings &other) noexcept
+ { d.swap(other.d); }
+
+ void setFilter(const QString &filterName, const QHelpFilterData &filterData);
+ void removeFilter(const QString &filterName);
+ QStringList filterNames() const;
+ QHelpFilterData filterData(const QString &filterName) const;
+ QMap<QString, QHelpFilterData> filters() const;
+
+ void setCurrentFilter(const QString &filterName);
+ QString currentFilter() const;
+
+ static QHelpFilterSettings readSettings(QHelpFilterEngine *filterEngine);
+ static bool applySettings(QHelpFilterEngine *filterEngine, const QHelpFilterSettings &settings);
+
+private:
+ QSharedDataPointer<QHelpFilterSettingsPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QHELPFILTERSETTINGS_H
diff --git a/src/assistant/help/qhelpfiltersettingswidget.cpp b/src/assistant/help/qhelpfiltersettingswidget.cpp
new file mode 100644
index 000000000..15cc4f475
--- /dev/null
+++ b/src/assistant/help/qhelpfiltersettingswidget.cpp
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhelpfilterdata.h"
+#include "qhelpfiltersettings_p.h"
+#include "qhelpfiltersettingswidget.h"
+#include "ui_qhelpfiltersettingswidget.h"
+#include "qfilternamedialog_p.h"
+
+#include <QtWidgets/QMessageBox>
+#include <QtCore/QVersionNumber>
+
+QT_BEGIN_NAMESPACE
+
+static QStringList versionsToStringList(const QList<QVersionNumber> &versions)
+{
+ QStringList versionList;
+ for (const QVersionNumber &version : versions)
+ versionList.append(version.isNull() ? QString() : version.toString());
+ return versionList;
+}
+
+static QList<QVersionNumber> stringListToVersions(const QStringList &versionList)
+{
+ QList<QVersionNumber> versions;
+ for (const QString &versionString : versionList)
+ versions.append(QVersionNumber::fromString(versionString));
+ return versions;
+}
+
+class QHelpFilterSettingsWidgetPrivate
+{
+ QHelpFilterSettingsWidget *q_ptr;
+ Q_DECLARE_PUBLIC(QHelpFilterSettingsWidget)
+public:
+ QHelpFilterSettingsWidgetPrivate() = default;
+
+ QHelpFilterSettings filterSettings() const;
+ void setFilterSettings(const QHelpFilterSettings &settings);
+
+ void updateCurrentFilter();
+ void componentsChanged(const QStringList &components);
+ void versionsChanged(const QStringList &versions);
+ void addFilterClicked();
+ void renameFilterClicked();
+ void removeFilterClicked();
+ void addFilter(const QString &filterName,
+ const QHelpFilterData &filterData = QHelpFilterData());
+ void removeFilter(const QString &filterName);
+ QString getUniqueFilterName(const QString &windowTitle,
+ const QString &initialFilterName);
+ QString suggestedNewFilterName(const QString &initialFilterName) const;
+
+ QMap<QString, QListWidgetItem *> m_filterToItem;
+ QHash<QListWidgetItem *, QString> m_itemToFilter;
+
+ Ui::QHelpFilterSettingsWidget m_ui;
+ QStringList m_components;
+ QList<QVersionNumber> m_versions;
+ QHelpFilterSettings m_filterSettings;
+};
+
+void QHelpFilterSettingsWidgetPrivate::setFilterSettings(const QHelpFilterSettings &settings)
+{
+ QString currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+ if (currentFilter.isEmpty()) {
+ if (!m_filterSettings.currentFilter().isEmpty())
+ currentFilter = m_filterSettings.currentFilter();
+ else
+ currentFilter = settings.currentFilter();
+ }
+
+ m_filterSettings = settings;
+
+ m_ui.filterWidget->clear();
+ m_ui.componentWidget->clear();
+ m_ui.versionWidget->clear();
+ m_itemToFilter.clear();
+ m_filterToItem.clear();
+
+ for (const QString &filterName : m_filterSettings.filterNames()) {
+ QListWidgetItem *item = new QListWidgetItem(filterName);
+ m_ui.filterWidget->addItem(item);
+ m_itemToFilter.insert(item, filterName);
+ m_filterToItem.insert(filterName, item);
+ if (filterName == currentFilter)
+ m_ui.filterWidget->setCurrentItem(item);
+ }
+
+ if (!m_ui.filterWidget->currentItem() && !m_filterToItem.isEmpty())
+ m_ui.filterWidget->setCurrentItem(m_filterToItem.first());
+
+ updateCurrentFilter();
+}
+
+QHelpFilterSettings QHelpFilterSettingsWidgetPrivate::filterSettings() const
+{
+ return m_filterSettings;
+}
+
+void QHelpFilterSettingsWidgetPrivate::updateCurrentFilter()
+{
+ const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+
+ const bool filterSelected = !currentFilter.isEmpty();
+ m_ui.componentWidget->setEnabled(filterSelected);
+ m_ui.versionWidget->setEnabled(filterSelected);
+ m_ui.renameButton->setEnabled(filterSelected);
+ m_ui.removeButton->setEnabled(filterSelected);
+
+ m_ui.componentWidget->setOptions(m_components,
+ m_filterSettings.filterData(currentFilter).components());
+ m_ui.versionWidget->setOptions(versionsToStringList(m_versions),
+ versionsToStringList(m_filterSettings.filterData(currentFilter).versions()));
+}
+
+void QHelpFilterSettingsWidgetPrivate::componentsChanged(const QStringList &components)
+{
+ const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+ if (currentFilter.isEmpty())
+ return;
+
+ QHelpFilterData filterData = m_filterSettings.filterData(currentFilter);
+ filterData.setComponents(components);
+ m_filterSettings.setFilter(currentFilter, filterData);
+}
+
+void QHelpFilterSettingsWidgetPrivate::versionsChanged(const QStringList &versions)
+{
+ const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+ if (currentFilter.isEmpty())
+ return;
+
+ QHelpFilterData filterData = m_filterSettings.filterData(currentFilter);
+ filterData.setVersions(stringListToVersions(versions));
+ m_filterSettings.setFilter(currentFilter, filterData);
+}
+
+void QHelpFilterSettingsWidgetPrivate::addFilterClicked()
+{
+ Q_Q(QHelpFilterSettingsWidget);
+
+ const QString newFilterName = getUniqueFilterName(q->tr("Add Filter"),
+ suggestedNewFilterName(q->tr("New Filter")));
+ if (newFilterName.isEmpty())
+ return;
+
+ addFilter(newFilterName);
+}
+
+void QHelpFilterSettingsWidgetPrivate::renameFilterClicked()
+{
+ Q_Q(QHelpFilterSettingsWidget);
+
+ const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+ if (currentFilter.isEmpty())
+ return;
+
+ const QString newFilterName = getUniqueFilterName(q->tr("Rename Filter"), currentFilter);
+ if (newFilterName.isEmpty())
+ return;
+
+ const QHelpFilterData oldFilterData = m_filterSettings.filterData(currentFilter);
+ removeFilter(currentFilter);
+ addFilter(newFilterName, oldFilterData);
+
+ if (m_filterSettings.currentFilter() == currentFilter)
+ m_filterSettings.setCurrentFilter(newFilterName);
+}
+
+void QHelpFilterSettingsWidgetPrivate::removeFilterClicked()
+{
+ Q_Q(QHelpFilterSettingsWidget);
+
+ const QString &currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem());
+ if (currentFilter.isEmpty())
+ return;
+
+ if (QMessageBox::question(q, q->tr("Remove Filter"),
+ q->tr("Are you sure you want to remove the \"%1\" filter?")
+ .arg(currentFilter),
+ QMessageBox::Yes | QMessageBox::No)
+ != QMessageBox::Yes) {
+ return;
+ }
+
+ removeFilter(currentFilter);
+
+ if (m_filterSettings.currentFilter() == currentFilter)
+ m_filterSettings.setCurrentFilter(QString());
+}
+
+void QHelpFilterSettingsWidgetPrivate::addFilter(const QString &filterName,
+ const QHelpFilterData &filterData)
+{
+ QListWidgetItem *item = new QListWidgetItem(filterName);
+ m_filterSettings.setFilter(filterName, filterData);
+ m_filterToItem.insert(filterName, item);
+ m_itemToFilter.insert(item, filterName);
+ m_ui.filterWidget->insertItem(m_filterToItem.keys().indexOf(filterName), item);
+
+ m_ui.filterWidget->setCurrentItem(item);
+ updateCurrentFilter();
+}
+
+void QHelpFilterSettingsWidgetPrivate::removeFilter(const QString &filterName)
+{
+ QListWidgetItem *item = m_filterToItem.value(filterName);
+ m_itemToFilter.remove(item);
+ m_filterToItem.remove(filterName);
+ delete item;
+
+ m_filterSettings.removeFilter(filterName);
+}
+
+QString QHelpFilterSettingsWidgetPrivate::getUniqueFilterName(const QString &windowTitle,
+ const QString &initialFilterName)
+{
+ Q_Q(QHelpFilterSettingsWidget);
+
+ QString newFilterName = initialFilterName;
+ while (1) {
+ QFilterNameDialog dialog(q);
+ dialog.setWindowTitle(windowTitle);
+ dialog.setFilterName(newFilterName);
+ if (dialog.exec() == QDialog::Rejected)
+ return QString();
+
+ newFilterName = dialog.filterName();
+ if (!m_filterToItem.contains(newFilterName))
+ break;
+
+ if (QMessageBox::warning(q, q->tr("Filter Exists"),
+ q->tr("The filter \"%1\" already exists.")
+ .arg(newFilterName),
+ QMessageBox::Retry | QMessageBox::Cancel)
+ == QMessageBox::Cancel) {
+ return QString();
+ }
+ }
+
+ return newFilterName;
+}
+
+QString QHelpFilterSettingsWidgetPrivate::suggestedNewFilterName(const QString &initialFilterName) const
+{
+ QString newFilterName = initialFilterName;
+
+ int counter = 1;
+ while (m_filterToItem.contains(newFilterName)) {
+ newFilterName = initialFilterName + QLatin1Char(' ')
+ + QString::number(++counter);
+ }
+
+ return newFilterName;
+}
+
+/*!
+ \class QHelpFilterSettingsWidget
+ \inmodule QtHelp
+ \since 5.15
+ \brief The QHelpFilterSettingsWidget class provides a widget that allows
+ for creating, editing and removing filters.
+
+ The instance of QHelpFilterSettingsWidget may be a part of
+ a preferences dialog. Before showing the dialog, \l setAvailableComponents()
+ and \l setAvailableVersions() should be called, otherwise the filter
+ settings widget will only offer a creation of empty filters,
+ which wouldn't be useful. In addition, \l readSettings should also
+ be called to fill up the filter settings widget with the list of filters
+ already stored in the filter engine. The creation of new filters,
+ modifications to existing filters and removal of unneeded filters are
+ handled by the widget automatically. If you want to store the current
+ state of the widget and apply it to the filter engine e.g. after
+ the user clicked the apply button - call \l applySettings().
+*/
+
+/*!
+ Constructs a filter settings widget with \a parent as parent widget.
+*/
+QHelpFilterSettingsWidget::QHelpFilterSettingsWidget(QWidget *parent)
+ : QWidget(parent)
+ , d_ptr(new QHelpFilterSettingsWidgetPrivate())
+{
+ Q_D(QHelpFilterSettingsWidget);
+ d->q_ptr = this;
+ d->m_ui.setupUi(this);
+
+ // TODO: make resources configurable
+ QString resourcePath = QLatin1String(":/qt-project.org/assistant/images/");
+#ifdef Q_OS_MACOS
+ resourcePath.append(QLatin1String("mac"));
+#else
+ resourcePath.append(QLatin1String("win"));
+#endif
+ d->m_ui.addButton->setIcon(QIcon(resourcePath + QLatin1String("/plus.png")));
+ d->m_ui.removeButton->setIcon(QIcon(resourcePath + QLatin1String("/minus.png")));
+
+ connect(d->m_ui.componentWidget, &QOptionsWidget::optionSelectionChanged,
+ [this](const QStringList &options) {
+ Q_D(QHelpFilterSettingsWidget);
+ d->componentsChanged(options);
+ });
+ connect(d->m_ui.versionWidget, &QOptionsWidget::optionSelectionChanged,
+ [this](const QStringList &options) {
+ Q_D(QHelpFilterSettingsWidget);
+ d->versionsChanged(options);
+ });
+ connect(d->m_ui.filterWidget, &QListWidget::currentItemChanged,
+ this, [this](QListWidgetItem *) {
+ Q_D(QHelpFilterSettingsWidget);
+ d->updateCurrentFilter();
+ });
+ connect(d->m_ui.filterWidget, &QListWidget::itemDoubleClicked,
+ [this](QListWidgetItem *) {
+ Q_D(QHelpFilterSettingsWidget);
+ d->renameFilterClicked();
+ });
+
+ // TODO: repeat these actions on context menu
+ connect(d->m_ui.addButton, &QAbstractButton::clicked,
+ [this]() {
+ Q_D(QHelpFilterSettingsWidget);
+ d->addFilterClicked();
+ });
+ connect(d->m_ui.renameButton, &QAbstractButton::clicked,
+ [this]() {
+ Q_D(QHelpFilterSettingsWidget);
+ d->renameFilterClicked();
+ });
+ connect(d->m_ui.removeButton, &QAbstractButton::clicked,
+ [this]() {
+ Q_D(QHelpFilterSettingsWidget);
+ d->removeFilterClicked();
+ });
+
+ d->m_ui.componentWidget->setNoOptionText(tr("No Component"));
+ d->m_ui.componentWidget->setInvalidOptionText(tr("Invalid Component"));
+ d->m_ui.versionWidget->setNoOptionText(tr("No Version"));
+ d->m_ui.versionWidget->setInvalidOptionText(tr("Invalid Version"));
+}
+
+/*!
+ Destroys the filter settings widget.
+*/
+QHelpFilterSettingsWidget::~QHelpFilterSettingsWidget() = default;
+
+/*!
+ Sets the list of all available components to \a components.
+ \sa QHelpFilterEngine::availableComponents()
+*/
+void QHelpFilterSettingsWidget::setAvailableComponents(const QStringList &components)
+{
+ Q_D(QHelpFilterSettingsWidget);
+ d->m_components = components;
+ d->updateCurrentFilter();
+}
+
+/*!
+ Sets the list of all available version numbers to \a versions.
+ \sa QHelpFilterEngine::availableVersions()
+*/
+void QHelpFilterSettingsWidget::setAvailableVersions(const QList<QVersionNumber> &versions)
+{
+ Q_D(QHelpFilterSettingsWidget);
+ d->m_versions = versions;
+ d->updateCurrentFilter();
+}
+
+/*!
+ Reads the filter settings stored inside \a filterEngine and sets up
+ this filter settings widget accordingly.
+*/
+void QHelpFilterSettingsWidget::readSettings(QHelpFilterEngine *filterEngine)
+{
+ Q_D(QHelpFilterSettingsWidget);
+ const QHelpFilterSettings settings = QHelpFilterSettings::readSettings(filterEngine);
+ d->setFilterSettings(settings);
+}
+
+/*!
+ Writes the filter settings, currently presented in this filter settings
+ widget, to the \a filterEngine. The old settings stored in the filter
+ engine will be overwritten.
+*/
+bool QHelpFilterSettingsWidget::applySettings(QHelpFilterEngine *filterEngine)
+{
+ Q_D(QHelpFilterSettingsWidget);
+ return QHelpFilterSettings::applySettings(filterEngine, d->filterSettings());
+}
+
+QT_END_NAMESPACE
diff --git a/src/assistant/help/qhelpfiltersettingswidget.h b/src/assistant/help/qhelpfiltersettingswidget.h
new file mode 100644
index 000000000..1b6606054
--- /dev/null
+++ b/src/assistant/help/qhelpfiltersettingswidget.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHELPFILTERSETTINGSWIDGET_H
+#define QHELPFILTERSETTINGSWIDGET_H
+
+#include <QtHelp/qhelp_global.h>
+
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QVersionNumber;
+
+class QHelpFilterEngine;
+class QHelpFilterSettingsWidgetPrivate;
+
+class QHELP_EXPORT QHelpFilterSettingsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QHelpFilterSettingsWidget(QWidget *parent);
+
+ ~QHelpFilterSettingsWidget();
+
+ void setAvailableComponents(const QStringList &components);
+ void setAvailableVersions(const QList<QVersionNumber> &versions);
+
+ // TODO: filterEngine may be moved to c'tor or to setFilterEngine() setter
+ void readSettings(QHelpFilterEngine *filterEngine);
+ bool applySettings(QHelpFilterEngine *filterEngine);
+
+private:
+ QScopedPointer<class QHelpFilterSettingsWidgetPrivate> d_ptr;
+ Q_DECLARE_PRIVATE(QHelpFilterSettingsWidget)
+ Q_DISABLE_COPY_MOVE(QHelpFilterSettingsWidget)
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/assistant/help/qhelpfiltersettingswidget.ui b/src/assistant/help/qhelpfiltersettingswidget.ui
new file mode 100644
index 000000000..7e16e3f7b
--- /dev/null
+++ b/src/assistant/help/qhelpfiltersettingswidget.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QHelpFilterSettingsWidget</class>
+ <widget class="QWidget" name="QHelpFilterSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>347</width>
+ <height>127</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" colspan="3">
+ <widget class="QLabel" name="filterLabel">
+ <property name="text">
+ <string>Filter</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="componentsLabel">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text">
+ <string>Components</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QLabel" name="versionsLabel">
+ <property name="text">
+ <string>Versions</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QListWidget" name="filterWidget"/>
+ </item>
+ <item row="1" column="3" rowspan="2">
+ <widget class="QOptionsWidget" name="componentWidget" native="true"/>
+ </item>
+ <item row="1" column="4" rowspan="2">
+ <widget class="QOptionsWidget" name="versionWidget" native="true"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QToolButton" name="addButton">
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QToolButton" name="renameButton">
+ <property name="text">
+ <string>Rename...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QToolButton" name="removeButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QOptionsWidget</class>
+ <extends>QWidget</extends>
+ <header>qoptionswidget_p.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/assistant/help/qoptionswidget.cpp b/src/assistant/help/qoptionswidget.cpp
new file mode 100644
index 000000000..21fdfe07a
--- /dev/null
+++ b/src/assistant/help/qoptionswidget.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoptionswidget_p.h"
+
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QItemDelegate>
+#include <QtWidgets/QListWidget>
+#include <QtWidgets/QVBoxLayout>
+
+QT_BEGIN_NAMESPACE
+
+class ListWidgetDelegate : public QItemDelegate
+{
+public:
+ ListWidgetDelegate(QWidget *w) : QItemDelegate(w), m_widget(w) {}
+
+ static bool isSeparator(const QModelIndex &index) {
+ return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
+ }
+ static void setSeparator(QListWidgetItem *item) {
+ item->setData(Qt::AccessibleDescriptionRole, QString::fromLatin1("separator"));
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ }
+
+protected:
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override {
+ if (isSeparator(index)) {
+ QRect rect = option.rect;
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(option.widget))
+ rect.setWidth(view->viewport()->width());
+ QStyleOption opt;
+ opt.rect = rect;
+ m_widget->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, m_widget);
+ } else {
+ QItemDelegate::paint(painter, option, index);
+ }
+ }
+
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override {
+ if (isSeparator(index)) {
+ int pm = m_widget->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, m_widget);
+ return QSize(pm, pm);
+ }
+ return QItemDelegate::sizeHint(option, index);
+ }
+private:
+ QWidget *m_widget;
+};
+
+static QStringList subtract(const QStringList &minuend, const QStringList &subtrahend)
+{
+ QStringList result = minuend;
+ for (const QString &str : subtrahend)
+ result.removeOne(str);
+ return result;
+}
+
+QOptionsWidget::QOptionsWidget(QWidget *parent)
+ : QWidget(parent)
+ , m_noOptionText(tr("No Option"))
+ , m_invalidOptionText(tr("Invalid Option"))
+{
+ m_listWidget = new QListWidget(this);
+ m_listWidget->setItemDelegate(new ListWidgetDelegate(m_listWidget));
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_listWidget);
+ layout->setContentsMargins(QMargins());
+
+ connect(m_listWidget, &QListWidget::itemChanged, this, &QOptionsWidget::itemChanged);
+}
+
+void QOptionsWidget::clear()
+{
+ setOptions(QStringList(), QStringList());
+}
+
+void QOptionsWidget::setOptions(const QStringList &validOptions,
+ const QStringList &selectedOptions)
+{
+ m_listWidget->clear();
+ m_optionToItem.clear();
+ m_itemToOption.clear();
+
+ m_validOptions = validOptions;
+ m_validOptions.removeDuplicates();
+ std::sort(m_validOptions.begin(), m_validOptions.end());
+
+ m_selectedOptions = selectedOptions;
+ m_selectedOptions.removeDuplicates();
+ std::sort(m_selectedOptions.begin(), m_selectedOptions.end());
+
+ m_invalidOptions = subtract(m_selectedOptions, m_validOptions);
+ const QStringList validSelectedOptions = subtract(m_selectedOptions, m_invalidOptions);
+ const QStringList validUnselectedOptions = subtract(m_validOptions, m_selectedOptions);
+
+ for (const QString &option : validSelectedOptions)
+ appendItem(option, true, true);
+
+ for (const QString &option : m_invalidOptions)
+ appendItem(option, false, true);
+
+ if ((validSelectedOptions.count() + m_invalidOptions.count())
+ && validUnselectedOptions.count()) {
+ appendSeparator();
+ }
+
+ for (const QString &option : validUnselectedOptions) {
+ appendItem(option, true, false);
+ if (option.isEmpty() && validUnselectedOptions.count() > 1) // special No Option item
+ appendSeparator();
+ }
+}
+
+QStringList QOptionsWidget::validOptions() const
+{
+ return m_validOptions;
+}
+
+QStringList QOptionsWidget::selectedOptions() const
+{
+ return m_selectedOptions;
+}
+
+void QOptionsWidget::setNoOptionText(const QString &text)
+{
+ if (m_noOptionText == text)
+ return;
+
+ m_noOptionText = text;
+
+ // update GUI
+ const auto itEnd = m_optionToItem.constEnd();
+ for (auto it = m_optionToItem.constBegin(); it != itEnd; ++it) {
+ const QString optionName = it.key();
+ if (optionName.isEmpty())
+ it.value()->setText(optionText(optionName, m_validOptions.contains(optionName)));
+ }
+}
+
+void QOptionsWidget::setInvalidOptionText(const QString &text)
+{
+ if (m_invalidOptionText == text)
+ return;
+
+ m_invalidOptionText = text;
+
+ // update GUI
+ for (const QString &option : m_invalidOptions)
+ m_optionToItem.value(option)->setText(optionText(option, false));
+}
+
+QString QOptionsWidget::optionText(const QString &optionName, bool valid) const
+{
+ QString text = optionName;
+ if (optionName.isEmpty())
+ text = QLatin1Char('[') + m_noOptionText + QLatin1Char(']');
+ if (!valid)
+ text += QLatin1String("\t[") + m_invalidOptionText + QLatin1Char(']');
+ return text;
+}
+
+QListWidgetItem *QOptionsWidget::appendItem(const QString &optionName, bool valid, bool selected)
+{
+ QListWidgetItem *optionItem = new QListWidgetItem(optionText(optionName, valid), m_listWidget);
+ optionItem->setCheckState(selected ? Qt::Checked : Qt::Unchecked);
+ m_listWidget->insertItem(m_listWidget->count(), optionItem);
+ m_optionToItem[optionName] = optionItem;
+ m_itemToOption[optionItem] = optionName;
+ return optionItem;
+}
+
+void QOptionsWidget::appendSeparator()
+{
+ QListWidgetItem *separatorItem = new QListWidgetItem(m_listWidget);
+ ListWidgetDelegate::setSeparator(separatorItem);
+ m_listWidget->insertItem(m_listWidget->count(), separatorItem);
+}
+
+void QOptionsWidget::itemChanged(QListWidgetItem *item)
+{
+ const auto it = m_itemToOption.constFind(item);
+ if (it == m_itemToOption.constEnd())
+ return;
+
+ const QString option = *it;
+
+ if (item->checkState() == Qt::Checked && !m_selectedOptions.contains(option)) {
+ m_selectedOptions.append(option);
+ std::sort(m_selectedOptions.begin(), m_selectedOptions.end());
+ } else if (item->checkState() == Qt::Unchecked && m_selectedOptions.contains(option)) {
+ m_selectedOptions.removeOne(option);
+ } else {
+ return;
+ }
+
+ emit optionSelectionChanged(m_selectedOptions);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/assistant/help/qoptionswidget_p.h b/src/assistant/help/qoptionswidget_p.h
new file mode 100644
index 000000000..ff075e464
--- /dev/null
+++ b/src/assistant/help/qoptionswidget_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPTIONSWIDGET_H
+#define QOPTIONSWIDGET_H
+
+#include <QtWidgets/QWidget>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+class QListWidget;
+class QListWidgetItem;
+
+class QOptionsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QOptionsWidget(QWidget *parent = nullptr);
+
+ void clear();
+ void setOptions(const QStringList &validOptions,
+ const QStringList &selectedOptions);
+ QStringList validOptions() const;
+ QStringList selectedOptions() const;
+
+ void setNoOptionText(const QString &text);
+ void setInvalidOptionText(const QString &text);
+
+signals:
+ void optionSelectionChanged(const QStringList &options);
+
+private:
+ QString optionText(const QString &optionName, bool valid) const;
+ QListWidgetItem *appendItem(const QString &optionName, bool valid, bool selected);
+ void appendSeparator();
+ void itemChanged(QListWidgetItem *item);
+
+ QListWidget *m_listWidget = nullptr;
+ QString m_noOptionText;
+ QString m_invalidOptionText;
+ QStringList m_validOptions;
+ QStringList m_invalidOptions;
+ QStringList m_selectedOptions;
+ QMap<QString, QListWidgetItem *> m_optionToItem;
+ QMap<QListWidgetItem *, QString> m_itemToOption;
+};
+
+QT_END_NAMESPACE
+
+#endif // OPTIONSWIDGET_H