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 : 2005-05-06 0007 * Description : Albums folder view. 0008 * 0009 * SPDX-FileCopyrightText: 2005-2006 by Joern Ahrens <joern dot ahrens at kdemail dot net> 0010 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com> 0012 * SPDX-FileCopyrightText: 2009-2011 by Johannes Wienke <languitar at semipol dot de> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "albumselectiontreeview.h" 0019 0020 // Qt includes 0021 0022 #include <QMessageBox> 0023 #include <QAction> 0024 #include <QEvent> 0025 #include <QIcon> 0026 0027 // KDE includes 0028 0029 #include <klocalizedstring.h> 0030 0031 // Local includes 0032 0033 #include "digikam_debug.h" 0034 #include "tagscache.h" 0035 #include "itemscanner.h" 0036 #include "albummanager.h" 0037 #include "facescansettings.h" 0038 #include "applicationsettings.h" 0039 #include "contextmenuhelper.h" 0040 #include "itemviewtooltip.h" 0041 #include "tooltipfiller.h" 0042 #include "thumbsgenerator.h" 0043 #include "newitemsfinder.h" 0044 #include "facesdetector.h" 0045 #include "coredbaccess.h" 0046 #include "coredb.h" 0047 0048 namespace Digikam 0049 { 0050 0051 class Q_DECL_HIDDEN AlbumViewToolTip: public ItemViewToolTip 0052 { 0053 Q_OBJECT 0054 0055 public: 0056 0057 explicit AlbumViewToolTip(AlbumSelectionTreeView* const view) 0058 : ItemViewToolTip(view) 0059 { 0060 } 0061 0062 AlbumSelectionTreeView* view() const 0063 { 0064 return static_cast<AlbumSelectionTreeView*>(ItemViewToolTip::view()); 0065 } 0066 0067 protected: 0068 0069 QString tipContents() override 0070 { 0071 PAlbum* const album = view()->albumForIndex(currentIndex()); 0072 0073 return (ToolTipFiller::albumTipContents(album, view()->albumModel()->albumCount(album))); 0074 } 0075 }; 0076 0077 // ---------------------------------------------------------------------------------------------------- 0078 0079 class Q_DECL_HIDDEN AlbumSelectionTreeView::Private 0080 { 0081 0082 public: 0083 0084 explicit Private() 0085 : enableToolTips (false), 0086 albumModificationHelper (nullptr), 0087 toolTip (nullptr), 0088 renameAction (nullptr), 0089 resetIconAction (nullptr), 0090 findDuplAction (nullptr), 0091 scanFacesAction (nullptr), 0092 repairHiddenAction (nullptr), 0093 rebuildThumbsAction (nullptr), 0094 expandSelected (nullptr), 0095 expandAllAlbums (nullptr), 0096 collapseSelected (nullptr), 0097 collapseAllAlbums (nullptr), 0098 contextMenuElement (nullptr) 0099 { 0100 } 0101 0102 bool enableToolTips; 0103 0104 AlbumModificationHelper* albumModificationHelper; 0105 AlbumViewToolTip* toolTip; 0106 0107 QAction* renameAction; 0108 QAction* resetIconAction; 0109 QAction* findDuplAction; 0110 QAction* scanFacesAction; 0111 QAction* repairHiddenAction; 0112 QAction* rebuildThumbsAction; 0113 QAction* expandSelected; 0114 QAction* expandAllAlbums; 0115 QAction* collapseSelected; 0116 QAction* collapseAllAlbums; 0117 0118 class AlbumSelectionTreeViewContextMenuElement; 0119 AlbumSelectionTreeViewContextMenuElement* contextMenuElement; 0120 }; 0121 0122 // ---------------------------------------------------------------------------------------------------- 0123 0124 class Q_DECL_HIDDEN AlbumSelectionTreeView::Private::AlbumSelectionTreeViewContextMenuElement 0125 : public AbstractAlbumTreeView::ContextMenuElement 0126 { 0127 0128 public: 0129 0130 explicit AlbumSelectionTreeViewContextMenuElement(AlbumSelectionTreeView::Private* const dd) 0131 : d(dd) 0132 { 0133 } 0134 0135 void addActions(AbstractAlbumTreeView*, ContextMenuHelper& cmh, Album* a) override 0136 { 0137 if (!a || a->isRoot()) 0138 { 0139 return; 0140 } 0141 0142 PAlbum* const album = dynamic_cast<PAlbum*>(a); 0143 0144 if (!album) 0145 { 0146 return; 0147 } 0148 0149 cmh.addActionNewAlbum(d->albumModificationHelper, album); 0150 cmh.addAction(QLatin1String("album_openinfilemanager")); 0151 cmh.addSeparator(); 0152 0153 // -------------------------------------------------------- 0154 0155 cmh.addActionRenameAlbum(d->albumModificationHelper, album); 0156 cmh.addActionResetAlbumIcon(d->albumModificationHelper, album); 0157 cmh.addSeparator(); 0158 0159 // -------------------------------------------------------- 0160 0161 cmh.addAction(d->expandSelected); 0162 cmh.addAction(d->collapseSelected); 0163 cmh.addAction(d->expandAllAlbums); 0164 cmh.addAction(d->collapseAllAlbums); 0165 cmh.addSeparator(); 0166 0167 // -------------------------------------------------------- 0168 0169 cmh.addAction(d->findDuplAction); 0170 d->albumModificationHelper->bindAlbum(d->findDuplAction, album); 0171 cmh.addAction(d->scanFacesAction); 0172 d->albumModificationHelper->bindAlbum(d->scanFacesAction, album); 0173 cmh.addAction(d->rebuildThumbsAction); 0174 d->albumModificationHelper->bindAlbum(d->rebuildThumbsAction, album); 0175 cmh.addImportMenu(); 0176 cmh.addExportMenu(); 0177 cmh.addSeparator(); 0178 0179 // -------------------------------------------------------- 0180 0181 cmh.addAction(d->repairHiddenAction); 0182 d->albumModificationHelper->bindAlbum(d->repairHiddenAction, album); 0183 0184 // -------------------------------------------------------- 0185 0186 if (!album->isAlbumRoot()) 0187 { 0188 cmh.addSeparator(); 0189 cmh.addActionDeleteAlbum(d->albumModificationHelper, album); 0190 cmh.addSeparator(); 0191 0192 // -------------------------------------------------------- 0193 0194 cmh.addActionEditAlbum(d->albumModificationHelper, album); 0195 } 0196 } 0197 0198 public: 0199 0200 AlbumSelectionTreeView::Private* const d; 0201 }; 0202 0203 // ---------------------------------------------------------------------------------------------------- 0204 0205 AlbumSelectionTreeView::AlbumSelectionTreeView(QWidget* const parent, 0206 AlbumModel* const model, 0207 AlbumModificationHelper* const albumModificationHelper) 0208 : AlbumTreeView(parent), 0209 d (new Private) 0210 { 0211 setAlbumModel(model); 0212 d->albumModificationHelper = albumModificationHelper; 0213 d->toolTip = new AlbumViewToolTip(this); 0214 0215 d->expandSelected = new QAction(QIcon::fromTheme(QLatin1String("go-down")), 0216 i18n("Expand Selected Nodes"), this); 0217 0218 d->expandAllAlbums = new QAction(QIcon::fromTheme(QLatin1String("expand-all")), 0219 i18n("Expand all Albums"), this); 0220 0221 d->collapseSelected = new QAction(QIcon::fromTheme(QLatin1String("go-up")), 0222 i18n("Collapse Selected Recursively"), this); 0223 0224 d->collapseAllAlbums = new QAction(QIcon::fromTheme(QLatin1String("collapse-all")), 0225 i18n("Collapse all Albums"), this); 0226 0227 d->findDuplAction = new QAction(QIcon::fromTheme(QLatin1String("tools-wizard")), 0228 i18n("Find Duplicates..."), this); 0229 0230 d->scanFacesAction = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), 0231 i18n("Scan for Faces"), this); 0232 0233 d->repairHiddenAction = new QAction(QIcon::fromTheme(QLatin1String("edit-group")), 0234 i18n("Repair hidden Items"), this); 0235 0236 d->rebuildThumbsAction = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), 0237 i18n("Refresh"), this); 0238 0239 connect(d->expandSelected, SIGNAL(triggered()), 0240 this, SLOT(slotExpandNode())); 0241 0242 connect(d->expandAllAlbums, SIGNAL(triggered()), 0243 this, SLOT(expandAll())); 0244 0245 connect(d->collapseSelected, SIGNAL(triggered()), 0246 this, SLOT(slotCollapseNode())); 0247 0248 connect(d->collapseAllAlbums, SIGNAL(triggered()), 0249 this, SLOT(slotCollapseAllNodes())); 0250 0251 connect(d->findDuplAction, SIGNAL(triggered()), 0252 this, SLOT(slotFindDuplicates())); 0253 0254 connect(d->scanFacesAction, SIGNAL(triggered()), 0255 this, SLOT(slotScanForFaces())); 0256 0257 connect(d->repairHiddenAction, SIGNAL(triggered()), 0258 this, SLOT(slotRepairHiddenItems())); 0259 0260 connect(d->rebuildThumbsAction, SIGNAL(triggered()), 0261 this, SLOT(slotRebuildThumbs())); 0262 0263 setSortingEnabled(true); 0264 setSelectAlbumOnClick(true); 0265 setEnableContextMenu(true); 0266 setContextMenuTitle(i18n("Albums")); 0267 0268 d->contextMenuElement = new Private::AlbumSelectionTreeViewContextMenuElement(d); 0269 addContextMenuElement(d->contextMenuElement); 0270 } 0271 0272 AlbumSelectionTreeView::~AlbumSelectionTreeView() 0273 { 0274 delete d->contextMenuElement; 0275 delete d; 0276 } 0277 0278 void AlbumSelectionTreeView::setEnableToolTips(bool enable) 0279 { 0280 d->enableToolTips = enable; 0281 } 0282 0283 void AlbumSelectionTreeView::slotFindDuplicates() 0284 { 0285 Q_EMIT signalFindDuplicates(QList<PAlbum*> { d->albumModificationHelper->boundAlbum(sender()) }); 0286 } 0287 0288 void AlbumSelectionTreeView::slotScanForFaces() 0289 { 0290 PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); 0291 0292 if (!album) 0293 { 0294 return; 0295 } 0296 0297 AlbumList albums; 0298 albums << album; 0299 0300 if (album->childCount()) 0301 { 0302 if (QMessageBox::question(this, i18nc("@title:window", "Scan for Faces"), 0303 i18n("Should sub-albums be scanned too?")) 0304 == QMessageBox::Yes) 0305 { 0306 albums << album->childAlbums(true); 0307 } 0308 } 0309 0310 FaceScanSettings settings; 0311 0312 settings.accuracy = ApplicationSettings::instance()->getFaceDetectionAccuracy(); 0313 settings.useYoloV3 = ApplicationSettings::instance()->getFaceDetectionYoloV3(); 0314 settings.task = FaceScanSettings::DetectAndRecognize; 0315 settings.alreadyScannedHandling = FaceScanSettings::Rescan; 0316 settings.albums = albums; 0317 0318 FacesDetector* const tool = new FacesDetector(settings); 0319 tool->start(); 0320 } 0321 0322 void AlbumSelectionTreeView::slotRepairHiddenItems() 0323 { 0324 PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); 0325 0326 if (!album) 0327 { 0328 return; 0329 } 0330 0331 int originalVersionTag = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion()); 0332 0333 Q_FOREACH (const qlonglong& id, CoreDbAccess().db()->getItemIDsInAlbum(album->id())) 0334 { 0335 ItemInfo info(id); 0336 0337 if (!info.isNull() && info.isGrouped()) 0338 { 0339 if (info.groupImage().albumId() != album->id()) 0340 { 0341 info.removeFromGroup(); 0342 } 0343 } 0344 0345 if (!info.hasDerivedImages() && info.tagIds().contains(originalVersionTag)) 0346 { 0347 ItemScanner::resolveImageHistory(info.id()); 0348 ItemScanner::tagItemHistoryGraph(info.id()); 0349 } 0350 } 0351 } 0352 0353 void AlbumSelectionTreeView::slotRebuildThumbs() 0354 { 0355 PAlbum* const album = d->albumModificationHelper->boundAlbum(sender()); 0356 0357 if (!album) 0358 { 0359 return; 0360 } 0361 0362 ThumbsGenerator* const tool = new ThumbsGenerator(true, album->id()); 0363 tool->start(); 0364 0365 // if physical album, schedule a collection scan of current album's path 0366 0367 if (album->type() == Album::PHYSICAL) 0368 { 0369 NewItemsFinder* const tool2 = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, 0370 QStringList() << static_cast<PAlbum*>(album)->folderPath()); 0371 tool2->start(); 0372 } 0373 } 0374 0375 bool AlbumSelectionTreeView::viewportEvent(QEvent* event) 0376 { 0377 // let the base class handle the event if it is not a tool tip request 0378 0379 if (event->type() != QEvent::ToolTip) 0380 { 0381 return AlbumTreeView::viewportEvent(event); 0382 } 0383 0384 // only show tool tips if requested 0385 0386 if (!d->enableToolTips) 0387 { 0388 return false; 0389 } 0390 0391 // check that we got a correct event 0392 0393 QHelpEvent* const helpEvent = dynamic_cast<QHelpEvent*> (event); 0394 0395 if (!helpEvent) 0396 { 0397 qCDebug(DIGIKAM_GENERAL_LOG) << "Unable to determine the correct type of the event. " 0398 << "This should not happen."; 0399 return false; 0400 } 0401 0402 // find the item this tool tip belongs to 0403 0404 QModelIndex index = indexAt(helpEvent->pos()); 0405 0406 if (!index.isValid()) 0407 { 0408 return true; 0409 } 0410 0411 PAlbum* const album = albumForIndex(index); 0412 0413 if (!album || album->isRoot() || album->isAlbumRoot()) 0414 { 0415 // there was no album so we really don't want to show a tooltip. 0416 0417 return true; 0418 } 0419 0420 QRect itemRect = visualRect(index); 0421 0422 if (!itemRect.contains(helpEvent->pos())) 0423 { 0424 return true; 0425 } 0426 0427 QStyleOptionViewItem option; 0428 0429 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0430 0431 initViewItemOption(&option); 0432 0433 #else 0434 0435 option = viewOptions(); 0436 0437 #endif 0438 0439 option.rect = itemRect; 0440 0441 // visualRect can be larger than viewport, intersect with viewport rect 0442 0443 option.rect &= viewport()->rect(); 0444 option.state |= (index == currentIndex() ? QStyle::State_HasFocus : QStyle::State_None); 0445 d->toolTip->show(option, index); 0446 0447 return true; 0448 } 0449 0450 } // namespace Digikam 0451 0452 #include "albumselectiontreeview.moc" 0453 0454 #include "moc_albumselectiontreeview.cpp"