File indexing completed on 2025-01-19 03:56:15
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-07-15 0007 * Description : Item delegate for image versions list view 0008 * 0009 * SPDX-FileCopyrightText: 2010-2011 by Martin Klapetek <martin dot klapetek at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "versionsdelegate.h" 0016 0017 // Qt includes 0018 0019 #include <QApplication> 0020 #include <QPainter> 0021 #include <QPropertyAnimation> 0022 #include <QStyle> 0023 #include <QStyleOptionViewItem> 0024 0025 // KDE includes 0026 0027 #include <klocalizedstring.h> 0028 0029 // Local includes 0030 0031 #include "digikam_debug.h" 0032 #include "itemdelegate.h" 0033 #include "itemhistorygraphmodel.h" 0034 #include "itemversionsmodel.h" 0035 #include "thumbnailloadthread.h" 0036 #include "dcategorydrawer.h" 0037 #include "dlayoutbox.h" 0038 #include "dworkingpixmap.h" 0039 0040 namespace Digikam 0041 { 0042 0043 class Q_DECL_HIDDEN VersionsDelegate::Private 0044 { 0045 public: 0046 0047 explicit Private() 0048 : categoryExtraSpacing (6), 0049 filterItemExtraSpacing(4), 0050 animationState (0), 0051 animation (nullptr), 0052 workingPixmap (nullptr), 0053 categoryDrawer (nullptr), 0054 thumbnailSize (64), 0055 thumbsWaitingFor (0), 0056 inSizeHint (false) 0057 { 0058 } 0059 0060 const int categoryExtraSpacing; 0061 const int filterItemExtraSpacing; 0062 0063 int animationState; 0064 QPropertyAnimation* animation; 0065 DWorkingPixmap* workingPixmap; 0066 DCategoryDrawer* categoryDrawer; 0067 int thumbnailSize; 0068 0069 int thumbsWaitingFor; 0070 bool inSizeHint; 0071 0072 public: 0073 0074 inline const QWidget* widget(const QStyleOptionViewItem& option) 0075 { 0076 if (const QStyleOptionViewItem* v3 = qstyleoption_cast<const QStyleOptionViewItem*>(&option)) 0077 { 0078 return v3->widget; 0079 } 0080 0081 return nullptr; 0082 } 0083 0084 inline const QStyle* style(const QStyleOptionViewItem& option) 0085 { 0086 const QWidget* w = widget(option); 0087 0088 return (w ? w->style() : QApplication::style()); 0089 } 0090 }; 0091 0092 VersionsDelegate::VersionsDelegate(QObject* const parent) 0093 : QStyledItemDelegate(parent), 0094 d (new Private) 0095 { 0096 d->workingPixmap = new DWorkingPixmap(this); 0097 d->categoryDrawer = new DCategoryDrawer(nullptr); 0098 d->animation = new QPropertyAnimation(this, "animationState", this); 0099 d->animation->setStartValue(0); 0100 d->animation->setEndValue(d->workingPixmap->frameCount() - 1); 0101 d->animation->setDuration(100 * d->workingPixmap->frameCount()); 0102 d->animation->setLoopCount(-1); 0103 } 0104 0105 VersionsDelegate::~VersionsDelegate() 0106 { 0107 delete d->categoryDrawer; 0108 delete d; 0109 } 0110 0111 int VersionsDelegate::animationState() const 0112 { 0113 return d->animationState; 0114 } 0115 0116 void VersionsDelegate::setAnimationState(int animationState) 0117 { 0118 if (d->animationState == animationState) 0119 { 0120 return; 0121 } 0122 0123 d->animationState = animationState; 0124 Q_EMIT animationStateChanged(); 0125 } 0126 0127 void VersionsDelegate::setThumbnailSize(int size) const 0128 { 0129 d->thumbnailSize = size; 0130 } 0131 0132 int VersionsDelegate::thumbnailSize() const 0133 { 0134 return d->thumbnailSize; 0135 } 0136 0137 void VersionsDelegate::beginPainting() 0138 { 0139 d->thumbsWaitingFor = 0; 0140 } 0141 0142 void VersionsDelegate::finishPainting() 0143 { 0144 /* 0145 qCDebug(DIGIKAM_GENERAL_LOG) << "painting finished" << d->thumbsWaitingFor; 0146 */ 0147 if (d->thumbsWaitingFor) 0148 { 0149 d->animation->start(); 0150 } 0151 else 0152 { 0153 d->animation->stop(); 0154 } 0155 } 0156 0157 QSize VersionsDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const 0158 { 0159 if (index.data(ItemHistoryGraphModel::IsImageItemRole).toBool()) 0160 { 0161 d->inSizeHint = true; 0162 QSize size = QStyledItemDelegate::sizeHint(option, index); 0163 d->inSizeHint = false; 0164 0165 return size; 0166 } 0167 else if (index.data(ItemHistoryGraphModel::IsFilterActionItemRole).toBool()) 0168 { 0169 QSize size = QStyledItemDelegate::sizeHint(option, index); 0170 size += QSize(0, d->filterItemExtraSpacing); 0171 0172 return size; 0173 } 0174 else if (index.data(ItemHistoryGraphModel::IsCategoryItemRole).toBool()) 0175 { 0176 int height = d->categoryDrawer->categoryHeight(index, option) + d->categoryExtraSpacing; 0177 QSize size = QStyledItemDelegate::sizeHint(option, index); 0178 0179 return size.expandedTo(QSize(0, height)); 0180 } 0181 else if (index.data(ItemHistoryGraphModel::IsSeparatorItemRole).toBool()) 0182 { 0183 //int pm = d->style(option)->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, d->widget(option)); 0184 int pm = d->style(option)->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, d->widget(option)); 0185 //int spacing = d->style(option)->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option); 0186 0187 return QSize(1, pm); 0188 } 0189 else 0190 { 0191 return QStyledItemDelegate::sizeHint(option, index); 0192 } 0193 } 0194 0195 void VersionsDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0196 { 0197 if (index.data(ItemHistoryGraphModel::IsCategoryItemRole).toBool()) 0198 { 0199 QStyleOption opt = option; 0200 opt.rect.adjust(d->categoryExtraSpacing / 2, d->categoryExtraSpacing / 2, - d->categoryExtraSpacing / 2, 0); 0201 0202 // purpose of sortRole is unclear, give Qt::DisplayRole 0203 0204 d->categoryDrawer->drawCategory(index, Qt::DisplayRole, opt, painter); 0205 } 0206 else if (index.data(ItemHistoryGraphModel::IsSeparatorItemRole).toBool()) 0207 { 0208 d->style(option)->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &option, painter, d->widget(option)); 0209 } 0210 else 0211 { 0212 QStyledItemDelegate::paint(painter, option, index); 0213 return; 0214 /* 0215 if (index.data(ItemHistoryGraphModel::IsSubjectImageRole).toBool()) 0216 { 0217 // draw 1px border 0218 QPen oldPen = painter->pen(); 0219 QPen pen(option.palette.windowText(), 0); 0220 painter->setPen(pen); 0221 painter->drawRect(option.rect); 0222 painter->setPen(oldPen); 0223 } 0224 */ 0225 } 0226 } 0227 0228 void VersionsDelegate::initStyleOption(QStyleOptionViewItem* option, const QModelIndex& index) const 0229 { 0230 QStyledItemDelegate::initStyleOption(option, index); 0231 0232 // Don't show the separator-like focus indicator 0233 0234 option->state &= ~QStyle::State_HasFocus; 0235 0236 if (!index.data(ItemHistoryGraphModel::IsImageItemRole).toBool()) 0237 { 0238 return; 0239 } 0240 /* 0241 if (index.data(ItemHistoryGraphModel::IsSubjectImageRole).toBool()) 0242 { 0243 option->font.setWeight(QFont::Bold); 0244 } 0245 */ 0246 option->font.setWeight(QFont::Bold); 0247 0248 if (QStyleOptionViewItem* const v4 = qstyleoption_cast<QStyleOptionViewItem*>(option)) 0249 { 0250 v4->features |= QStyleOptionViewItem::HasDecoration; 0251 0252 if (d->inSizeHint) 0253 { 0254 v4->decorationSize = QSize(d->thumbnailSize, d->thumbnailSize); 0255 } 0256 else 0257 { 0258 QPixmap pix = ItemDelegate::retrieveThumbnailPixmap(index, d->thumbnailSize); 0259 0260 if (pix.isNull()) 0261 { 0262 pix = d->workingPixmap->frameAt(d->animationState); 0263 d->thumbsWaitingFor++; 0264 } 0265 0266 v4->icon = QIcon(pix); 0267 v4->decorationSize = pix.size(); 0268 } 0269 } 0270 } 0271 0272 /* 0273 void VersionsDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0274 { 0275 painter->save(); 0276 painter->setRenderHint(QPainter::Antialiasing, true); 0277 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter); 0278 //qCDebug(DIGIKAM_GENERAL_LOG) << QApplication::style()->subElementRect(QStyle::SE_ItemViewItemDecoration, &option, 0); 0279 0280 if (dynamic_cast<const ItemVersionsModel*>(index.model())->paintTree()) 0281 { 0282 const_cast<QStyleOptionViewItem&>(option).rect.setLeft(option.rect.left() + (index.data(Qt::UserRole).toInt() * 16)); 0283 } 0284 0285 QRect thumbRect(option.rect.left()+4, option.rect.top()+8, 64, 48); 0286 painter->setPen(Qt::black); 0287 painter->drawRect(thumbRect); 0288 0289 QPixmap thumbnail; 0290 0291 if (ThumbnailLoadThread::defaultIconViewThread()->find(index.data(Qt::DisplayRole).toString(), thumbnail)) 0292 { 0293 if (!thumbnail.isNull()) 0294 { 0295 thumbnail = thumbnail.scaled(64, 48, Qt::KeepAspectRatio); 0296 const_cast<VersionsDelegate*>(this)->d->thumbsPainted++; 0297 } 0298 else 0299 { 0300 //if the thumbnail pixmap is null, display an error icon instead 0301 thumbnail = BarIcon("task-reject"); 0302 } 0303 0304 if (d->thumbsPainted == index.model()->rowCount()) 0305 { 0306 // the timer can be stopped after last thumbnail is drawn, 0307 // but it needs to be delayed a little, so that all thumbs 0308 // have enough time to get painted correctly 0309 delayedAnimationTimerStop(); 0310 0311 } 0312 } 0313 else 0314 { 0315 //when the thumbnail is not loaded yet, start the animation 0316 d->workingWidget->toggleTimer(true); 0317 0318 connect(d->workingWidget, SIGNAL(animationStep()), 0319 dynamic_cast<const ItemVersionsModel*>(index.model()), SLOT(slotAnimationStep())); 0320 0321 thumbnail = QPixmap::grabWidget(d->workingWidget); 0322 } 0323 0324 painter->drawPixmap(thumbRect.left()+(32-(int)(thumbnail.width()/2)), thumbRect.top()+(24-(int)(thumbnail.height()/2)), thumbnail); 0325 0326 QRect textRect = option.rect; 0327 textRect.setLeft(textRect.left() + 72); 0328 QUrl path(index.data(Qt::DisplayRole).toString()); 0329 0330 if (index.row() == 0 && index.model()->rowCount() > 1) 0331 { 0332 painter->drawText(textRect, Qt::AlignVCenter, i18n("%1 (Original)", path.fileName())); 0333 } 0334 else if (index.row() == 0 && index.model()->rowCount() == 1) 0335 { 0336 painter->drawText(textRect, Qt::AlignVCenter, i18n("This is the original image")); 0337 } 0338 else 0339 { 0340 painter->drawText(textRect, Qt::AlignVCenter, path.fileName()); 0341 } 0342 0343 painter->restore(); 0344 } 0345 */ 0346 0347 } // namespace Digikam 0348 0349 #include "moc_versionsdelegate.cpp"