File indexing completed on 2025-01-19 03:57:34

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2013-08-01
0007  * Description : Qt model view for Showfoto item - the delegate
0008  *
0009  * SPDX-FileCopyrightText: 2013      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0010  * SPDX-FileCopyrightText: 2013-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "showfotodelegate_p.h"
0017 
0018 namespace ShowFoto
0019 {
0020 
0021 void ShowfotoDelegate::ShowfotoDelegatePrivate::clearRects()
0022 {
0023     ShowfotoItemViewDelegatePrivate::clearRects();
0024     dateRect             = QRect(0, 0, 0, 0);
0025     pixmapRect           = QRect(0, 0, 0, 0);
0026     nameRect             = QRect(0, 0, 0, 0);
0027     resolutionRect       = QRect(0, 0, 0, 0);
0028     sizeRect             = QRect(0, 0, 0, 0);
0029     imageInformationRect = QRect(0, 0, 0, 0);
0030     coordinatesRect      = QRect(0, 0, 0, 0);
0031 }
0032 
0033 ShowfotoDelegate::ShowfotoDelegate(QWidget* const parent)
0034     : ShowfotoItemViewDelegate(*new ShowfotoDelegatePrivate, parent)
0035 {
0036 }
0037 
0038 ShowfotoDelegate::ShowfotoDelegate(ShowfotoDelegate::ShowfotoDelegatePrivate& dd, QWidget* const parent)
0039     : ShowfotoItemViewDelegate(dd, parent)
0040 {
0041 }
0042 
0043 ShowfotoDelegate::~ShowfotoDelegate()
0044 {
0045     Q_D(ShowfotoDelegate);
0046     Q_UNUSED(d); // To please compiler about warnings.
0047 }
0048 
0049 void ShowfotoDelegate::setView(ShowfotoThumbnailBar* view)
0050 {
0051     Q_D(ShowfotoDelegate);
0052     setViewOnAllOverlays(view);
0053 
0054     if (d->currentView)
0055     {
0056         disconnect(d->currentView, SIGNAL(modelChanged()),
0057                    this, SLOT(modelChanged()));
0058     }
0059 
0060     d->currentView = view;
0061 
0062     setModel(view ? view->model() : nullptr);
0063 
0064     if (d->currentView)
0065     {
0066         connect(d->currentView, SIGNAL(modelChanged()),
0067                 this, SLOT(modelChanged()));
0068     }
0069 }
0070 
0071 void ShowfotoDelegate::setModel(QAbstractItemModel* model)
0072 {
0073     Q_D(ShowfotoDelegate);
0074 
0075     // 1) We only need the model to invalidate model-index based caches on change
0076     // 2) We do not need to care for overlays. The view calls setActive() on them on model change
0077 
0078     if (model == d->currentModel)
0079     {
0080         return;
0081     }
0082 
0083     if (d->currentModel)
0084     {
0085         disconnect(d->currentModel, nullptr, this, nullptr);
0086     }
0087 
0088     d->currentModel = model;
0089 
0090     if (d->currentModel)
0091     {
0092         connect(d->currentModel, SIGNAL(layoutAboutToBeChanged()),
0093                 this, SLOT(modelContentsChanged()));
0094 
0095         connect(d->currentModel, SIGNAL(modelAboutToBeReset()),
0096                 this, SLOT(modelContentsChanged()));
0097 
0098         connect(d->currentModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
0099                 this, SLOT(modelContentsChanged()));
0100 
0101         connect(d->currentModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
0102                 this, SLOT(modelContentsChanged()));
0103 
0104         connect(d->currentModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0105                 this, SLOT(modelContentsChanged()));
0106     }
0107 }
0108 
0109 void ShowfotoDelegate::setSpacing(int spacing)
0110 {
0111     ShowfotoItemViewDelegate::setSpacing(spacing);
0112 }
0113 
0114 QRect ShowfotoDelegate::pixmapRect() const
0115 {
0116     Q_D(const ShowfotoDelegate);
0117 
0118     return d->pixmapRect;
0119 }
0120 
0121 QRect ShowfotoDelegate::imageInformationRect() const
0122 {
0123     Q_D(const ShowfotoDelegate);
0124 
0125     return d->imageInformationRect;
0126 }
0127 
0128 QRect ShowfotoDelegate::groupIndicatorRect() const
0129 {
0130     Q_D(const ShowfotoDelegate);
0131 
0132     return d->groupRect;
0133 }
0134 
0135 QRect ShowfotoDelegate::coordinatesIndicatorRect() const
0136 {
0137     Q_D(const ShowfotoDelegate);
0138 
0139     return d->coordinatesRect;
0140 }
0141 
0142 QPixmap ShowfotoDelegate::retrieveThumbnailPixmap(const QModelIndex& index, int thumbnailSize)
0143 {
0144     // work around constness
0145 
0146     QAbstractItemModel* const model = const_cast<QAbstractItemModel*>(index.model());
0147 
0148     // set requested thumbnail size
0149 
0150     model->setData(index, thumbnailSize, ShowfotoItemModel::ThumbnailRole);
0151 
0152     // get data from model
0153 
0154     QVariant thumbData              = index.data(ShowfotoItemModel::ThumbnailRole);
0155 
0156     return thumbData.value<QPixmap>();
0157 }
0158 
0159 QPixmap ShowfotoDelegate::thumbnailPixmap(const QModelIndex& index) const
0160 {
0161     Q_D(const ShowfotoDelegate);
0162 
0163     return retrieveThumbnailPixmap(index, d->thumbSize.size());
0164 }
0165 
0166 void ShowfotoDelegate::paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const
0167 {
0168     Q_D(const ShowfotoDelegate);
0169     ShowfotoItemInfo info     = ShowfotoItemModel::retrieveShowfotoItemInfo(index);
0170     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0171     KConfigGroup group        = config->group(QLatin1String("ImageViewer Settings"));
0172 
0173     if (info.isNull())
0174     {
0175         return;
0176     }
0177 
0178     // state of painter must not be changed
0179 
0180     p->save();
0181     p->translate(option.rect.topLeft());
0182 
0183     bool isSelected = (option.state & QStyle::State_Selected);
0184 
0185     // Thumbnail
0186 
0187     QPixmap pix;
0188 
0189     if (isSelected)
0190     {
0191         pix = d->selPixmap;
0192     }
0193     else
0194     {
0195         pix = d->regPixmap;
0196     }
0197 
0198     QRect actualPixmapRect = drawThumbnail(p, d->pixmapRect, pix, thumbnailPixmap(index));
0199 
0200     if (!actualPixmapRect.isNull())
0201     {
0202         const_cast<ShowfotoDelegate*>(this)->updateActualPixmapRect(index, actualPixmapRect);
0203     }
0204 
0205     p->setPen(isSelected ? qApp->palette().color(QPalette::HighlightedText)
0206                          : qApp->palette().color(QPalette::Text));
0207 
0208     if (!d->nameRect.isNull())
0209     {
0210         drawName(p, d->nameRect, info.name);
0211     }
0212 
0213     if (!d->dateRect.isNull())
0214     {
0215         drawCreationDate(p, d->dateRect, (info.ctime.isValid() ? info.ctime : info.dtime));
0216     }
0217 
0218     if (!d->sizeRect.isNull())
0219     {
0220         drawFileSize(p, d->sizeRect, info.size);
0221     }
0222 
0223     if (ShowfotoSettings::instance()->getShowFormatOverThumbnail())
0224     {
0225         QString frm = info.mime;
0226         drawImageFormat(p, actualPixmapRect, frm);
0227     }
0228 
0229     if (ShowfotoSettings::instance()->getShowCoordinates() && info.photoInfo.hasCoordinates)
0230     {
0231         drawGeolocationIndicator(p, d->coordinatesRect);
0232     }
0233 
0234     if (d->drawFocusFrame)
0235     {
0236         drawFocusRect(p, option, isSelected);
0237     }
0238 
0239     if (d->drawMouseOverFrame)
0240     {
0241         drawMouseOverRect(p, option);
0242     }
0243 
0244     p->restore();
0245 
0246     drawOverlays(p, option, index);
0247 }
0248 
0249 QPixmap ShowfotoDelegate::pixmapForDrag(const QStyleOptionViewItem& option,
0250                                         const QList<QModelIndex>& indexes) const
0251 {
0252     QPixmap icon;
0253 
0254     if (!indexes.isEmpty())
0255     {
0256         icon = thumbnailPixmap(indexes.first());
0257     }
0258 
0259     return makeDragPixmap(option, indexes, displayRatio(), icon);
0260 }
0261 
0262 bool ShowfotoDelegate::acceptsToolTip(const QPoint& pos, const QRect& visualRect, const QModelIndex& index,
0263                                       QRect* toolTipRect) const
0264 {
0265     return onActualPixmapRect(pos, visualRect, index, toolTipRect);
0266 }
0267 
0268 bool ShowfotoDelegate::acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index,
0269                                          QRect* activationRect) const
0270 {
0271     return onActualPixmapRect(pos, visualRect, index, activationRect);
0272 }
0273 
0274 bool ShowfotoDelegate::onActualPixmapRect(const QPoint& pos, const QRect& visualRect, const QModelIndex& index,
0275                                           QRect* returnRect) const
0276 {
0277     QRect actualRect = actualPixmapRect(index);
0278 
0279     if (actualRect.isNull())
0280     {
0281         return false;
0282     }
0283 
0284     actualRect.translate(visualRect.topLeft());
0285 
0286     if (returnRect)
0287     {
0288         *returnRect = actualRect;
0289     }
0290 
0291     return actualRect.contains(pos);
0292 }
0293 
0294 void ShowfotoDelegate::setDefaultViewOptions(const QStyleOptionViewItem& option)
0295 {
0296 
0297     ShowfotoItemViewDelegate::setDefaultViewOptions(option);
0298 }
0299 
0300 void ShowfotoDelegate::invalidatePaintingCache()
0301 {
0302     ShowfotoItemViewDelegate::invalidatePaintingCache();
0303 }
0304 
0305 void ShowfotoDelegate::updateContentWidth()
0306 {
0307     Q_D(ShowfotoDelegate);
0308     d->contentWidth = d->thumbSize.size() + 2*d->radius;
0309 }
0310 
0311 void ShowfotoDelegate::updateSizeRectsAndPixmaps()
0312 {
0313     Q_D(ShowfotoDelegate);
0314 
0315     // ---- Reset rects and prepare fonts ----
0316 
0317     d->clearRects();
0318     prepareFonts();
0319 
0320     // ---- Fixed sizes and metrics ----
0321 
0322     updateContentWidth();
0323     prepareMetrics(d->contentWidth);
0324 
0325     // ---- Calculate rects ----
0326 
0327     updateRects();
0328 
0329     // ---- Cached pixmaps ----
0330 
0331     prepareBackground();
0332 
0333     // ---- Drawing related caches ----
0334 
0335     clearCaches();
0336 }
0337 
0338 void ShowfotoDelegate::clearCaches()
0339 {
0340     Q_D(ShowfotoDelegate);
0341     ShowfotoItemViewDelegate::clearCaches();
0342     d->actualPixmapRectCache.clear();
0343 }
0344 
0345 void ShowfotoDelegate::clearModelDataCaches()
0346 {
0347     Q_D(ShowfotoDelegate);
0348     d->actualPixmapRectCache.clear();
0349 }
0350 
0351 void ShowfotoDelegate::modelChanged()
0352 {
0353     Q_D(ShowfotoDelegate);
0354     clearModelDataCaches();
0355     setModel(d->currentView ? d->currentView->model() : nullptr);
0356 }
0357 
0358 void ShowfotoDelegate::modelContentsChanged()
0359 {
0360     clearModelDataCaches();
0361 }
0362 
0363 QRect ShowfotoDelegate::actualPixmapRect(const QModelIndex& index) const
0364 {
0365     Q_D(const ShowfotoDelegate);
0366 
0367     // We do not recompute if not found. Assumption is cache is always properly updated.
0368 
0369     QRect* const rect = d->actualPixmapRectCache.object(index.row());
0370 
0371     if (rect)
0372     {
0373         return *rect;
0374     }
0375     else
0376     {
0377         return d->pixmapRect;
0378     }
0379 }
0380 
0381 void ShowfotoDelegate::updateActualPixmapRect(const QModelIndex& index, const QRect& rect)
0382 {
0383     Q_D(ShowfotoDelegate);
0384     QRect* const old = d->actualPixmapRectCache.object(index.row());
0385 
0386     if (!old || (*old != rect))
0387     {
0388         d->actualPixmapRectCache.insert(index.row(), new QRect(rect));
0389     }
0390 }
0391 
0392 int ShowfotoDelegate::calculatethumbSizeToFit(int ws)
0393 {
0394     Q_D(ShowfotoDelegate);
0395 
0396     int ts     = thumbnailSize().size();
0397     int gs     = gridSize().width();
0398     int sp     = spacing();
0399     ws         = ws - 2*sp;
0400 
0401     // Thumbnails size loop to check (upper/lower)
0402 
0403     int ts1, ts2;
0404 
0405     // New grid size used in loop
0406 
0407     int ngs;
0408 
0409     double rs1 = fmod((double)ws, (double)gs);
0410 
0411     for (ts1 = ts ; ts1 < ThumbnailSize::Huge ; ++ts1)
0412     {
0413         ngs        = ts1 + 2*(d->margin + d->radius) + sp;
0414         double nrs = fmod((double)ws, (double)ngs);
0415 
0416         if (nrs <= rs1)
0417         {
0418             rs1 = nrs;
0419         }
0420         else
0421         {
0422             break;
0423         }
0424     }
0425 
0426     double rs2 = fmod((double)ws, (double)gs);
0427 
0428     for (ts2 = ts ; ts2 > ThumbnailSize::Small ; --ts2)
0429     {
0430         ngs        = ts2 + 2*(d->margin + d->radius) + sp;
0431         double nrs = fmod((double)ws, (double)ngs);
0432 
0433         if (nrs >= rs2)
0434         {
0435             rs2 = nrs;
0436         }
0437         else
0438         {
0439             rs2 = nrs;
0440             break;
0441         }
0442     }
0443 
0444     if (rs1 > rs2)
0445     {
0446         return (ts2);
0447     }
0448 
0449     return (ts1);
0450 }
0451 
0452 // --- ShowfotoThumbnailDelegate ---------------------------------------
0453 
0454 void ShowfotoThumbnailDelegatePrivate::init(ShowfotoThumbnailDelegate* const q)
0455 {
0456     Q_UNUSED(q);
0457 }
0458 
0459 // ------------------------------------------------------------------------------------------------
0460 
0461 ShowfotoThumbnailDelegate::ShowfotoThumbnailDelegate(ShowfotoThumbnailBar* const parent)
0462     : ShowfotoDelegate(*new ShowfotoThumbnailDelegatePrivate, parent)
0463 {
0464     Q_D(ShowfotoThumbnailDelegate);
0465     d->init(this);
0466 }
0467 
0468 ShowfotoThumbnailDelegate::~ShowfotoThumbnailDelegate()
0469 {
0470 }
0471 
0472 void ShowfotoThumbnailDelegate::setFlow(QListView::Flow flow)
0473 {
0474     Q_D(ShowfotoThumbnailDelegate);
0475     d->flow = flow;
0476 }
0477 
0478 void ShowfotoThumbnailDelegate::setDefaultViewOptions(const QStyleOptionViewItem& option)
0479 {
0480     Q_D(ShowfotoThumbnailDelegate);
0481 
0482     // store before calling parent class
0483 
0484     d->viewSize = option.rect;
0485     ShowfotoDelegate::setDefaultViewOptions(option);
0486 }
0487 
0488 int ShowfotoThumbnailDelegate::maximumSize() const
0489 {
0490     Q_D(const ShowfotoThumbnailDelegate);
0491 
0492     return (ThumbnailSize::Huge + (2*d->radius + 2*d->margin));
0493 }
0494 
0495 int ShowfotoThumbnailDelegate::minimumSize() const
0496 {
0497     Q_D(const ShowfotoThumbnailDelegate);
0498 
0499     return (ThumbnailSize::Small + 2*d->radius + 2*d->margin);
0500 }
0501 
0502 bool ShowfotoThumbnailDelegate::acceptsActivation(const QPoint& pos, const QRect& visualRect,
0503                                                   const QModelIndex& index, QRect* activationRect) const
0504 {
0505     // reuse implementation from grandparent
0506 
0507     return ShowfotoItemViewDelegate::acceptsActivation(pos, visualRect, index, activationRect); // clazy:exclude=skipped-base-method
0508 }
0509 
0510 void ShowfotoThumbnailDelegate::updateContentWidth()
0511 {
0512     Q_D(ShowfotoThumbnailDelegate);
0513 
0514     int maxSize;
0515 
0516     if (d->flow == QListView::LeftToRight)
0517     {
0518         maxSize = d->viewSize.height();
0519     }
0520     else
0521     {
0522         maxSize = d->viewSize.width();
0523     }
0524 
0525     d->thumbSize = ThumbnailSize(thumbnailPixmapSize(true, maxSize - 2*d->radius - 2*d->margin));
0526 
0527     ShowfotoDelegate::updateContentWidth();
0528 }
0529 
0530 int ShowfotoThumbnailDelegate::thumbnailPixmapSize(bool withHighlight, int size)
0531 {
0532     if (withHighlight && (size >= 10))
0533     {
0534         return (size + 2);
0535     }
0536 
0537     return size;
0538 }
0539 
0540 void ShowfotoThumbnailDelegate::updateRects()
0541 {
0542     Q_D(ShowfotoThumbnailDelegate);
0543 
0544     d->pixmapRect      = QRect(d->margin, d->margin, d->contentWidth, d->contentWidth);
0545     d->rect            = QRect(0, 0, d->contentWidth + 2*d->margin, d->contentWidth + 2*d->margin);
0546     d->coordinatesRect = QRect(d->contentWidth - 16+2, d->pixmapRect.top(), 16, 16);
0547 
0548     if (d->flow == QListView::LeftToRight)
0549     {
0550         d->gridSize = QSize(d->rect.width() + d->spacing, d->rect.height());
0551     }
0552     else
0553     {
0554         d->gridSize = QSize(d->rect.width(), d->rect.height() + d->spacing);
0555     }
0556 }
0557 
0558 // --- ShowfotoNormalDelegate -----------------------------------------------------------------------
0559 
0560 void ShowfotoNormalDelegatePrivate::init(ShowfotoNormalDelegate* const q, ShowfotoThumbnailBar* const parent)
0561 {
0562 /*
0563     categoryDrawer = new ShowfotoCategoryDrawer(parent);
0564 */
0565     Q_UNUSED(parent);
0566     Q_UNUSED(q);
0567 }
0568 
0569 // ------------------------------------------------------------------------------------------------
0570 
0571 ShowfotoNormalDelegate::ShowfotoNormalDelegate(ShowfotoThumbnailBar* const bar,
0572                                                QObject* const)
0573     : ShowfotoDelegate(*new ShowfotoNormalDelegatePrivate, bar)
0574 {
0575     Q_D(ShowfotoNormalDelegate);
0576 
0577     d->init(this, bar);
0578 }
0579 
0580 ShowfotoNormalDelegate::ShowfotoNormalDelegate(ShowfotoNormalDelegatePrivate& dd,
0581                                                ShowfotoThumbnailBar* const bar,
0582                                                QObject* const)
0583     : ShowfotoDelegate(dd, bar)
0584 {
0585     Q_D(ShowfotoNormalDelegate);
0586 
0587     d->init(this, bar);
0588 }
0589 
0590 ShowfotoNormalDelegate::~ShowfotoNormalDelegate()
0591 {
0592 }
0593 
0594 void ShowfotoNormalDelegate::updateRects()
0595 {
0596     Q_D(ShowfotoNormalDelegate);
0597 
0598     int y                   = d->margin;
0599     d->pixmapRect           = QRect(d->margin, y, d->contentWidth, d->contentWidth);
0600     y                       = d->pixmapRect.bottom();
0601     d->imageInformationRect = QRect(d->margin, y, d->contentWidth, 0);
0602 
0603     d->imageInformationRect.setBottom(y);
0604 
0605     d->rect                 = QRect(0, 0, d->contentWidth + 2*d->margin, y+d->margin+d->radius);
0606     d->gridSize             = QSize(d->rect.width() + d->spacing, d->rect.height() + d->spacing);
0607 }
0608 
0609 } // namespace ShowFoto
0610 
0611 #include "moc_showfotodelegate.cpp"