File indexing completed on 2025-04-27 03:58:28

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-01-16
0007  * Description : Qt item view for images - common delegate code
0008  *
0009  * SPDX-FileCopyrightText: 2002-2005 by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText:      2009 by Andi Clemens <andi dot clemens at gmail dot com>
0011  * SPDX-FileCopyrightText: 2002-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  * SPDX-FileCopyrightText: 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "ditemdelegate.h"
0019 
0020 // C++ includes
0021 
0022 #include <cmath>
0023 
0024 // Qt includes
0025 
0026 #include <QApplication>
0027 #include <QCache>
0028 #include <QPainter>
0029 #include <QLocale>
0030 
0031 // KDE includes
0032 
0033 #include <klocalizedstring.h>
0034 
0035 // Local includes
0036 
0037 #include "itemviewcategorized.h"
0038 #include "thememanager.h"
0039 #include "thumbbardock.h"
0040 
0041 namespace Digikam
0042 {
0043 
0044 class Q_DECL_HIDDEN DItemDelegate::Private
0045 {
0046 public:
0047 
0048     explicit Private()
0049     {
0050     }
0051 
0052     QCache<QString, QPixmap> thumbnailBorderCache;
0053     QCache<QString, QString> squeezedTextCache;
0054 };
0055 
0056 DItemDelegate::DItemDelegate(QObject* const parent)
0057     : QAbstractItemDelegate(parent),
0058       d                    (new Private)
0059 {
0060 }
0061 
0062 DItemDelegate::~DItemDelegate()
0063 {
0064     delete d;
0065 }
0066 
0067 void DItemDelegate::clearCaches()
0068 {
0069     d->thumbnailBorderCache.clear();
0070     d->squeezedTextCache.clear();
0071 }
0072 
0073 QPixmap DItemDelegate::thumbnailBorderPixmap(const QSize& pixSize, bool isGrouped) const
0074 {
0075     const QColor borderColor = QColor(0, 0, 0, 128);
0076     QString cacheKey         = QString::number(pixSize.width())  + QLatin1Char('-')
0077                              + QString::number(pixSize.height()) + QLatin1Char('-')
0078                              + QString::number(isGrouped);
0079     QPixmap* const cachePix  = d->thumbnailBorderCache.object(cacheKey);
0080 
0081     if (!cachePix)
0082     {
0083         const int radius = 3;
0084         QPixmap pix;
0085         const int width  = pixSize.width()  + 2*radius;
0086         const int height = pixSize.height() + 2*radius;
0087 
0088         if (isGrouped)
0089         {
0090             pix = ThumbBarDock::generateFuzzyRectForGroup(QSize(width, height),
0091                                                           borderColor,
0092                                                           radius);
0093         }
0094         else
0095         {
0096             pix = ThumbBarDock::generateFuzzyRect(QSize(width, height),
0097                                                   borderColor,
0098                                                   radius);
0099         }
0100 
0101         d->thumbnailBorderCache.insert(cacheKey, new QPixmap(pix));
0102         return pix;
0103     }
0104 
0105     return *cachePix;
0106 }
0107 
0108 QPixmap DItemDelegate::makeDragPixmap(const QStyleOptionViewItem& option,
0109                                       const QList<QModelIndex>& indexes,
0110                                       double displayRatio,
0111                                       const QPixmap& suggestedPixmap)
0112 {
0113     int iconSize = qRound(64.0 * displayRatio);
0114     QPixmap icon = suggestedPixmap;
0115 
0116     if (icon.isNull())
0117     {
0118         icon = QPixmap(QIcon::fromTheme(QLatin1String("image-jpeg")).pixmap(32));
0119     }
0120 
0121     if (qMax(icon.width(), icon.height()) > iconSize)
0122     {
0123         icon = icon.scaled(iconSize, iconSize, Qt::KeepAspectRatio,
0124                                                Qt::SmoothTransformation);
0125     }
0126 
0127     int w                 = icon.width();
0128     int h                 = icon.height();
0129     const int borderWidth = 6;
0130 
0131     QSizeF drawSize       = QSizeF(w, h) / displayRatio;
0132     QRect  rect(0, 0, w + qRound((double)borderWidth * 2.0 * displayRatio),
0133                       h + qRound((double)borderWidth * 2.0 * displayRatio));
0134     QRect  pixmapRect(QPoint(borderWidth, borderWidth), drawSize.toSize());
0135 
0136     QPixmap pix(rect.size());
0137     pix.setDevicePixelRatio(displayRatio);
0138     QPainter p(&pix);
0139 
0140 /*
0141     // border
0142     p.fillRect(0, 0, pix.width()-1, pix.height()-1, QColor(Qt::white));
0143     p.setPen(QPen(Qt::black, 1));
0144     p.drawRect(0, 0, pix.width()-1, pix.height()-1);
0145 */
0146 
0147     QStyleOption opt(option);
0148     opt.rect = rect;
0149     qApp->style()->drawPrimitive(QStyle::PE_PanelTipLabel, &opt, &p);
0150 
0151     p.drawPixmap(pixmapRect, icon);
0152 
0153     QFont f(option.font);
0154     f.setBold(true);
0155     p.setFont(f);
0156 
0157     if (indexes.size() > 1)
0158     {
0159         QRect   textRect;
0160         QString text;
0161 
0162         QString text2(i18np("1 Image", "%1 Images", indexes.count()));
0163         QString text1 = QString::number(indexes.count());
0164         QRect r1      = p.boundingRect(pixmapRect, Qt::AlignLeft | Qt::AlignTop, text1).adjusted(0, 0, 1, 1);
0165         QRect r2      = p.boundingRect(pixmapRect, Qt::AlignLeft | Qt::AlignTop, text2).adjusted(0, 0, 1, 1);
0166 
0167         if ((r2.width() > pixmapRect.width()) || (r2.height() > pixmapRect.height()))
0168         {
0169 //            textRect     = r1;
0170             text         = text1;
0171             int rectSize = qMax(r1.width(), r1.height());
0172             textRect     = QRect(0, 0, rectSize, rectSize);
0173         }
0174         else
0175         {
0176             textRect = QRect(0, 0, r2.width(), r2.height());
0177             text     = text2;
0178         }
0179 
0180         textRect.moveLeft((pixmapRect.width() - textRect.width()) / 2 + pixmapRect.x());
0181         textRect.moveTop((pixmapRect.height() - textRect.height()) * 4 / 5);
0182         p.fillRect(textRect, QColor(0, 0, 0, 128));
0183         p.setPen(Qt::white);
0184         p.drawText(textRect, Qt::AlignCenter, text);
0185     }
0186 
0187     return pix;
0188 }
0189 
0190 QString DItemDelegate::dateToString(const QDateTime& datetime)
0191 {
0192     return QLocale().toString(datetime, QLocale::ShortFormat);
0193 }
0194 
0195 QString DItemDelegate::squeezedTextCached(QPainter* const p, int width, const QString& text) const
0196 {
0197     QCache<QString, QString>* const cache = &const_cast<DItemDelegate*>(this)->d->squeezedTextCache;
0198 
0199     // We do not need to include the font into cache key, the cache is cleared on font change
0200 
0201     QString cacheKey                      = QString::number(width) + QString::number(qHash(text));
0202     QString* const cachedString           = cache->object(cacheKey);
0203 
0204     if (cachedString)
0205     {
0206         return *cachedString;
0207     }
0208 
0209     QString result = squeezedText(p->fontMetrics(), width, text);
0210     cache->insert(cacheKey, new QString(result));
0211 
0212     return result;
0213 }
0214 
0215 QString DItemDelegate::squeezedText(const QFontMetrics& fm, int width, const QString& text)
0216 {
0217     QString fullText(text);
0218     fullText.replace(QLatin1Char('\n'), QLatin1Char(' '));
0219 
0220     return fm.elidedText(text, Qt::ElideRight, width);
0221 }
0222 
0223 } // namespace Digikam
0224 
0225 #include "moc_ditemdelegate.cpp"