File indexing completed on 2025-01-19 03:53:22
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2014-05-17 0007 * Description : Album Labels Tree View. 0008 * 0009 * SPDX-FileCopyrightText: 2014-2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0010 * SPDX-FileCopyrightText: 2014-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 "labelstreeview.h" 0017 0018 // QT includes 0019 0020 #include <QApplication> 0021 #include <QPainter> 0022 #include <QUrl> 0023 0024 // KDE includes 0025 0026 #include <kconfiggroup.h> 0027 #include <klocalizedstring.h> 0028 0029 // Local includes 0030 0031 #include "digikam_debug.h" 0032 #include "digikam_globals.h" 0033 #include "coredbsearchxml.h" 0034 #include "searchtabheader.h" 0035 #include "albummanager.h" 0036 #include "albumtreeview.h" 0037 #include "itemlister.h" 0038 #include "coredbaccess.h" 0039 #include "coredb.h" 0040 #include "colorlabelfilter.h" 0041 #include "picklabelfilter.h" 0042 #include "tagscache.h" 0043 #include "applicationsettings.h" 0044 #include "dnotificationwrapper.h" 0045 #include "digikamapp.h" 0046 #include "ratingwidget.h" 0047 #include "dbjobsmanager.h" 0048 0049 namespace Digikam 0050 { 0051 0052 class Q_DECL_HIDDEN LabelsTreeView::Private 0053 { 0054 public: 0055 0056 explicit Private() 0057 : ratings (nullptr), 0058 picks (nullptr), 0059 colors (nullptr), 0060 isCheckableTreeView (false), 0061 isLoadingState (false), 0062 iconSizeFromSetting (0) 0063 { 0064 } 0065 0066 QFont regularFont; 0067 QSize iconSize; 0068 0069 QTreeWidgetItem* ratings; 0070 QTreeWidgetItem* picks; 0071 QTreeWidgetItem* colors; 0072 0073 bool isCheckableTreeView; 0074 bool isLoadingState; 0075 int iconSizeFromSetting; 0076 0077 QHash<Labels, QList<int> > selectedLabels; 0078 0079 static const QString configRatingSelectionEntry; 0080 static const QString configPickSelectionEntry; 0081 static const QString configColorSelectionEntry; 0082 static const QString configExpansionEntry; 0083 }; 0084 0085 const QString LabelsTreeView::Private::configRatingSelectionEntry(QLatin1String("RatingSelection")); 0086 const QString LabelsTreeView::Private::configPickSelectionEntry(QLatin1String("PickSelection")); 0087 const QString LabelsTreeView::Private::configColorSelectionEntry(QLatin1String("ColorSelection")); 0088 const QString LabelsTreeView::Private::configExpansionEntry(QLatin1String("Expansion")); 0089 0090 LabelsTreeView::LabelsTreeView(QWidget* const parent, bool setCheckable) 0091 : QTreeWidget (parent), 0092 StateSavingObject(this), 0093 d (new Private) 0094 { 0095 d->regularFont = ApplicationSettings::instance()->getTreeViewFont(); 0096 d->iconSizeFromSetting = ApplicationSettings::instance()->getTreeViewIconSize(); 0097 d->iconSize = QSize(d->iconSizeFromSetting, d->iconSizeFromSetting); 0098 d->isCheckableTreeView = setCheckable; 0099 0100 setHeaderLabel(i18nc("@title", "Labels")); 0101 setUniformRowHeights(false); 0102 initTreeView(); 0103 0104 if (d->isCheckableTreeView) 0105 { 0106 QTreeWidgetItemIterator it(this); 0107 0108 while (*it) 0109 { 0110 if ((*it)->parent()) 0111 { 0112 (*it)->setFlags((*it)->flags()|Qt::ItemIsUserCheckable); 0113 (*it)->setCheckState(0, Qt::Unchecked); 0114 } 0115 0116 ++it; 0117 } 0118 } 0119 else 0120 { 0121 setSelectionMode(QAbstractItemView::ExtendedSelection); 0122 } 0123 0124 connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), 0125 this, SLOT(slotSettingsChanged())); 0126 } 0127 0128 LabelsTreeView::~LabelsTreeView() 0129 { 0130 delete d; 0131 } 0132 0133 bool LabelsTreeView::isCheckable() const 0134 { 0135 return d->isCheckableTreeView; 0136 } 0137 0138 bool LabelsTreeView::isLoadingState() const 0139 { 0140 return d->isLoadingState; 0141 } 0142 0143 QPixmap LabelsTreeView::goldenStarPixmap(bool fillin) const 0144 { 0145 QPixmap pixmap = QPixmap(60, 60); 0146 pixmap.fill(Qt::transparent); 0147 0148 QPainter p1(&pixmap); 0149 p1.setRenderHint(QPainter::Antialiasing, true); 0150 0151 if (fillin) 0152 { 0153 p1.setBrush(qApp->palette().color(QPalette::Link)); 0154 } 0155 0156 QPen pen(palette().color(QPalette::Active, foregroundRole())); 0157 p1.setPen(pen); 0158 0159 QTransform transform; 0160 transform.scale(4, 4); // 60px/15px (RatingWidget::starPolygon() size is 15*15px) 0161 p1.setTransform(transform); 0162 0163 p1.drawPolygon(RatingWidget::starPolygon(), Qt::WindingFill); 0164 p1.end(); 0165 0166 return pixmap; 0167 } 0168 0169 QPixmap LabelsTreeView::colorRectPixmap(const QColor& color) const 0170 { 0171 QRect rect(8, 8, 48, 48); 0172 QPixmap pixmap = QPixmap(60, 60); 0173 pixmap.fill(Qt::transparent); 0174 0175 QPainter p1(&pixmap); 0176 p1.setRenderHint(QPainter::Antialiasing, true); 0177 p1.setBrush(color); 0178 p1.setPen(palette().color(QPalette::Active, foregroundRole())); 0179 p1.drawRect(rect); 0180 p1.end(); 0181 0182 return pixmap; 0183 } 0184 0185 QHash<LabelsTreeView::Labels, QList<int> > LabelsTreeView::selectedLabels() 0186 { 0187 QHash<Labels, QList<int> > selectedLabelsHash; 0188 QList<int> selectedRatings; 0189 QList<int> selectedPicks; 0190 QList<int> selectedColors; 0191 0192 if (d->isCheckableTreeView) 0193 { 0194 QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::Checked); 0195 0196 while (*it) 0197 { 0198 QTreeWidgetItem* const item = (*it); 0199 0200 if (item->parent() == d->ratings) 0201 { 0202 selectedRatings << indexFromItem(item).row(); 0203 } 0204 else if (item->parent() == d->picks) 0205 { 0206 selectedPicks << indexFromItem(item).row(); 0207 } 0208 else 0209 { 0210 selectedColors << indexFromItem(item).row(); 0211 } 0212 0213 ++it; 0214 } 0215 } 0216 else 0217 { 0218 Q_FOREACH (QTreeWidgetItem* const item, selectedItems()) 0219 { 0220 if (item->parent() == d->ratings) 0221 { 0222 selectedRatings << indexFromItem(item).row(); 0223 } 0224 else if (item->parent() == d->picks) 0225 { 0226 selectedPicks << indexFromItem(item).row(); 0227 } 0228 else 0229 { 0230 selectedColors << indexFromItem(item).row(); 0231 } 0232 } 0233 } 0234 0235 selectedLabelsHash[Ratings] = selectedRatings; 0236 selectedLabelsHash[Picks] = selectedPicks; 0237 selectedLabelsHash[Colors] = selectedColors; 0238 0239 return selectedLabelsHash; 0240 } 0241 0242 void LabelsTreeView::doLoadState() 0243 { 0244 d->isLoadingState = true; 0245 KConfigGroup configGroup = getConfigGroup(); 0246 const QList<int> expansion = configGroup.readEntry(entryName(d->configExpansionEntry), QList<int>()); 0247 const QList<int> selectedRatings = configGroup.readEntry(entryName(d->configRatingSelectionEntry), QList<int>()); 0248 const QList<int> selectedPicks = configGroup.readEntry(entryName(d->configPickSelectionEntry), QList<int>()); 0249 const QList<int> selectedColors = configGroup.readEntry(entryName(d->configColorSelectionEntry), QList<int>()); 0250 0251 d->ratings->setExpanded(true); 0252 d->picks->setExpanded(true); 0253 d->colors->setExpanded(true); 0254 0255 Q_FOREACH (int parent, expansion) 0256 { 0257 switch (parent) 0258 { 0259 case 1: 0260 d->ratings->setExpanded(false); 0261 break; 0262 0263 case 2: 0264 d->picks->setExpanded(false); 0265 break; 0266 0267 case 3: 0268 d->colors->setExpanded(false); 0269 0270 default: 0271 break; 0272 } 0273 } 0274 0275 Q_FOREACH (int rating, selectedRatings) 0276 { 0277 if (d->isCheckableTreeView) 0278 { 0279 d->ratings->child(rating)->setCheckState(0, Qt::Checked); 0280 } 0281 else 0282 { 0283 d->ratings->child(rating)->setSelected(true); 0284 } 0285 } 0286 0287 Q_FOREACH (int pick, selectedPicks) 0288 { 0289 if (d->isCheckableTreeView) 0290 { 0291 d->picks->child(pick)->setCheckState(0, Qt::Checked); 0292 } 0293 else 0294 { 0295 d->picks->child(pick)->setSelected(true); 0296 } 0297 } 0298 0299 Q_FOREACH (int color, selectedColors) 0300 { 0301 if (d->isCheckableTreeView) 0302 { 0303 d->colors->child(color)->setCheckState(0, Qt::Checked); 0304 } 0305 else 0306 { 0307 d->colors->child(color)->setSelected(true); 0308 } 0309 } 0310 0311 d->isLoadingState = false; 0312 } 0313 0314 void LabelsTreeView::doSaveState() 0315 { 0316 KConfigGroup configGroup = getConfigGroup(); 0317 QList<int> expansion; 0318 0319 if (!d->ratings->isExpanded()) 0320 { 0321 expansion << 1; 0322 } 0323 0324 if (!d->picks->isExpanded()) 0325 { 0326 expansion << 2; 0327 } 0328 0329 if (!d->colors->isExpanded()) 0330 { 0331 expansion << 3; 0332 } 0333 0334 QHash<Labels, QList<int> > labels = selectedLabels(); 0335 0336 configGroup.writeEntry(entryName(d->configExpansionEntry), expansion); 0337 configGroup.writeEntry(entryName(d->configRatingSelectionEntry), labels[Ratings]); 0338 configGroup.writeEntry(entryName(d->configPickSelectionEntry), labels[Picks]); 0339 configGroup.writeEntry(entryName(d->configColorSelectionEntry), labels[Colors]); 0340 } 0341 0342 void LabelsTreeView::setCurrentAlbum() 0343 { 0344 Q_EMIT signalSetCurrentAlbum(); 0345 } 0346 0347 void LabelsTreeView::initTreeView() 0348 { 0349 setIconSize(QSize(d->iconSizeFromSetting*5,d->iconSizeFromSetting)); 0350 initRatingsTree(); 0351 initPicksTree(); 0352 initColorsTree(); 0353 expandAll(); 0354 setRootIsDecorated(false); 0355 } 0356 0357 void LabelsTreeView::initRatingsTree() 0358 { 0359 d->ratings = new QTreeWidgetItem(this); 0360 d->ratings->setText(0, i18nc("@item: rating tree", "Rating")); 0361 d->ratings->setFont(0, d->regularFont); 0362 d->ratings->setFlags(Qt::ItemIsEnabled); 0363 0364 QTreeWidgetItem* const noRate = new QTreeWidgetItem(d->ratings); 0365 noRate->setText(0, i18nc("@item: rating tree", "No Rating")); 0366 noRate->setFont(0, d->regularFont); 0367 QPixmap pix2(goldenStarPixmap().size()); 0368 pix2.fill(Qt::transparent); 0369 QPainter p2(&pix2); 0370 p2.setRenderHint(QPainter::Antialiasing, true); 0371 p2.setPen(palette().color(QPalette::Active, foregroundRole())); 0372 p2.drawPixmap(0, 0, goldenStarPixmap(false)); 0373 noRate->setIcon(0, QIcon(pix2)); 0374 noRate->setSizeHint(0, d->iconSize); 0375 0376 for (int rate = 1 ; rate <= 5 ; ++rate) 0377 { 0378 QTreeWidgetItem* const rateWidget = new QTreeWidgetItem(d->ratings); 0379 0380 QPixmap pix(goldenStarPixmap().width()*rate, goldenStarPixmap().height()); 0381 pix.fill(Qt::transparent); 0382 QPainter p(&pix); 0383 int offset = 0; 0384 p.setRenderHint(QPainter::Antialiasing, true); 0385 p.setPen(palette().color(QPalette::Active, foregroundRole())); 0386 0387 for (int i = 0 ; i < rate ; ++i) 0388 { 0389 p.drawPixmap(offset, 0, goldenStarPixmap()); 0390 offset += goldenStarPixmap().width(); 0391 } 0392 0393 rateWidget->setIcon(0, QIcon(pix)); 0394 rateWidget->setSizeHint(0, d->iconSize); 0395 } 0396 } 0397 0398 void LabelsTreeView::initPicksTree() 0399 { 0400 d->picks = new QTreeWidgetItem(this); 0401 d->picks->setText(0, i18nc("@title: pick tree", "Pick")); 0402 d->picks->setFont(0, d->regularFont); 0403 d->picks->setFlags(Qt::ItemIsEnabled); 0404 0405 QStringList pickSetNames; 0406 pickSetNames << i18nc("@item: pick tree", "No Pick") 0407 << i18nc("@item: pick tree", "Rejected Item") 0408 << i18nc("@item: pick tree", "Pending Item") 0409 << i18nc("@item: pick tree", "Accepted Item"); 0410 0411 QStringList pickSetIcons; 0412 pickSetIcons << QLatin1String("flag-black") 0413 << QLatin1String("flag-red") 0414 << QLatin1String("flag-yellow") 0415 << QLatin1String("flag-green"); 0416 0417 Q_FOREACH (const QString& pick, pickSetNames) 0418 { 0419 QTreeWidgetItem* const pickWidgetItem = new QTreeWidgetItem(d->picks); 0420 pickWidgetItem->setText(0, pick); 0421 pickWidgetItem->setFont(0, d->regularFont); 0422 pickWidgetItem->setIcon(0, QIcon::fromTheme(pickSetIcons.at(pickSetNames.indexOf(pick)))); 0423 } 0424 } 0425 0426 void LabelsTreeView::initColorsTree() 0427 { 0428 d->colors = new QTreeWidgetItem(this); 0429 d->colors->setText(0, i18nc("@item: color tree", "Color")); 0430 d->colors->setFont(0, d->regularFont); 0431 d->colors->setFlags(Qt::ItemIsEnabled); 0432 0433 QTreeWidgetItem* const noColor = new QTreeWidgetItem(d->colors); 0434 noColor->setText(0, i18nc("@item: color tree", "No Color")); 0435 noColor->setFont(0, d->regularFont); 0436 noColor->setIcon(0, QIcon::fromTheme(QLatin1String("emblem-unmounted"))); 0437 0438 QStringList colorSet; 0439 colorSet << QLatin1String("red") << QLatin1String("orange") 0440 << QLatin1String("yellow") << QLatin1String("darkgreen") 0441 << QLatin1String("darkblue") << QLatin1String("magenta") 0442 << QLatin1String("darkgray") << QLatin1String("black") 0443 << QLatin1String("white"); 0444 0445 QStringList colorSetNames; 0446 colorSetNames << i18nc("@item: color tree", "Red") << i18nc("@item: color tree", "Orange") 0447 << i18nc("@item: color tree", "Yellow") << i18nc("@item: color tree", "Green") 0448 << i18nc("@item: color tree", "Blue") << i18nc("@item: color tree", "Magenta") 0449 << i18nc("@item: color tree", "Gray") << i18nc("@item: color tree", "Black") 0450 << i18nc("@item: color tree", "White"); 0451 0452 Q_FOREACH (const QString& color, colorSet) 0453 { 0454 QTreeWidgetItem* const colorWidgetItem = new QTreeWidgetItem(d->colors); 0455 colorWidgetItem->setText(0, colorSetNames.at(colorSet.indexOf(color))); 0456 colorWidgetItem->setFont(0, d->regularFont); 0457 QPixmap colorIcon = colorRectPixmap(QColor(color)); 0458 colorWidgetItem->setIcon(0, QIcon(colorIcon)); 0459 colorWidgetItem->setSizeHint(0, d->iconSize); 0460 } 0461 } 0462 0463 void LabelsTreeView::slotSettingsChanged() 0464 { 0465 if (d->iconSizeFromSetting != ApplicationSettings::instance()->getTreeViewIconSize()) 0466 { 0467 d->iconSizeFromSetting = ApplicationSettings::instance()->getTreeViewIconSize(); 0468 setIconSize(QSize(d->iconSizeFromSetting*5, d->iconSizeFromSetting)); 0469 d->iconSize = QSize(d->iconSizeFromSetting, d->iconSizeFromSetting); 0470 QTreeWidgetItemIterator it(this); 0471 0472 while (*it) 0473 { 0474 (*it)->setSizeHint(0, d->iconSize); 0475 ++it; 0476 } 0477 } 0478 0479 if (d->regularFont != ApplicationSettings::instance()->getTreeViewFont()) 0480 { 0481 d->regularFont = ApplicationSettings::instance()->getTreeViewFont(); 0482 QTreeWidgetItemIterator it(this); 0483 0484 while (*it) 0485 { 0486 (*it)->setFont(0, d->regularFont); 0487 ++it; 0488 } 0489 } 0490 } 0491 0492 void LabelsTreeView::restoreSelectionFromHistory(QHash<Labels, QList<int> > neededLabels) 0493 { 0494 QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::Selected); 0495 0496 while (*it) 0497 { 0498 (*it)->setSelected(false); 0499 ++it; 0500 } 0501 0502 Q_FOREACH (int rateItemIndex, neededLabels[Ratings]) 0503 { 0504 d->ratings->child(rateItemIndex)->setSelected(true); 0505 } 0506 0507 Q_FOREACH (int pickItemIndex, neededLabels[Picks]) 0508 { 0509 d->picks->child(pickItemIndex)->setSelected(true); 0510 } 0511 0512 Q_FOREACH (int colorItemIndex, neededLabels[Colors]) 0513 { 0514 d->colors->child(colorItemIndex)->setSelected(true); 0515 } 0516 } 0517 0518 } // namespace Digikam 0519 0520 #include "moc_labelstreeview.cpp"