summaryrefslogtreecommitdiffstats
path: root/src/assistant/help/qoptionswidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/assistant/help/qoptionswidget.cpp')
-rw-r--r--src/assistant/help/qoptionswidget.cpp229
1 files changed, 229 insertions, 0 deletions
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