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"