File indexing completed on 2025-02-16 04:40:44
0001 /*************************************************************************** 0002 * SPDX-License-Identifier: GPL-2.0-or-later 0003 * * 0004 * SPDX-FileCopyrightText: 2004-2019 Thomas Fischer <fischer@unix-ag.uni-kl.de> 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, see <https://www.gnu.org/licenses/>. * 0018 ***************************************************************************/ 0019 0020 #include "rangewidget.h" 0021 0022 #include <QComboBox> 0023 #include <QLineEdit> 0024 #include <QBoxLayout> 0025 #include <QStringListModel> 0026 #include <QLabel> 0027 0028 #include <KLocalizedString> 0029 0030 class RangeWidget::Private 0031 { 0032 public: 0033 enum TextAlternative {LowerAlternativ, UpperAlternative}; 0034 0035 const QStringList values; 0036 int lowerValue, upperValue; 0037 QComboBox *lowerComboBox, *upperComboBox; 0038 0039 Private(const QStringList &_values, RangeWidget *parent) 0040 : values(_values), lowerValue(0), upperValue(_values.size() - 1) 0041 { 0042 Q_UNUSED(parent) 0043 0044 QBoxLayout *layout = new QHBoxLayout(parent); 0045 layout->setContentsMargins(0, 0, 0, 0); 0046 0047 lowerComboBox = new QComboBox(parent); 0048 layout->addWidget(lowerComboBox, 1, Qt::AlignCenter); 0049 lowerComboBox->setModel(new QStringListModel(lowerComboBox)); 0050 0051 QLabel *label = new QLabel(QChar(0x22ef), parent); 0052 layout->addWidget(label, 0, Qt::AlignCenter); 0053 0054 upperComboBox = new QComboBox(parent); 0055 layout->addWidget(upperComboBox, 1, Qt::AlignCenter); 0056 upperComboBox->setModel(new QStringListModel(upperComboBox)); 0057 0058 layout->addStretch(100); ///< left-align this widget's child widgets 0059 0060 adjustComboBoxes(); 0061 0062 connect(lowerComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), parent, &RangeWidget::lowerComboBoxChanged); 0063 connect(upperComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), parent, &RangeWidget::upperComboBoxChanged); 0064 } 0065 0066 QStringList stringListRange(const QStringList &originalList, int min, int max, const TextAlternative textAlternative) { 0067 if (originalList.isEmpty()) return QStringList(); 0068 0069 QStringList result; 0070 for (int i = qMin(originalList.size() - 1, qMin(max, qMax(0, min))); i <= qMin(originalList.size() - 1, qMax(min, qMax(0, max))); ++i) { 0071 const QStringList alternatives = originalList[i].split(QStringLiteral("|")); 0072 Q_ASSERT_X(alternatives.size() >= 1 && alternatives.size() <= 2, "RangeWidget::Private::stringListRange", "Either one or two alternatives must be given"); 0073 const int alternativeIndex = alternatives.size() == 1 || textAlternative == LowerAlternativ ? 0 : 1; 0074 if (!alternatives[alternativeIndex].isEmpty()) 0075 result.append(alternatives[alternativeIndex]); 0076 } 0077 0078 return result; 0079 } 0080 0081 void adjustComboBoxes() { 0082 const int minimum = 0, maximum = values.size() - 1; 0083 Q_ASSERT_X(minimum <= lowerValue, "RangeWidget::Private::adjustSpinBoxes", "minimum<=lowerValue"); 0084 Q_ASSERT_X(lowerValue <= upperValue, "RangeWidget::Private::adjustSpinBoxes", "lowerValue<=upperValue"); 0085 Q_ASSERT_X(upperValue <= maximum, "RangeWidget::Private::adjustSpinBoxes", "upperValue<=maximum"); 0086 0087 /// Disable signals being emitted when the combo boxes get updated 0088 QSignalBlocker lowerComboBoxSignalBlocker(lowerComboBox), upperComboBoxSignalBlocker(upperComboBox); 0089 0090 /// Compute a temporary QStringList containing only values from minimum to current upper value 0091 const QStringList lowerValues = stringListRange(values, minimum, upperValue, LowerAlternativ); 0092 qobject_cast<QStringListModel *>(lowerComboBox->model())->setStringList(lowerValues); 0093 lowerComboBox->setCurrentIndex(lowerValue); 0094 0095 /// Compute a temporary QStringList containing only values from current lower value to maximum 0096 const QStringList upperValues = stringListRange(values, lowerValue, maximum, UpperAlternative); 0097 qobject_cast<QStringListModel *>(upperComboBox->model())->setStringList(upperValues); 0098 upperComboBox->setCurrentIndex(upperValue - lowerValue); 0099 } 0100 }; 0101 0102 RangeWidget::RangeWidget(const QStringList &values, QWidget *parent) 0103 : QWidget(parent), d(new Private(values, this)) 0104 { 0105 /// nothing 0106 } 0107 0108 RangeWidget::~RangeWidget() 0109 { 0110 delete d; 0111 } 0112 0113 int RangeWidget::maximum() const 0114 { 0115 return d->values.size() - 1; 0116 } 0117 0118 void RangeWidget::setLowerValue(int newLowerValue) 0119 { 0120 newLowerValue = qMin(qMax(qMin(newLowerValue, d->values.size() - 1), 0), d->upperValue); 0121 if (newLowerValue != d->lowerValue) { 0122 d->lowerValue = newLowerValue; 0123 Q_EMIT lowerValueChanged(d->lowerValue); 0124 d->adjustComboBoxes(); 0125 } 0126 } 0127 0128 int RangeWidget::lowerValue() const 0129 { 0130 return d->lowerValue; 0131 } 0132 0133 void RangeWidget::setUpperValue(int newUpperValue) 0134 { 0135 newUpperValue = qMax(qMax(qMin(newUpperValue, d->values.size() - 1), 0), d->lowerValue); 0136 if (newUpperValue != d->upperValue) { 0137 d->upperValue = newUpperValue; 0138 Q_EMIT upperValueChanged(d->upperValue); 0139 d->adjustComboBoxes(); 0140 } 0141 } 0142 0143 int RangeWidget::upperValue() const 0144 { 0145 return d->upperValue; 0146 } 0147 0148 void RangeWidget::lowerComboBoxChanged(int spinboxLowerValue) 0149 { 0150 const int newLowerValue = spinboxLowerValue; 0151 if (newLowerValue != d->lowerValue) { 0152 d->lowerValue = newLowerValue; 0153 Q_EMIT lowerValueChanged(d->lowerValue); 0154 d->adjustComboBoxes(); 0155 } 0156 } 0157 0158 void RangeWidget::upperComboBoxChanged(int spinboxUpperValue) 0159 { 0160 const int newUpperValue = spinboxUpperValue + d->lowerValue; 0161 if (newUpperValue != d->upperValue) { 0162 d->upperValue = newUpperValue; 0163 Q_EMIT upperValueChanged(d->upperValue); 0164 d->adjustComboBoxes(); 0165 } 0166 }