summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2019-11-29 10:35:49 +0100
committerJarek Kobus <jaroslaw.kobus@qt.io>2020-01-09 14:23:47 +0100
commit13dbd946a3325855c23b16b0864c88d87c914c85 (patch)
tree9501f167e520241b41c6b91f517953ae30bc15ad
parent9e6943370585bdc791caae6c83555b3aa5efe063 (diff)
QtHelp: Add filter settings struct and editor for it
Adds the QHelpFilterSettings class, describing all the available filter details. Adds the QHelpFilterSettingsWidget class, serving as an editor for all available filter. It also provides methods for storing and retrieving filter details into / from the help settings. Change-Id: Ie87578fc30d8114b95508f5b761e7914447c247a Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-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