File indexing completed on 2024-04-14 04:36:10

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
0003    Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
0004    Copyright (C) 2008-2015 Jarosław Staniek <staniek@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library 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 GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "combobox.h"
0023 #include "KPropertyEditorView.h"
0024 #include "KPropertyListData.h"
0025 #include "KPropertyUtils.h"
0026 #include "KPropertyUtils_p.h"
0027 #include "KPropertyWidgetsFactory.h"
0028 #include "kproperty_debug.h"
0029 
0030 #include <QCompleter>
0031 #include <QGuiApplication>
0032 
0033 KPropertyComboBoxEditorOptions::KPropertyComboBoxEditorOptions()
0034  : extraValueAllowed(false)
0035 {
0036 }
0037 
0038 KPropertyComboBoxEditorOptions::KPropertyComboBoxEditorOptions(
0039     const KPropertyComboBoxEditorOptions &other)
0040 {
0041     *this = other;
0042 }
0043 
0044 KPropertyComboBoxEditorOptions::~KPropertyComboBoxEditorOptions()
0045 {
0046     delete iconProvider;
0047 }
0048 
0049 KPropertyComboBoxEditorOptions& KPropertyComboBoxEditorOptions::operator=(const KPropertyComboBoxEditorOptions &other)
0050 {
0051     if (this != &other) {
0052         if (other.iconProvider) {
0053             iconProvider = other.iconProvider->clone();
0054         } else {
0055             delete iconProvider;
0056             iconProvider = nullptr;
0057         }
0058         extraValueAllowed = other.extraValueAllowed;
0059     }
0060     return *this;
0061 }
0062 
0063 
0064 class Q_DECL_HIDDEN KPropertyComboBoxEditor::Private
0065 {
0066 public:
0067     Private()
0068     {
0069     }
0070     ~Private()
0071     {
0072         delete completer;
0073     }
0074     KPropertyListData listData;
0075     bool setValueEnabled = true;
0076     KPropertyComboBoxEditorOptions options;
0077     QCompleter *completer = nullptr;
0078 };
0079 
0080 KPropertyComboBoxEditor::KPropertyComboBoxEditor(const KPropertyListData &listData,
0081                                                  const KPropertyComboBoxEditorOptions &options,
0082                                                  QWidget *parent)
0083     : QComboBox(parent), d(new Private)
0084 {
0085     d->options = options;
0086     setEditable(d->options.extraValueAllowed);
0087     setInsertPolicy(QComboBox::NoInsert);
0088     setAutoCompletion(true);
0089     setContextMenuPolicy(Qt::NoContextMenu);
0090     setListData(listData);
0091     connect(this, SIGNAL(activated(int)), this, SLOT(slotValueChanged(int)));
0092 
0093     int paddingTop = 2;
0094     int paddingLeft = 3;
0095     const QString style(parent->style()->objectName());
0096     if (!KPropertyUtilsPrivate::gridLineColor(this).isValid()) {
0097         setFrame(false);
0098         paddingTop = 0;
0099     }
0100     if (style == QLatin1String("windowsvista") || style == QLatin1String("fusion")) {
0101         paddingLeft = 2;
0102     }
0103 
0104     //Set the stylesheet to a plain style
0105     QString styleSheet = QString::fromLatin1("QComboBox { \
0106         %1 \
0107         padding-top: %2px; padding-left: %3px; }").arg(borderSheet(this)).arg(paddingTop).arg(paddingLeft);
0108     setStyleSheet(styleSheet);
0109 }
0110 
0111 KPropertyComboBoxEditor::~KPropertyComboBoxEditor()
0112 {
0113     delete d;
0114 }
0115 
0116 //static
0117 QString KPropertyComboBoxEditor::borderSheet(const QWidget *widget)
0118 {
0119     Q_ASSERT(widget);
0120     const QString style(widget->parentWidget() ? widget->parentWidget()->style()->objectName() : QString());
0121     if (style == QLatin1String("windowsvista") // a hack
0122         || style == QLatin1String("fusion"))
0123     {
0124         return QString();
0125     }
0126     return QLatin1String("border: 0px; ");
0127 }
0128 
0129 bool KPropertyComboBoxEditor::listDataKeysAvailable() const
0130 {
0131     return !d->listData.keys().isEmpty();
0132 }
0133 
0134 QVariant KPropertyComboBoxEditor::value() const
0135 {
0136     if (!listDataKeysAvailable())
0137         return QVariant();
0138 
0139     const int idx = currentIndex();
0140     if (idx < 0 || idx >= d->listData.keys().count()
0141         || d->listData.names()[idx].toString() != currentText().trimmed())
0142     {
0143         if (!d->options.extraValueAllowed || currentText().isEmpty())
0144             return QVariant();
0145         return currentText().trimmed(); //trimmed 4 safety
0146     }
0147     return d->listData.keys()[idx];
0148 }
0149 
0150 void KPropertyComboBoxEditor::setValue(const QVariant &value)
0151 {
0152     if (!d->setValueEnabled)
0153         return;
0154     const int idx = d->listData.keys().isEmpty() ? -1 : d->listData.keys().indexOf(value);
0155 //    kprDebug() << "**********" << idx << "" << value.toString();
0156     if (idx >= 0 && idx < count()) {
0157         setCurrentIndex(idx);
0158     }
0159     else {
0160         if (idx < 0) {
0161             if (d->options.extraValueAllowed) {
0162                 setCurrentIndex(-1);
0163                 setEditText(value.toString());
0164             }
0165             kprWarning() << "NO SUCH KEY:" << value.toString()
0166                 << "property=" << objectName();
0167         } else {
0168             QStringList list;
0169             for (int i = 0; i < count(); i++)
0170                 list += itemText(i);
0171             kprWarning() << "NO SUCH INDEX WITHIN COMBOBOX:" << idx
0172                 << "count=" << count() << "value=" << value.toString()
0173                 << "property=" << objectName() << "\nActual combobox contents"
0174                 << list;
0175         }
0176         setItemText(currentIndex(), QString());
0177     }
0178 }
0179 
0180 void KPropertyComboBoxEditor::fillValues()
0181 {
0182     delete d->completer;
0183     clear();
0184     if (!listDataKeysAvailable())
0185         return;
0186 
0187     int index = 0;
0188     for (const QString &itemName : d->listData.namesAsStringList()) {
0189         addItem(itemName);
0190         if (d->options.iconProvider) {
0191             QIcon icon = d->options.iconProvider->icon(index);
0192             setItemIcon(index, icon);
0193         }
0194         index++;
0195     }
0196     if (isEditable()) {
0197         d->completer = new QCompleter(d->listData.namesAsStringList());
0198         d->completer->setWidget(this);
0199     }
0200 }
0201 
0202 void KPropertyComboBoxEditor::setListData(const KPropertyListData & listData)
0203 {
0204     d->listData = listData;
0205     fillValues();
0206 }
0207 
0208 void KPropertyComboBoxEditor::slotValueChanged(int)
0209 {
0210     emit commitData( this );
0211 }
0212 
0213 void KPropertyComboBoxEditor::paintEvent( QPaintEvent * event )
0214 {
0215     QComboBox::paintEvent(event);
0216     KPropertyWidgetsFactory::paintTopGridLine(this);
0217 }
0218 
0219 //-----------------------
0220 
0221 KPropertyComboBoxDelegate::KPropertyComboBoxDelegate()
0222 {
0223     options()->setBordersVisible(true);
0224 }
0225 
0226 QString KPropertyComboBoxDelegate::propertyValueToString(const KProperty* property, const QLocale &locale) const
0227 {
0228     Q_UNUSED(locale)
0229     KPropertyListData *listData = property->listData();
0230     if (!listData)
0231         return property->value().toString();
0232     if (property->value().isNull())
0233         return QString();
0234     //kprDebug() << "property->value()==" << property->value();
0235     const int idx = listData->keys().indexOf(property->value());
0236     //kprDebug() << "idx==" << idx;
0237     if (idx == -1) {
0238       if (!property->option("extraValueAllowed").toBool())
0239         return QString();
0240       else
0241         return property->value().toString();
0242     }
0243     return property->listData()->names()[idx].toString();
0244 }
0245 
0246 QString KPropertyComboBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const
0247 {
0248     Q_UNUSED(locale)
0249     return value.toString();
0250 }
0251 
0252 QWidget* KPropertyComboBoxDelegate::createEditor( int type, QWidget *parent,
0253     const QStyleOptionViewItem & option, const QModelIndex & index ) const
0254 {
0255     Q_UNUSED(type);
0256     Q_UNUSED(option);
0257 
0258     KProperty *property = KPropertyUtils::propertyForIndex(index);
0259     if (!property) {
0260         return nullptr;
0261     }
0262     KPropertyComboBoxEditorOptions options;
0263     options.extraValueAllowed = property->option("extraValueAllowed", false).toBool();
0264     KPropertyComboBoxEditor *cb = new KPropertyComboBoxEditor(*property->listData(), options, parent);
0265     return cb;
0266 }