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"