File indexing completed on 2025-01-19 03:50:38
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-04-20 0007 * Description : Qt model-view for items - category drawer 0008 * 0009 * SPDX-FileCopyrightText: 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2011 by Andi Clemens <andi dot clemens at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "itemcategorydrawer.h" 0017 0018 // Qt includes 0019 0020 #include <QPainter> 0021 #include <QApplication> 0022 #include <QLocale> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "album.h" 0031 #include "albummanager.h" 0032 #include "itemalbummodel.h" 0033 #include "itemcategorizedview.h" 0034 #include "itemdelegate.h" 0035 #include "itemfiltermodel.h" 0036 #include "itemmodel.h" 0037 #include "itemscanner.h" 0038 #include "searchfolderview.h" 0039 #include "facetagsiface.h" 0040 0041 namespace Digikam 0042 { 0043 0044 class Q_DECL_HIDDEN ItemCategoryDrawer::Private 0045 { 0046 public: 0047 0048 explicit Private() 0049 : lowerSpacing(0), 0050 view (nullptr) 0051 { 0052 } 0053 0054 QFont font; 0055 QRect rect; 0056 QPixmap pixmap; 0057 int lowerSpacing; 0058 ItemCategorizedView* view; 0059 }; 0060 0061 ItemCategoryDrawer::ItemCategoryDrawer(ItemCategorizedView* const parent) 0062 : DCategoryDrawer(nullptr), 0063 d (new Private) 0064 { 0065 d->view = parent; 0066 } 0067 0068 ItemCategoryDrawer::~ItemCategoryDrawer() 0069 { 0070 delete d; 0071 } 0072 0073 int ItemCategoryDrawer::categoryHeight(const QModelIndex& /*index*/, const QStyleOption& /*option*/) const 0074 { 0075 return (d->rect.height() + d->lowerSpacing); 0076 } 0077 0078 int ItemCategoryDrawer::maximumHeight() const 0079 { 0080 return (d->rect.height() + d->lowerSpacing); 0081 } 0082 0083 void ItemCategoryDrawer::setLowerSpacing(int spacing) 0084 { 0085 d->lowerSpacing = spacing; 0086 } 0087 0088 void ItemCategoryDrawer::setDefaultViewOptions(const QStyleOptionViewItem& option) 0089 { 0090 d->font = option.font; 0091 0092 if (option.rect.width() != d->rect.width()) 0093 { 0094 updateRectsAndPixmaps(option.rect.width()); 0095 } 0096 } 0097 0098 void ItemCategoryDrawer::invalidatePaintingCache() 0099 { 0100 if (d->rect.isNull()) 0101 { 0102 return; 0103 } 0104 0105 updateRectsAndPixmaps(d->rect.width()); 0106 } 0107 0108 void ItemCategoryDrawer::drawCategory(const QModelIndex& index, int /*sortRole*/, 0109 const QStyleOption& option, QPainter* p) const 0110 { 0111 if (option.rect.width() != d->rect.width()) 0112 { 0113 const_cast<ItemCategoryDrawer*>(this)->updateRectsAndPixmaps(option.rect.width()); 0114 } 0115 0116 p->save(); 0117 0118 p->translate(option.rect.topLeft()); 0119 0120 ItemSortSettings::CategorizationMode mode = (ItemSortSettings::CategorizationMode)index.data(ItemFilterModel::CategorizationModeRole).toInt(); 0121 0122 p->drawPixmap(0, 0, d->pixmap); 0123 0124 QFont fontBold(d->font); 0125 QFont fontNormal(d->font); 0126 fontBold.setBold(true); 0127 int fnSize = fontBold.pointSize(); 0128 0129 if (fnSize > 0) 0130 { 0131 fontBold.setPointSize(fnSize+2); 0132 } 0133 else 0134 { 0135 fnSize = fontBold.pixelSize(); 0136 fontBold.setPixelSize(fnSize+2); 0137 } 0138 0139 QString header; 0140 QString subLine; 0141 0142 switch (mode) 0143 { 0144 case ItemSortSettings::NoCategories: 0145 break; 0146 0147 case ItemSortSettings::OneCategory: 0148 viewHeaderText(index, &header, &subLine); 0149 break; 0150 0151 case ItemSortSettings::CategoryByAlbum: 0152 textForAlbum(index, &header, &subLine); 0153 break; 0154 0155 case ItemSortSettings::CategoryByFormat: 0156 textForFormat(index, &header, &subLine); 0157 break; 0158 0159 case ItemSortSettings::CategoryByMonth: 0160 textForMonth(index, &header, &subLine); 0161 break; 0162 0163 case ItemSortSettings::CategoryByFaces: 0164 textForFace(index, &header, &subLine); 0165 break; 0166 } 0167 0168 p->setPen(qApp->palette().color(QPalette::HighlightedText)); 0169 p->setFont(fontBold); 0170 0171 QRect tr; 0172 p->drawText(5, 5, d->rect.width(), d->rect.height(), 0173 Qt::AlignLeft | Qt::AlignTop, 0174 p->fontMetrics().elidedText(header, Qt::ElideRight, d->rect.width() - 10), &tr); 0175 0176 int y = tr.height() + 2; 0177 0178 p->setFont(fontNormal); 0179 0180 p->drawText(5, y, d->rect.width(), d->rect.height() - y, 0181 Qt::AlignLeft | Qt::AlignVCenter, 0182 p->fontMetrics().elidedText(subLine, Qt::ElideRight, d->rect.width() - 10)); 0183 0184 p->restore(); 0185 } 0186 0187 void ItemCategoryDrawer::viewHeaderText(const QModelIndex& index, QString* header, QString* subLine) const 0188 { 0189 ItemModel* const sourceModel = index.data(ItemModel::ItemModelPointerRole).value<ItemModel*>(); 0190 0191 if (!sourceModel) 0192 { 0193 return; 0194 } 0195 0196 int count = d->view->categoryRange(index).height(); 0197 0198 // Add here further model subclasses in use with ItemCategoryDrawer. 0199 // Note you need a Q_OBJECT in the class's header for this to work. 0200 0201 ItemAlbumModel* const albumModel = qobject_cast<ItemAlbumModel*>(sourceModel); 0202 0203 if (albumModel) 0204 { 0205 QList<Album*> albums = albumModel->currentAlbums(); 0206 Album* album = nullptr; 0207 0208 if (albums.isEmpty()) 0209 { 0210 return; 0211 } 0212 0213 album = albums.first(); 0214 0215 if (!album) 0216 { 0217 return; 0218 } 0219 0220 switch (album->type()) 0221 { 0222 case Album::PHYSICAL: 0223 textForPAlbum(static_cast<PAlbum*>(album), albumModel->isRecursingAlbums(), count, header, subLine); 0224 break; 0225 0226 case Album::TAG: 0227 textForTAlbum(static_cast<TAlbum*>(album), albumModel->isRecursingTags(), count, header, subLine); 0228 break; 0229 0230 case Album::DATE: 0231 textForDAlbum(static_cast<DAlbum*>(album), count, header, subLine); 0232 break; 0233 0234 case Album::SEARCH: 0235 textForSAlbum(static_cast<SAlbum*>(album), count, header, subLine); 0236 break; 0237 0238 case Album::FACE: 0239 default: 0240 break; 0241 } 0242 } 0243 } 0244 0245 void ItemCategoryDrawer::textForAlbum(const QModelIndex& index, QString* header, QString* subLine) const 0246 { 0247 int albumId = index.data(ItemFilterModel::CategoryAlbumIdRole).toInt(); 0248 PAlbum* const album = AlbumManager::instance()->findPAlbum(albumId); 0249 int count = d->view->categoryRange(index).height(); 0250 textForPAlbum(album, false, count, header, subLine); 0251 } 0252 0253 void ItemCategoryDrawer::textForFormat(const QModelIndex& index, QString* header, QString* subLine) const 0254 { 0255 QString format = index.data(ItemFilterModel::CategoryFormatRole).toString(); 0256 format = ItemScanner::formatToString(format); 0257 *header = format; 0258 int count = d->view->categoryRange(index).height(); 0259 *subLine = i18np("1 Item", "%1 Items", count); 0260 } 0261 0262 void ItemCategoryDrawer::textForMonth(const QModelIndex& index, QString* header, QString* subLine) const 0263 { 0264 QDate date = index.data(ItemFilterModel::CategoryDateRole).toDate(); 0265 *header = date.toString(QLatin1String("MMM yyyy")); 0266 int count = d->view->categoryRange(index).height(); 0267 *subLine = i18np("1 Item", "%1 Items", count); 0268 } 0269 0270 void ItemCategoryDrawer::textForFace(const QModelIndex& index, QString* header, QString* subLine) const 0271 { 0272 *header = index.data(ItemFilterModel::CategoryFaceRole).toString(); 0273 int count = d->view->categoryRange(index).height(); 0274 *subLine = i18np("1 Item", "%1 Items", count); 0275 } 0276 0277 void ItemCategoryDrawer::textForPAlbum(PAlbum* album, bool recursive, int count, QString* header, QString* subLine) const 0278 { 0279 Q_UNUSED(recursive); 0280 0281 if (!album) 0282 { 0283 return; 0284 } 0285 0286 QDate date = album->date(); 0287 0288 QLocale tmpLocale; 0289 0290 // day of month with two digits 0291 0292 QString day = tmpLocale.toString(date, QLatin1String("dd")); 0293 0294 // short form of the month 0295 0296 QString month = tmpLocale.toString(date, QLatin1String("MMM")); 0297 0298 // long form of the year 0299 0300 QString year = tmpLocale.toString(date, QLatin1String("yyyy")); 0301 0302 *subLine = i18ncp("%1: day of month with two digits, %2: short month name, %3: year", 0303 "Album Date: %2 %3 %4 - 1 Item", "Album Date: %2 %3 %4 - %1 Items", 0304 count, day, month, year); 0305 0306 if (!album->caption().isEmpty()) 0307 { 0308 QString caption = album->caption(); 0309 *subLine += QLatin1String(" - ") + caption.replace(QLatin1Char('\n'), QLatin1Char(' ')); 0310 } 0311 0312 *header = album->prettyUrl(); 0313 } 0314 0315 void ItemCategoryDrawer::textForTAlbum(TAlbum* talbum, bool recursive, int count, QString* header, 0316 QString* subLine) const 0317 { 0318 *header = talbum->title(); 0319 0320 if (recursive && talbum->firstChild()) 0321 { 0322 int n=0; 0323 0324 for (AlbumIterator it(talbum) ; it.current() ; ++it) 0325 { 0326 n++; 0327 } 0328 0329 QString firstPart = i18ncp("%2: a tag title; %3: number of subtags", 0330 "%2 including 1 subtag", "%2 including %1 subtags", 0331 n, talbum->tagPath(false)); 0332 0333 *subLine = i18ncp("%2: the previous string (e.g. 'Foo including 7 subtags'); %1: number of items in tag", 0334 "%2 - 1 Item", "%2 - %1 Items", 0335 count, firstPart); 0336 } 0337 else 0338 { 0339 *subLine = i18np("%2 - 1 Item", "%2 - %1 Items", count, talbum->tagPath(false)); 0340 } 0341 } 0342 0343 void ItemCategoryDrawer::textForSAlbum(SAlbum* salbum, int count, QString* header, QString* subLine) const 0344 { 0345 QString title = salbum->displayTitle(); 0346 0347 *header = title; 0348 0349 if (salbum->isNormalSearch()) 0350 { 0351 *subLine = i18np("Keyword Search - 1 Item", "Keyword Search - %1 Items", count); 0352 } 0353 else if (salbum->isAdvancedSearch()) 0354 { 0355 *subLine = i18np("Advanced Search - 1 Item", "Advanced Search - %1 Items", count); 0356 } 0357 else 0358 { 0359 *subLine = i18np("1 Item", "%1 Items", count); 0360 } 0361 } 0362 0363 void ItemCategoryDrawer::textForDAlbum(DAlbum* album, int count, QString* header, QString* subLine) const 0364 { 0365 QString year = QLocale().toString(album->date(), QLatin1String("yyyy")); 0366 0367 if (album->range() == DAlbum::Month) 0368 { 0369 *header = i18nc("Month String - Year String", "%1 %2", 0370 QLocale().standaloneMonthName(album->date().month(), QLocale::LongFormat), year); 0371 } 0372 else 0373 { 0374 *header = year; 0375 } 0376 0377 *subLine = i18np("1 Item", "%1 Items", count); 0378 } 0379 0380 void ItemCategoryDrawer::updateRectsAndPixmaps(int width) 0381 { 0382 d->rect = QRect(0, 0, 0, 0); 0383 0384 // Title -------------------------------------------------------- 0385 0386 QFont fn(d->font); 0387 int fnSize = fn.pointSize(); 0388 bool usePointSize; 0389 0390 if (fnSize > 0) 0391 { 0392 fn.setPointSize(fnSize+2); 0393 usePointSize = true; 0394 } 0395 else 0396 { 0397 fnSize = fn.pixelSize(); 0398 fn.setPixelSize(fnSize+2); 0399 usePointSize = false; 0400 } 0401 0402 fn.setBold(true); 0403 QFontMetrics fm(fn); 0404 QRect tr = fm.boundingRect(0, 0, width, 0405 0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter, 0406 QLatin1String("XXX")); 0407 d->rect.setHeight(tr.height()); 0408 0409 if (usePointSize) 0410 { 0411 fn.setPointSize(d->font.pointSize()); 0412 } 0413 else 0414 { 0415 fn.setPixelSize(d->font.pixelSize()); 0416 } 0417 0418 fn.setBold(false); 0419 fm = QFontMetrics(fn); 0420 tr = fm.boundingRect(0, 0, width, 0421 0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter, 0422 QLatin1String("XXX")); 0423 0424 d->rect.setHeight(d->rect.height() + tr.height() + 10); 0425 d->rect.setWidth(width); 0426 0427 d->pixmap = QPixmap(d->rect.width(), d->rect.height()); 0428 d->pixmap.fill(qApp->palette().color(QPalette::Highlight)); 0429 } 0430 0431 } // namespace Digikam 0432 0433 #include "moc_itemcategorydrawer.cpp"