File indexing completed on 2025-01-05 03:51:13
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-04-24 0007 * Description : Qt model-view for items 0008 * 0009 * SPDX-FileCopyrightText: 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2011 by Andi Clemens <andi dot clemens at gmail dot com> 0012 * SPDX-FileCopyrightText: 2013 by Michael G. Hansen <mike at mghansen dot de> 0013 * SPDX-FileCopyrightText: 2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0014 * SPDX-FileCopyrightText: 2017 by Simon Frei <freisim93 at gmail dot com> 0015 * 0016 * SPDX-License-Identifier: GPL-2.0-or-later 0017 * 0018 * ============================================================ */ 0019 0020 #include "digikamitemview_p.h" 0021 0022 // Qt includes 0023 0024 #include <QApplication> 0025 #include <QPointer> 0026 #include <QAction> 0027 #include <QMenu> 0028 #include <QIcon> 0029 #include <QUrl> 0030 0031 // Local includes 0032 0033 #include "digikam_debug.h" 0034 #include "albummanager.h" 0035 #include "coredb.h" 0036 #include "coredboperationgroup.h" 0037 #include "advancedrenamedialog.h" 0038 #include "advancedrenameprocessdialog.h" 0039 #include "assignnameoverlay.h" 0040 #include "contextmenuhelper.h" 0041 #include "coredbaccess.h" 0042 #include "ddragobjects.h" 0043 #include "digikamapp.h" 0044 #include "digikamitemdelegate.h" 0045 #include "itemfacedelegate.h" 0046 #include "dio.h" 0047 #include "groupindicatoroverlay.h" 0048 #include "itemalbumfiltermodel.h" 0049 #include "itemalbummodel.h" 0050 #include "itemdragdrop.h" 0051 #include "itemratingoverlay.h" 0052 #include "itemfullscreenoverlay.h" 0053 #include "itemcoordinatesoverlay.h" 0054 #include "tagslineeditoverlay.h" 0055 #include "imagewindow.h" 0056 #include "fileactionmngr.h" 0057 #include "fileactionprogress.h" 0058 #include "thumbnailloadthread.h" 0059 #include "tagregion.h" 0060 #include "addtagslineedit.h" 0061 #include "facerejectionoverlay.h" 0062 #include "facetagsiface.h" 0063 0064 namespace Digikam 0065 { 0066 0067 DigikamItemView::DigikamItemView(QWidget* const parent) 0068 : ItemCategorizedView(parent), 0069 d (new Private(this)) 0070 { 0071 installDefaultModels(); 0072 0073 d->editPipeline.plugDatabaseEditor(); 0074 d->editPipeline.plugTrainer(); 0075 d->editPipeline.construct(); 0076 0077 connect(&d->editPipeline, SIGNAL(scheduled()), 0078 this, SLOT(slotInitProgressIndicator())); 0079 0080 d->normalDelegate = new DigikamItemDelegate(this); 0081 d->faceDelegate = new ItemFaceDelegate(this); 0082 0083 setItemDelegate(d->normalDelegate); 0084 setSpacing(10); 0085 0086 ApplicationSettings* const settings = ApplicationSettings::instance(); 0087 0088 imageFilterModel()->setCategorizationMode(ItemSortSettings::CategoryByAlbum); 0089 0090 imageAlbumModel()->setThumbnailLoadThread(ThumbnailLoadThread::defaultIconViewThread()); 0091 0092 // Virtual method: use Dynamic binding. 0093 0094 this->setThumbnailSize(ThumbnailSize(settings->getDefaultIconSize())); 0095 0096 imageAlbumModel()->setPreloadThumbnails(true); 0097 0098 imageModel()->setDragDropHandler(new ItemDragDropHandler(imageModel())); 0099 setDragEnabled(true); 0100 setAcceptDrops(true); 0101 setDropIndicatorShown(false); 0102 0103 setToolTipEnabled(settings->showToolTipsIsValid()); 0104 imageFilterModel()->setStringTypeNatural(settings->isStringTypeNatural()); 0105 imageFilterModel()->setSortRole((ItemSortSettings::SortRole)settings->getImageSortOrder()); 0106 imageFilterModel()->setSortOrder((ItemSortSettings::SortOrder)settings->getImageSorting()); 0107 imageFilterModel()->setCategorizationMode((ItemSortSettings::CategorizationMode)settings->getImageSeparationMode()); 0108 imageFilterModel()->setCategorizationSortOrder((ItemSortSettings::SortOrder) settings->getImageSeparationSortOrder()); 0109 0110 // selection overlay 0111 0112 addSelectionOverlay(d->normalDelegate); 0113 addSelectionOverlay(d->faceDelegate); 0114 0115 // rotation overlays 0116 0117 d->rotateLeftOverlay = ItemRotateOverlay::left(this); 0118 d->rotateRightOverlay = ItemRotateOverlay::right(this); 0119 d->fullscreenOverlay = ItemFullScreenOverlay::instance(this); 0120 d->updateOverlays(); 0121 0122 // rating overlay 0123 0124 ItemRatingOverlay* const ratingOverlay = new ItemRatingOverlay(this); 0125 addOverlay(ratingOverlay); 0126 0127 // face overlays 0128 // NOTE: order to plug this overlay is important, else rejection cant be suitable (see bug #324759). 0129 0130 addAssignNameOverlay(d->faceDelegate); 0131 addRejectionOverlay(d->faceDelegate); 0132 0133 GroupIndicatorOverlay* const groupOverlay = new GroupIndicatorOverlay(this); 0134 addOverlay(groupOverlay); 0135 0136 addOverlay(new ItemCoordinatesOverlay(this)); 0137 0138 connect(ratingOverlay, SIGNAL(ratingEdited(QList<QModelIndex>,int)), 0139 this, SLOT(assignRating(QList<QModelIndex>,int))); 0140 0141 connect(groupOverlay, SIGNAL(toggleGroupOpen(QModelIndex)), 0142 this, SLOT(groupIndicatorClicked(QModelIndex))); 0143 0144 connect(groupOverlay, SIGNAL(showButtonContextMenu(QModelIndex,QContextMenuEvent*)), 0145 this, SLOT(showGroupContextMenu(QModelIndex,QContextMenuEvent*))); 0146 0147 d->utilities = new ItemViewUtilities(this); 0148 0149 connect(imageModel()->dragDropHandler(), SIGNAL(assignTags(QList<ItemInfo>,QList<int>)), 0150 FileActionMngr::instance(), SLOT(assignTags(QList<ItemInfo>,QList<int>))); 0151 0152 connect(imageModel()->dragDropHandler(), SIGNAL(addToGroup(ItemInfo,QList<ItemInfo>)), 0153 FileActionMngr::instance(), SLOT(addToGroup(ItemInfo,QList<ItemInfo>))); 0154 0155 connect(imageModel()->dragDropHandler(), SIGNAL(dragDropSort(ItemInfo,QList<ItemInfo>)), 0156 this, SLOT(dragDropSort(ItemInfo,QList<ItemInfo>))); 0157 0158 connect(d->utilities, SIGNAL(editorCurrentUrlChanged(QUrl)), 0159 this, SLOT(setCurrentUrlWhenAvailable(QUrl))); 0160 0161 // --- NOTE: use dynamic binding as slotSetupChanged() is a virtual method which can be re-implemented in derived classes. 0162 0163 connect(settings, &ApplicationSettings::setupChanged, 0164 this, &DigikamItemView::slotSetupChanged); 0165 0166 this->slotSetupChanged(); 0167 } 0168 0169 DigikamItemView::~DigikamItemView() 0170 { 0171 delete d; 0172 } 0173 0174 ItemViewUtilities* DigikamItemView::utilities() const 0175 { 0176 return d->utilities; 0177 } 0178 0179 void DigikamItemView::setThumbnailSize(const ThumbnailSize& size) 0180 { 0181 imageThumbnailModel()->setPreloadThumbnailSize(size); 0182 ItemCategorizedView::setThumbnailSize(size); 0183 } 0184 0185 ItemInfoList DigikamItemView::allItemInfos(bool grouping) const 0186 { 0187 if (grouping) 0188 { 0189 return resolveGrouping(ItemCategorizedView::allItemInfos()); 0190 } 0191 0192 return ItemCategorizedView::allItemInfos(); 0193 } 0194 0195 ItemInfoList DigikamItemView::selectedItemInfos(bool grouping) const 0196 { 0197 if (grouping) 0198 { 0199 return resolveGrouping(ItemCategorizedView::selectedItemInfos()); 0200 } 0201 0202 return ItemCategorizedView::selectedItemInfos(); 0203 } 0204 0205 ItemInfoList DigikamItemView::selectedItemInfosCurrentFirst(bool grouping) const 0206 { 0207 if (grouping) 0208 { 0209 return resolveGrouping(ItemCategorizedView::selectedItemInfosCurrentFirst()); 0210 } 0211 0212 return ItemCategorizedView::selectedItemInfosCurrentFirst(); 0213 } 0214 0215 void DigikamItemView::dragDropSort(const ItemInfo& pick, const QList<ItemInfo>& infos) 0216 { 0217 if (pick.isNull() || infos.isEmpty()) 0218 { 0219 return; 0220 } 0221 0222 ItemInfoList infoList = allItemInfos(false); 0223 qlonglong counter = pick.manualOrder(); 0224 bool order = (ApplicationSettings::instance()-> 0225 getImageSorting() == Qt::AscendingOrder); 0226 bool found = false; 0227 0228 QApplication::setOverrideCursor(Qt::WaitCursor); 0229 0230 CoreDbOperationGroup group; 0231 group.setMaximumTime(200); 0232 0233 Q_FOREACH (ItemInfo info, infoList) 0234 { 0235 if (!found && info.id() == pick.id()) 0236 { 0237 Q_FOREACH (ItemInfo dropInfo, infos) 0238 { 0239 dropInfo.setManualOrder(counter); 0240 counter += (order ? 1 : -1); 0241 } 0242 0243 info.setManualOrder(counter); 0244 found = true; 0245 } 0246 else if (found && !infos.contains(info)) 0247 { 0248 if (( order && info.manualOrder() > counter) || 0249 (!order && info.manualOrder() < counter)) 0250 { 0251 break; 0252 } 0253 0254 counter += (order ? 100 : -100); 0255 info.setManualOrder(counter); 0256 } 0257 0258 group.allowLift(); 0259 } 0260 0261 QApplication::restoreOverrideCursor(); 0262 0263 imageFilterModel()->invalidate(); 0264 } 0265 0266 bool DigikamItemView::allNeedGroupResolving(const ApplicationSettings::OperationType type) const 0267 { 0268 return needGroupResolving(type, allItemInfos()); 0269 } 0270 0271 bool DigikamItemView::selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const 0272 { 0273 return needGroupResolving(type, selectedItemInfos()); 0274 } 0275 0276 int DigikamItemView::fitToWidthIcons() 0277 { 0278 return delegate()->calculatethumbSizeToFit(viewport()->size().width()); 0279 } 0280 0281 void DigikamItemView::slotSetupChanged() 0282 { 0283 imageFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); 0284 setToolTipEnabled(ApplicationSettings::instance()->showToolTipsIsValid()); 0285 setFont(ApplicationSettings::instance()->getIconViewFont()); 0286 0287 d->updateOverlays(); 0288 0289 ItemCategorizedView::slotSetupChanged(); 0290 } 0291 0292 bool DigikamItemView::hasHiddenGroupedImages(const ItemInfo& info) const 0293 { 0294 return (info.hasGroupedImages() && 0295 !imageFilterModel()->isAllGroupsOpen() && 0296 !imageFilterModel()->isGroupOpen(info.id())); 0297 } 0298 0299 ItemInfoList DigikamItemView::imageInfos(const QList<QModelIndex>& indexes, 0300 ApplicationSettings::OperationType type) const 0301 { 0302 ItemInfoList infos = ItemCategorizedView::imageInfos(indexes); 0303 0304 if (needGroupResolving(type, infos)) 0305 { 0306 return resolveGrouping(infos); 0307 } 0308 0309 return infos; 0310 } 0311 0312 bool DigikamItemView::getFaceMode() const 0313 { 0314 return d->faceMode; 0315 } 0316 0317 void DigikamItemView::setFaceMode(bool on) 0318 { 0319 d->faceMode = on; 0320 0321 if (on) 0322 { 0323 // See ItemLister, which creates a search the implements listing tag in the ioslave 0324 0325 imageAlbumModel()->setSpecialTagListing(QLatin1String("faces")); 0326 setItemDelegate(d->faceDelegate); 0327 0328 // grouping is not very much compatible with faces 0329 0330 imageFilterModel()->setAllGroupsOpen(true); 0331 0332 // by default, Face View is categorized by Faces. 0333 0334 imageFilterModel()->setCategorizationMode(ItemSortSettings::CategoryByFaces); 0335 0336 Q_EMIT signalSeparationModeChanged((int)ItemSortSettings::CategoryByFaces); 0337 } 0338 else 0339 { 0340 imageAlbumModel()->setSpecialTagListing(QString()); 0341 setItemDelegate(d->normalDelegate); 0342 0343 bool open = ApplicationSettings::instance()->getAllGroupsOpen(); 0344 int separationMode = ApplicationSettings::instance()->getImageSeparationMode(); 0345 0346 imageFilterModel()->setAllGroupsOpen(open); 0347 imageFilterModel()->setCategorizationMode((ItemSortSettings::CategorizationMode)separationMode); 0348 0349 Q_EMIT signalSeparationModeChanged((int)separationMode); 0350 } 0351 } 0352 0353 void DigikamItemView::addRejectionOverlay(ItemDelegate* delegate) 0354 { 0355 FaceRejectionOverlay* const rejectionOverlay = new FaceRejectionOverlay(this); 0356 0357 connect(rejectionOverlay, SIGNAL(rejectFaces(QList<QModelIndex>)), 0358 this, SLOT(removeFaces(QList<QModelIndex>))); 0359 0360 addOverlay(rejectionOverlay, delegate); 0361 } 0362 0363 /* 0364 void DigikamItemView::addTagEditOverlay(ItemDelegate* delegate) 0365 { 0366 TagsLineEditOverlay* tagOverlay = new TagsLineEditOverlay(this); 0367 0368 connect(tagOverlay, SIGNAL(tagEdited(QModelIndex,QString)), 0369 this, SLOT(assignTag(QModelIndex,QString))); 0370 0371 addOverlay(tagOverlay, delegate); 0372 } 0373 */ 0374 0375 void DigikamItemView::addAssignNameOverlay(ItemDelegate* delegate) 0376 { 0377 AssignNameOverlay* const nameOverlay = new AssignNameOverlay(this); 0378 addOverlay(nameOverlay, delegate); 0379 0380 connect(nameOverlay, SIGNAL(confirmFaces(QList<QModelIndex>,int)), 0381 this, SLOT(confirmFaces(QList<QModelIndex>,int))); 0382 0383 connect(nameOverlay, SIGNAL(removeFaces(QList<QModelIndex>)), 0384 this, SLOT(rejectFaces(QList<QModelIndex>))); 0385 0386 connect(nameOverlay, SIGNAL(unknownFaces(QList<QModelIndex>)), 0387 this, SLOT(unknownFaces(QList<QModelIndex>))); 0388 0389 connect(nameOverlay, SIGNAL(ignoreFaces(QList<QModelIndex>)), 0390 this, SLOT(ignoreFaces(QList<QModelIndex>))); 0391 } 0392 0393 void DigikamItemView::confirmFaces(const QList<QModelIndex>& indexes, int tagId) 0394 { 0395 /** 0396 * You aren't allowed to "confirm" a person as 0397 * Ignored. Marking as Ignored is treated as a 0398 * changeTag() operation. 0399 */ 0400 if (FaceTags::isTheIgnoredPerson(tagId)) 0401 { 0402 rejectFaces(indexes); 0403 return; 0404 } 0405 0406 QList<ItemInfo> infos; 0407 QList<FaceTagsIface> faces; 0408 QList<QModelIndex> sourceIndexes; 0409 0410 // fast-remove in the "unknown person" view 0411 0412 Album* const album = currentAlbum(); 0413 bool needFastRemove = false; 0414 0415 if (album) 0416 { 0417 needFastRemove = (d->faceMode && (tagId != album->id())); 0418 } 0419 0420 Q_FOREACH (const QModelIndex& index, indexes) 0421 { 0422 faces << d->faceDelegate->face(index); 0423 infos << ItemModel::retrieveItemInfo(index); 0424 0425 if (needFastRemove) 0426 { 0427 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index); 0428 } 0429 } 0430 0431 imageAlbumModel()->removeIndexes(sourceIndexes); 0432 0433 for (int i = 0 ; i < infos.size() ; ++i) 0434 { 0435 d->editPipeline.confirm(infos[i], faces[i], tagId); 0436 } 0437 0438 clearSelection(); 0439 } 0440 0441 void DigikamItemView::removeFaces(const QList<QModelIndex>& indexes) 0442 { 0443 QList<ItemInfo> infos; 0444 QList<FaceTagsIface> faces; 0445 QList<QModelIndex> sourceIndexes; 0446 0447 Q_FOREACH (const QModelIndex& index, indexes) 0448 { 0449 faces << d->faceDelegate->face(index); 0450 infos << ItemModel::retrieveItemInfo(index); 0451 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index); 0452 } 0453 0454 imageAlbumModel()->removeIndexes(sourceIndexes); 0455 0456 for (int i = 0 ; i < infos.size() ; ++i) 0457 { 0458 d->editPipeline.remove(infos[i], faces[i]); 0459 } 0460 0461 clearSelection(); 0462 } 0463 0464 void DigikamItemView::unknownFaces(const QList<QModelIndex>& indexes) 0465 { 0466 QList<ItemInfo> infos; 0467 QList<FaceTagsIface> faces; 0468 QList<QModelIndex> sourceIndexes; 0469 0470 Q_FOREACH (const QModelIndex& index, indexes) 0471 { 0472 faces << d->faceDelegate->face(index); 0473 infos << ItemModel::retrieveItemInfo(index); 0474 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index); 0475 } 0476 0477 imageAlbumModel()->removeIndexes(sourceIndexes); 0478 0479 for (int i = 0 ; i < infos.size() ; ++i) 0480 { 0481 d->editPipeline.editTag(infos[i], faces[i], 0482 FaceTags::unknownPersonTagId()); 0483 } 0484 0485 clearSelection(); 0486 } 0487 0488 void DigikamItemView::rejectFaces(const QList<QModelIndex>& indexes) 0489 { 0490 QList<ItemInfo> infos; 0491 QList<FaceTagsIface> faces; 0492 QList<QModelIndex> sourceIndexes; 0493 0494 Q_FOREACH (const QModelIndex& index, indexes) 0495 { 0496 faces << d->faceDelegate->face(index); 0497 infos << ItemModel::retrieveItemInfo(index); 0498 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index); 0499 } 0500 0501 imageAlbumModel()->removeIndexes(sourceIndexes); 0502 0503 for (int i = 0 ; i < infos.size() ; ++i) 0504 { 0505 if (FaceTags::isTheUnknownPerson(faces[i].tagId())) 0506 { 0507 // Reject signal was sent from an Unknown Face. Mark as Ignored. 0508 0509 d->editPipeline.editTag(infos[i], faces[i], FaceTags::ignoredPersonTagId()); 0510 } 0511 else if (FaceTags::isTheIgnoredPerson(faces[i].tagId())) 0512 { 0513 // Reject signal was sent from an Ignored Face. Remove face. 0514 0515 d->editPipeline.remove(infos[i], faces[i]); 0516 } 0517 else 0518 { 0519 // Reject face suggestion. Mark as Unknown. 0520 0521 d->editPipeline.editTag(infos[i], faces[i], FaceTags::unknownPersonTagId()); 0522 } 0523 } 0524 0525 clearSelection(); 0526 } 0527 0528 void DigikamItemView::ignoreFaces(const QList<QModelIndex>& indexes) 0529 { 0530 QList<ItemInfo> infos; 0531 QList<FaceTagsIface> faces; 0532 QList<QModelIndex> sourceIndexes; 0533 0534 Q_FOREACH (const QModelIndex& index, indexes) 0535 { 0536 faces << d->faceDelegate->face(index); 0537 infos << ItemModel::retrieveItemInfo(index); 0538 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index); 0539 } 0540 0541 imageAlbumModel()->removeIndexes(sourceIndexes); 0542 0543 for (int i = 0 ; i < infos.size() ; ++i) 0544 { 0545 d->editPipeline.editTag(infos[i], faces[i], 0546 FaceTags::ignoredPersonTagId()); 0547 } 0548 0549 clearSelection(); 0550 } 0551 0552 QList<int> DigikamItemView::getFaceIds(const QList<QModelIndex>& indexes) const 0553 { 0554 QList<int> ids; 0555 0556 Q_FOREACH (const QModelIndex& index, indexes) 0557 { 0558 ids << d->faceDelegate->face(index).tagId(); 0559 } 0560 0561 return ids; 0562 } 0563 0564 void DigikamItemView::activated(const ItemInfo& info, Qt::KeyboardModifiers modifiers) 0565 { 0566 if (info.isNull()) 0567 { 0568 return; 0569 } 0570 0571 if (modifiers != Qt::AltModifier) 0572 { 0573 int leftClickAction = ApplicationSettings::instance()->getItemLeftClickAction(); 0574 0575 if (leftClickAction == ApplicationSettings::ShowPreview) 0576 { 0577 Q_EMIT previewRequested(info); 0578 } 0579 else if (leftClickAction == ApplicationSettings::StartEditor) 0580 { 0581 openFile(info); 0582 } 0583 else if (leftClickAction == ApplicationSettings::ShowOnTable) 0584 { 0585 d->utilities->insertToLightTable(allItemInfos(), info, false); 0586 } 0587 else 0588 { 0589 d->utilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info); 0590 } 0591 } 0592 else 0593 { 0594 d->utilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info); 0595 } 0596 } 0597 0598 void DigikamItemView::showContextMenuOnInfo(QContextMenuEvent* event, const ItemInfo& info) 0599 { 0600 Q_EMIT signalShowContextMenuOnInfo(event, info, QList<QAction*>(), imageFilterModel()); 0601 } 0602 0603 void DigikamItemView::showGroupContextMenu(const QModelIndex& index, QContextMenuEvent* event) 0604 { 0605 Q_UNUSED(index); 0606 Q_EMIT signalShowGroupContextMenu(event, selectedItemInfosCurrentFirst(), imageFilterModel()); 0607 } 0608 0609 void DigikamItemView::showContextMenu(QContextMenuEvent* event) 0610 { 0611 Q_EMIT signalShowContextMenu(event); 0612 } 0613 0614 void DigikamItemView::openFile(const ItemInfo& info) 0615 { 0616 d->utilities->openInfos(info, allItemInfos(), currentAlbum()); 0617 } 0618 0619 void DigikamItemView::deleteSelected(const ItemViewUtilities::DeleteMode deleteMode) 0620 { 0621 ItemInfoList imageInfoList = selectedItemInfos(true); 0622 0623 if (d->utilities->deleteImages(imageInfoList, deleteMode)) 0624 { 0625 awayFromSelection(); 0626 } 0627 } 0628 0629 void DigikamItemView::deleteSelectedDirectly(const ItemViewUtilities::DeleteMode deleteMode) 0630 { 0631 ItemInfoList imageInfoList = selectedItemInfos(true); 0632 0633 d->utilities->deleteImagesDirectly(imageInfoList, deleteMode); 0634 awayFromSelection(); 0635 } 0636 0637 void DigikamItemView::assignRating(const QList<QModelIndex>& indexes, int rating) 0638 { 0639 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata); 0640 FileActionMngr::instance()->assignRating(infos, rating); 0641 } 0642 0643 void DigikamItemView::groupIndicatorClicked(const QModelIndex& index) 0644 { 0645 ItemInfo info = imageFilterModel()->imageInfo(index); 0646 0647 if (info.isNull()) 0648 { 0649 return; 0650 } 0651 0652 setCurrentIndex(index); 0653 imageFilterModel()->toggleGroupOpen(info.id()); 0654 imageAlbumModel()->ensureHasGroupedImages(info); 0655 } 0656 0657 void DigikamItemView::rename() 0658 { 0659 ItemInfoList infos = selectedItemInfos(); 0660 0661 if (needGroupResolving(ApplicationSettings::Rename, infos)) 0662 { 0663 infos = resolveGrouping(infos); 0664 } 0665 0666 QList<QUrl> urls = infos.toImageUrlList(); 0667 bool loop = false; 0668 NewNamesList newNamesList; 0669 0670 do 0671 { 0672 qCDebug(DIGIKAM_GENERAL_LOG) << "Selected URLs to rename: " << urls; 0673 0674 QPointer<AdvancedRenameDialog> dlg = new AdvancedRenameDialog(this); 0675 dlg->slotAddImages(urls); 0676 0677 if (dlg->exec() != QDialog::Accepted) 0678 { 0679 delete dlg; 0680 break; 0681 } 0682 0683 if (!loop) 0684 { 0685 QUrl nextUrl = nextInOrder(infos.last(), 1).fileUrl(); 0686 setCurrentUrl(nextUrl); 0687 loop = true; 0688 } 0689 0690 newNamesList = dlg->newNames(); 0691 delete dlg; 0692 0693 setFocus(); 0694 qApp->processEvents(); 0695 0696 if (!newNamesList.isEmpty()) 0697 { 0698 QPointer<AdvancedRenameProcessDialog> dlg2 = new AdvancedRenameProcessDialog(newNamesList, this); 0699 (void)dlg2->exec(); 0700 0701 imageFilterModel()->invalidate(); 0702 urls = dlg2->failedUrls(); 0703 delete dlg2; 0704 } 0705 } 0706 while (!urls.isEmpty() && !newNamesList.isEmpty()); 0707 } 0708 0709 void DigikamItemView::slotRotateLeft(const QList<QModelIndex>& indexes) 0710 { 0711 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata); 0712 FileActionMngr::instance()->transform(infos, MetaEngineRotation::Rotate270); 0713 } 0714 0715 void DigikamItemView::slotRotateRight(const QList<QModelIndex>& indexes) 0716 { 0717 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata); 0718 FileActionMngr::instance()->transform(infos, MetaEngineRotation::Rotate90); 0719 } 0720 0721 void DigikamItemView::slotFullscreen(const QList<QModelIndex>& indexes) 0722 { 0723 QList<ItemInfo> infos = imageInfos(indexes, ApplicationSettings::Slideshow); 0724 0725 if (infos.isEmpty()) 0726 { 0727 return; 0728 } 0729 0730 // Just fullscreen the first. 0731 0732 const ItemInfo& info = infos.at(0); 0733 0734 QList<DPluginAction*> actions = DPluginLoader::instance()-> 0735 pluginActions(QLatin1String("org.kde.digikam.plugin.generic.SlideShow"), 0736 DigikamApp::instance()); 0737 0738 if (actions.isEmpty()) 0739 { 0740 return; 0741 } 0742 0743 // Trigger SlideShow manual 0744 0745 actions[0]->setData(info.fileUrl()); 0746 actions[0]->trigger(); 0747 } 0748 0749 void DigikamItemView::slotInitProgressIndicator() 0750 { 0751 if (!ProgressManager::instance()->findItembyId(QLatin1String("FaceActionProgress"))) 0752 { 0753 FileActionProgress* const item = new FileActionProgress(QLatin1String("FaceActionProgress")); 0754 0755 connect(&d->editPipeline, SIGNAL(started(QString)), 0756 item, SLOT(slotProgressStatus(QString))); 0757 0758 connect(&d->editPipeline, SIGNAL(progressValueChanged(float)), 0759 item, SLOT(slotProgressValue(float))); 0760 0761 connect(&d->editPipeline, SIGNAL(finished()), 0762 item, SLOT(slotCompleted())); 0763 } 0764 } 0765 0766 void DigikamItemView::scrollTo(const QModelIndex& index, ScrollHint hint) 0767 { 0768 // we do not want to change the view, when in the "Thumbnails" view in "People" 0769 // see bugs 444692, 40232, ... 0770 0771 bool runningFaceAction = (ProgressManager::instance()->findItembyId(QLatin1String("FacesDetector")) || 0772 ProgressManager::instance()->findItembyId(QLatin1String("FaceActionProgress"))); 0773 0774 if ((viewMode() == QListView::IconMode) && getFaceMode() && runningFaceAction) 0775 { 0776 return; 0777 } 0778 0779 ItemCategorizedView::scrollTo(index, hint); 0780 } 0781 0782 } // namespace Digikam 0783 0784 #include "moc_digikamitemview.cpp"