File indexing completed on 2025-12-07 04:08:18

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-08-21
0007  * Description : a combo box with a width not depending of text
0008  *               content size
0009  *
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText:      2008 by Andi Clemens <andi dot clemens at googlemail dot com>
0012  * SPDX-FileCopyrightText:      2005 by Tom Albers <tomalbers at kde dot nl>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "squeezedcombobox.h"
0019 
0020 // Qt includes
0021 
0022 #include <QTimer>
0023 #include <QStyle>
0024 #include <QApplication>
0025 #include <QResizeEvent>
0026 
0027 namespace Digikam
0028 {
0029 
0030 class Q_DECL_HIDDEN SqueezedComboBox::Private
0031 {
0032 public:
0033 
0034     explicit Private()
0035       : timer(nullptr)
0036     {
0037     }
0038 
0039     QMap<int, QString> originalItems;
0040 
0041     QTimer*            timer;
0042 };
0043 
0044 SqueezedComboBox::SqueezedComboBox(QWidget* const parent, const char* name)
0045     : QComboBox(parent),
0046       d        (new Private)
0047 {
0048     setObjectName(QString::fromUtf8(name));
0049     setMinimumWidth(100);
0050 
0051     d->timer = new QTimer(this);
0052     d->timer->setSingleShot(true);
0053 
0054     connect(d->timer, &QTimer::timeout,
0055             this, &SqueezedComboBox::slotTimeOut);
0056 
0057     connect(this, static_cast<void (SqueezedComboBox::*)(int)>(&SqueezedComboBox::activated),
0058             this, &SqueezedComboBox::slotUpdateToolTip);
0059 }
0060 
0061 SqueezedComboBox::~SqueezedComboBox()
0062 {
0063     d->originalItems.clear();
0064     delete d->timer;
0065     delete d;
0066 }
0067 
0068 bool SqueezedComboBox::contains(const QString& text) const
0069 {
0070     if (text.isEmpty())
0071     {
0072         return false;
0073     }
0074 
0075     for (QMap<int, QString>::const_iterator it = d->originalItems.constBegin() ;
0076          it != d->originalItems.constEnd() ; ++it)
0077     {
0078         if (it.value() == text)
0079         {
0080             return true;
0081         }
0082     }
0083 
0084     return false;
0085 }
0086 
0087 int SqueezedComboBox::findOriginalText(const QString& text,
0088                                        Qt::CaseSensitivity cs) const
0089 {
0090     if (text.isEmpty())
0091     {
0092         return -1;
0093     }
0094 
0095     for (QMap<int, QString>::const_iterator it = d->originalItems.constBegin() ;
0096          it != d->originalItems.constEnd() ; ++it)
0097     {
0098         if (it.value().compare(text, cs) == 0)
0099         {
0100             return it.key();
0101         }
0102     }
0103 
0104     return -1;
0105 }
0106 
0107 QSize SqueezedComboBox::sizeHint() const
0108 {
0109     ensurePolished();
0110     QFontMetrics fm = fontMetrics();
0111     int maxW        = count() ? 18 : 7 * fm.horizontalAdvance(QLatin1Char('x')) + 18;
0112     int maxH        = qMax(fm.lineSpacing(), 14) + 2;
0113 
0114     QStyleOptionComboBox options;
0115     options.initFrom(this);
0116 
0117     return style()->sizeFromContents(QStyle::CT_ComboBox, &options, QSize(maxW, maxH), this);
0118 }
0119 
0120 void SqueezedComboBox::insertSqueezedItem(const QString& newItem, int index,
0121                                           const QVariant& userData)
0122 {
0123     d->originalItems[index] = newItem;
0124     QComboBox::insertItem(index, squeezeText(newItem), userData);
0125 
0126     // if this is the first item, set the tooltip.
0127 
0128     if (index == 0)
0129     {
0130         slotUpdateToolTip(0);
0131     }
0132 }
0133 
0134 void SqueezedComboBox::insertSqueezedList(const QStringList& newItems, int index)
0135 {
0136     for (QStringList::const_iterator it = newItems.constBegin() ;
0137          it != newItems.constEnd() ; ++it)
0138     {
0139         insertSqueezedItem(*it, index);
0140         ++index;
0141     }
0142 }
0143 
0144 void SqueezedComboBox::addSqueezedItem(const QString& newItem,
0145                                        const QVariant& userData)
0146 {
0147     insertSqueezedItem(newItem, count(), userData);
0148 }
0149 
0150 void SqueezedComboBox::setCurrent(const QString& itemText)
0151 {
0152     QString squeezedText = squeezeText(itemText);
0153     qint32 itemIndex     = findText(squeezedText);
0154 
0155     if (itemIndex >= 0)
0156     {
0157         setCurrentIndex(itemIndex);
0158     }
0159 }
0160 
0161 void SqueezedComboBox::resizeEvent(QResizeEvent *)
0162 {
0163     d->timer->start(200);
0164 }
0165 
0166 void SqueezedComboBox::slotTimeOut()
0167 {
0168     for (QMap<int, QString>::iterator it = d->originalItems.begin() ;
0169          it != d->originalItems.end() ; ++it)
0170     {
0171         setItemText(it.key(), squeezeText(it.value()));
0172     }
0173 }
0174 
0175 QString SqueezedComboBox::squeezeText(const QString& original) const
0176 {
0177     // not the complete widgetSize is usable. Need to compensate for that.
0178 
0179     int widgetSize = width() - 30;
0180     QFontMetrics fm(fontMetrics());
0181 
0182     // If we can fit the full text, return that.
0183 
0184     if (fm.horizontalAdvance(original) < widgetSize)
0185     {
0186         return (original);
0187     }
0188 
0189     // We need to squeeze.
0190 
0191     QString sqItem = original; // prevent empty return value;
0192     widgetSize     = widgetSize-fm.horizontalAdvance(QLatin1String("..."));
0193 
0194     for (int i = 0 ; i != original.length() ; ++i)
0195     {
0196         if ((int)fm.horizontalAdvance(original.right(i)) > widgetSize)
0197         {
0198             sqItem = QString(original.left(i) + QLatin1String("..."));
0199             break;
0200         }
0201     }
0202 
0203     return sqItem;
0204 }
0205 
0206 void SqueezedComboBox::slotUpdateToolTip(int index)
0207 {
0208      setToolTip(d->originalItems[index]);
0209 
0210      Q_EMIT signalItemActivated(item(index));
0211 }
0212 
0213 QString SqueezedComboBox::itemHighlighted() const
0214 {
0215     int curItem = currentIndex();
0216 
0217     return d->originalItems[curItem];
0218 }
0219 
0220 QString SqueezedComboBox::item(int index) const
0221 {
0222     return d->originalItems[index];
0223 }
0224 
0225 } // namespace Digikam
0226 
0227 #include "moc_squeezedcombobox.cpp"