diff options
Diffstat (limited to 'src/assistant/help/qoptionswidget.cpp')
-rw-r--r-- | src/assistant/help/qoptionswidget.cpp | 229 |
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 |