1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2009-04-24
7 * Description : Qt model-view for items
8 *
9 * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10 * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11 * Copyright (C) 2011 by Andi Clemens <andi dot clemens at gmail dot com>
12 * Copyright (C) 2013 by Michael G. Hansen <mike at mghansen dot de>
13 * Copyright (C) 2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
14 * Copyright (C) 2017 by Simon Frei <freisim93 at gmail dot com>
15 *
16 * This program is free software you can redistribute it
17 * and/or modify it under the terms of the GNU General
18 * Public License as published by the Free Software Foundation
19 * either version 2, or (at your option)
20 * any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * ============================================================ */
28
29 #include "digikamitemview_p.h"
30
31 // Qt includes
32
33 #include <QApplication>
34 #include <QPointer>
35 #include <QAction>
36 #include <QMenu>
37 #include <QIcon>
38 #include <QUrl>
39
40 // Local includes
41
42 #include "digikam_debug.h"
43 #include "albummanager.h"
44 #include "coredb.h"
45 #include "coredboperationgroup.h"
46 #include "advancedrenamedialog.h"
47 #include "advancedrenameprocessdialog.h"
48 #include "applicationsettings.h"
49 #include "assignnameoverlay.h"
50 #include "contextmenuhelper.h"
51 #include "coredbaccess.h"
52 #include "ddragobjects.h"
53 #include "digikamapp.h"
54 #include "digikamitemdelegate.h"
55 #include "itemfacedelegate.h"
56 #include "dio.h"
57 #include "groupindicatoroverlay.h"
58 #include "itemalbumfiltermodel.h"
59 #include "itemalbummodel.h"
60 #include "itemdragdrop.h"
61 #include "itemratingoverlay.h"
62 #include "itemfullscreenoverlay.h"
63 #include "itemcoordinatesoverlay.h"
64 #include "tagslineeditoverlay.h"
65 #include "itemviewutilities.h"
66 #include "imagewindow.h"
67 #include "fileactionmngr.h"
68 #include "fileactionprogress.h"
69 #include "thumbnailloadthread.h"
70 #include "tagregion.h"
71 #include "addtagslineedit.h"
72 #include "facerejectionoverlay.h"
73 #include "facetagsiface.h"
74
75 namespace Digikam
76 {
77
DigikamItemView(QWidget * const parent)78 DigikamItemView::DigikamItemView(QWidget* const parent)
79 : ItemCategorizedView(parent),
80 d (new Private(this))
81 {
82 installDefaultModels();
83
84 d->editPipeline.plugDatabaseEditor();
85 d->editPipeline.plugTrainer();
86 d->editPipeline.construct();
87
88 connect(&d->editPipeline, SIGNAL(scheduled()),
89 this, SLOT(slotInitProgressIndicator()));
90
91 d->normalDelegate = new DigikamItemDelegate(this);
92 d->faceDelegate = new ItemFaceDelegate(this);
93
94 setItemDelegate(d->normalDelegate);
95 setSpacing(10);
96
97 ApplicationSettings* const settings = ApplicationSettings::instance();
98
99 imageFilterModel()->setCategorizationMode(ItemSortSettings::CategoryByAlbum);
100
101 imageAlbumModel()->setThumbnailLoadThread(ThumbnailLoadThread::defaultIconViewThread());
102
103 // Virtual method: use Dynamic binding.
104
105 this->setThumbnailSize(ThumbnailSize(settings->getDefaultIconSize()));
106
107 imageAlbumModel()->setPreloadThumbnails(true);
108
109 imageModel()->setDragDropHandler(new ItemDragDropHandler(imageModel()));
110 setDragEnabled(true);
111 setAcceptDrops(true);
112 setDropIndicatorShown(false);
113
114 setToolTipEnabled(settings->showToolTipsIsValid());
115 imageFilterModel()->setStringTypeNatural(settings->isStringTypeNatural());
116 imageFilterModel()->setSortRole((ItemSortSettings::SortRole)settings->getImageSortOrder());
117 imageFilterModel()->setSortOrder((ItemSortSettings::SortOrder)settings->getImageSorting());
118 imageFilterModel()->setCategorizationMode((ItemSortSettings::CategorizationMode)settings->getImageSeparationMode());
119 imageFilterModel()->setCategorizationSortOrder((ItemSortSettings::SortOrder) settings->getImageSeparationSortOrder());
120
121 // selection overlay
122
123 addSelectionOverlay(d->normalDelegate);
124 addSelectionOverlay(d->faceDelegate);
125
126 // rotation overlays
127
128 d->rotateLeftOverlay = ItemRotateOverlay::left(this);
129 d->rotateRightOverlay = ItemRotateOverlay::right(this);
130 d->fullscreenOverlay = ItemFullScreenOverlay::instance(this);
131 d->updateOverlays();
132
133 // rating overlay
134
135 ItemRatingOverlay* const ratingOverlay = new ItemRatingOverlay(this);
136 addOverlay(ratingOverlay);
137
138 // face overlays
139 // NOTE: order to plug this overlay is important, else rejection cant be suitable (see bug #324759).
140
141 addAssignNameOverlay(d->faceDelegate);
142 addRejectionOverlay(d->faceDelegate);
143
144 GroupIndicatorOverlay* const groupOverlay = new GroupIndicatorOverlay(this);
145 addOverlay(groupOverlay);
146
147 addOverlay(new ItemCoordinatesOverlay(this));
148
149 connect(ratingOverlay, SIGNAL(ratingEdited(QList<QModelIndex>,int)),
150 this, SLOT(assignRating(QList<QModelIndex>,int)));
151
152 connect(groupOverlay, SIGNAL(toggleGroupOpen(QModelIndex)),
153 this, SLOT(groupIndicatorClicked(QModelIndex)));
154
155 connect(groupOverlay, SIGNAL(showButtonContextMenu(QModelIndex,QContextMenuEvent*)),
156 this, SLOT(showGroupContextMenu(QModelIndex,QContextMenuEvent*)));
157
158 d->utilities = new ItemViewUtilities(this);
159
160 connect(imageModel()->dragDropHandler(), SIGNAL(assignTags(QList<ItemInfo>,QList<int>)),
161 FileActionMngr::instance(), SLOT(assignTags(QList<ItemInfo>,QList<int>)));
162
163 connect(imageModel()->dragDropHandler(), SIGNAL(addToGroup(ItemInfo,QList<ItemInfo>)),
164 FileActionMngr::instance(), SLOT(addToGroup(ItemInfo,QList<ItemInfo>)));
165
166 connect(imageModel()->dragDropHandler(), SIGNAL(dragDropSort(ItemInfo,QList<ItemInfo>)),
167 this, SLOT(dragDropSort(ItemInfo,QList<ItemInfo>)));
168
169 connect(d->utilities, SIGNAL(editorCurrentUrlChanged(QUrl)),
170 this, SLOT(setCurrentUrlWhenAvailable(QUrl)));
171
172 // --- NOTE: use dynamic binding as slotSetupChanged() is a virtual method which can be re-implemented in derived classes.
173
174 connect(settings, &ApplicationSettings::setupChanged,
175 this, &DigikamItemView::slotSetupChanged);
176
177 this->slotSetupChanged();
178 }
179
~DigikamItemView()180 DigikamItemView::~DigikamItemView()
181 {
182 delete d;
183 }
184
utilities() const185 ItemViewUtilities* DigikamItemView::utilities() const
186 {
187 return d->utilities;
188 }
189
setThumbnailSize(const ThumbnailSize & size)190 void DigikamItemView::setThumbnailSize(const ThumbnailSize& size)
191 {
192 imageThumbnailModel()->setPreloadThumbnailSize(size);
193 ItemCategorizedView::setThumbnailSize(size);
194 }
195
allItemInfos(bool grouping) const196 ItemInfoList DigikamItemView::allItemInfos(bool grouping) const
197 {
198 if (grouping)
199 {
200 return resolveGrouping(ItemCategorizedView::allItemInfos());
201 }
202
203 return ItemCategorizedView::allItemInfos();
204 }
205
selectedItemInfos(bool grouping) const206 ItemInfoList DigikamItemView::selectedItemInfos(bool grouping) const
207 {
208 if (grouping)
209 {
210 return resolveGrouping(ItemCategorizedView::selectedItemInfos());
211 }
212
213 return ItemCategorizedView::selectedItemInfos();
214 }
215
selectedItemInfosCurrentFirst(bool grouping) const216 ItemInfoList DigikamItemView::selectedItemInfosCurrentFirst(bool grouping) const
217 {
218 if (grouping)
219 {
220 return resolveGrouping(ItemCategorizedView::selectedItemInfosCurrentFirst());
221 }
222
223 return ItemCategorizedView::selectedItemInfosCurrentFirst();
224 }
225
dragDropSort(const ItemInfo & pick,const QList<ItemInfo> & infos)226 void DigikamItemView::dragDropSort(const ItemInfo& pick, const QList<ItemInfo>& infos)
227 {
228 if (pick.isNull() || infos.isEmpty())
229 {
230 return;
231 }
232
233 ItemInfoList infoList = allItemInfos(false);
234 qlonglong counter = pick.manualOrder();
235 bool order = (ApplicationSettings::instance()->
236 getImageSorting() == Qt::AscendingOrder);
237 bool found = false;
238
239 QApplication::setOverrideCursor(Qt::WaitCursor);
240
241 CoreDbOperationGroup group;
242 group.setMaximumTime(200);
243
244 foreach (ItemInfo info, infoList)
245 {
246 if (!found && info.id() == pick.id())
247 {
248 foreach (ItemInfo dropInfo, infos)
249 {
250 dropInfo.setManualOrder(counter);
251 counter += (order ? 1 : -1);
252 }
253
254 info.setManualOrder(counter);
255 found = true;
256 }
257 else if (found && !infos.contains(info))
258 {
259 if (( order && info.manualOrder() > counter) ||
260 (!order && info.manualOrder() < counter))
261 {
262 break;
263 }
264
265 counter += (order ? 100 : -100);
266 info.setManualOrder(counter);
267 }
268
269 group.allowLift();
270 }
271
272 QApplication::restoreOverrideCursor();
273
274 imageFilterModel()->invalidate();
275 }
276
allNeedGroupResolving(const ApplicationSettings::OperationType type) const277 bool DigikamItemView::allNeedGroupResolving(const ApplicationSettings::OperationType type) const
278 {
279 return needGroupResolving(type, allItemInfos());
280 }
281
selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const282 bool DigikamItemView::selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const
283 {
284 return needGroupResolving(type, selectedItemInfos());
285 }
286
fitToWidthIcons()287 int DigikamItemView::fitToWidthIcons()
288 {
289 return delegate()->calculatethumbSizeToFit(viewport()->size().width());
290 }
291
slotSetupChanged()292 void DigikamItemView::slotSetupChanged()
293 {
294 imageFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural());
295 setToolTipEnabled(ApplicationSettings::instance()->showToolTipsIsValid());
296 setFont(ApplicationSettings::instance()->getIconViewFont());
297
298 d->updateOverlays();
299
300 ItemCategorizedView::slotSetupChanged();
301 }
302
hasHiddenGroupedImages(const ItemInfo & info) const303 bool DigikamItemView::hasHiddenGroupedImages(const ItemInfo& info) const
304 {
305 return (info.hasGroupedImages() &&
306 !imageFilterModel()->isAllGroupsOpen() &&
307 !imageFilterModel()->isGroupOpen(info.id()));
308 }
309
imageInfos(const QList<QModelIndex> & indexes,ApplicationSettings::OperationType type) const310 ItemInfoList DigikamItemView::imageInfos(const QList<QModelIndex>& indexes,
311 ApplicationSettings::OperationType type) const
312 {
313 ItemInfoList infos = ItemCategorizedView::imageInfos(indexes);
314
315 if (needGroupResolving(type, infos))
316 {
317 return resolveGrouping(infos);
318 }
319
320 return infos;
321 }
322
getFaceMode() const323 bool DigikamItemView::getFaceMode() const
324 {
325 return d->faceMode;
326 }
327
setFaceMode(bool on)328 void DigikamItemView::setFaceMode(bool on)
329 {
330 d->faceMode = on;
331
332 if (on)
333 {
334 // See ItemLister, which creates a search the implements listing tag in the ioslave
335
336 imageAlbumModel()->setSpecialTagListing(QLatin1String("faces"));
337 setItemDelegate(d->faceDelegate);
338
339 // grouping is not very much compatible with faces
340
341 imageFilterModel()->setAllGroupsOpen(true);
342
343 // by default, Face View is categorized by Faces.
344
345 imageFilterModel()->setCategorizationMode(ItemSortSettings::CategoryByFaces);
346
347 emit signalSeparationModeChanged((int)ItemSortSettings::CategoryByFaces);
348 }
349 else
350 {
351 imageAlbumModel()->setSpecialTagListing(QString());
352 setItemDelegate(d->normalDelegate);
353
354 bool open = ApplicationSettings::instance()->getAllGroupsOpen();
355 int separationMode = ApplicationSettings::instance()->getImageSeparationMode();
356
357 imageFilterModel()->setAllGroupsOpen(open);
358 imageFilterModel()->setCategorizationMode((ItemSortSettings::CategorizationMode)separationMode);
359
360 emit signalSeparationModeChanged((int)separationMode);
361 }
362 }
363
addRejectionOverlay(ItemDelegate * delegate)364 void DigikamItemView::addRejectionOverlay(ItemDelegate* delegate)
365 {
366 FaceRejectionOverlay* const rejectionOverlay = new FaceRejectionOverlay(this);
367
368 connect(rejectionOverlay, SIGNAL(rejectFaces(QList<QModelIndex>)),
369 this, SLOT(removeFaces(QList<QModelIndex>)));
370
371 addOverlay(rejectionOverlay, delegate);
372 }
373
374 /*
375 void DigikamItemView::addTagEditOverlay(ItemDelegate* delegate)
376 {
377 TagsLineEditOverlay* tagOverlay = new TagsLineEditOverlay(this);
378
379 connect(tagOverlay, SIGNAL(tagEdited(QModelIndex,QString)),
380 this, SLOT(assignTag(QModelIndex,QString)));
381
382 addOverlay(tagOverlay, delegate);
383 }
384 */
385
addAssignNameOverlay(ItemDelegate * delegate)386 void DigikamItemView::addAssignNameOverlay(ItemDelegate* delegate)
387 {
388 AssignNameOverlay* const nameOverlay = new AssignNameOverlay(this);
389 addOverlay(nameOverlay, delegate);
390
391 connect(nameOverlay, SIGNAL(confirmFaces(QList<QModelIndex>,int)),
392 this, SLOT(confirmFaces(QList<QModelIndex>,int)));
393
394 connect(nameOverlay, SIGNAL(removeFaces(QList<QModelIndex>)),
395 this, SLOT(rejectFaces(QList<QModelIndex>)));
396
397 connect(nameOverlay, SIGNAL(unknownFaces(QList<QModelIndex>)),
398 this, SLOT(unknownFaces(QList<QModelIndex>)));
399 }
400
confirmFaces(const QList<QModelIndex> & indexes,int tagId)401 void DigikamItemView::confirmFaces(const QList<QModelIndex>& indexes, int tagId)
402 {
403 /**
404 * You aren't allowed to "confirm" a person as
405 * Ignored. Marking as Ignored is treated as a
406 * changeTag() operation.
407 */
408 if (FaceTags::isTheIgnoredPerson(tagId))
409 {
410 rejectFaces(indexes);
411 return;
412 }
413
414 QList<ItemInfo> infos;
415 QList<FaceTagsIface> faces;
416 QList<QModelIndex> sourceIndexes;
417
418 // fast-remove in the "unknown person" view
419
420 Album* const album = currentAlbum();
421 bool needFastRemove = false;
422
423 if (album)
424 {
425 needFastRemove = (d->faceMode && (tagId != album->id()));
426 }
427
428 foreach (const QModelIndex& index, indexes)
429 {
430 faces << d->faceDelegate->face(index);
431 infos << ItemModel::retrieveItemInfo(index);
432
433 if (needFastRemove)
434 {
435 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index);
436 }
437 }
438
439 imageAlbumModel()->removeIndexes(sourceIndexes);
440
441 for (int i = 0 ; i < infos.size() ; ++i)
442 {
443 d->editPipeline.confirm(infos[i], faces[i], tagId);
444 }
445 }
446
removeFaces(const QList<QModelIndex> & indexes)447 void DigikamItemView::removeFaces(const QList<QModelIndex>& indexes)
448 {
449 QList<ItemInfo> infos;
450 QList<FaceTagsIface> faces;
451 QList<QModelIndex> sourceIndexes;
452
453 foreach (const QModelIndex& index, indexes)
454 {
455 faces << d->faceDelegate->face(index);
456 infos << ItemModel::retrieveItemInfo(index);
457 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index);
458 }
459
460 imageAlbumModel()->removeIndexes(sourceIndexes);
461
462 for (int i = 0 ; i < infos.size() ; ++i)
463 {
464 d->editPipeline.remove(infos[i], faces[i]);
465 }
466 }
467
unknownFaces(const QList<QModelIndex> & indexes)468 void DigikamItemView::unknownFaces(const QList<QModelIndex>& indexes)
469 {
470 QList<ItemInfo> infos;
471 QList<FaceTagsIface> faces;
472 QList<QModelIndex> sourceIndexes;
473
474 foreach (const QModelIndex& index, indexes)
475 {
476 faces << d->faceDelegate->face(index);
477 infos << ItemModel::retrieveItemInfo(index);
478 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index);
479 }
480
481 imageAlbumModel()->removeIndexes(sourceIndexes);
482
483 for (int i = 0 ; i < infos.size() ; ++i)
484 {
485 d->editPipeline.editTag(infos[i], faces[i],
486 FaceTags::unknownPersonTagId());
487 }
488 }
489
rejectFaces(const QList<QModelIndex> & indexes)490 void DigikamItemView::rejectFaces(const QList<QModelIndex>& indexes)
491 {
492 QList<ItemInfo> infos;
493 QList<FaceTagsIface> faces;
494 QList<QModelIndex> sourceIndexes;
495
496 foreach (const QModelIndex& index, indexes)
497 {
498 faces << d->faceDelegate->face(index);
499 infos << ItemModel::retrieveItemInfo(index);
500 sourceIndexes << imageSortFilterModel()->mapToSourceItemModel(index);
501 }
502
503 imageAlbumModel()->removeIndexes(sourceIndexes);
504
505 for (int i = 0 ; i < infos.size() ; ++i)
506 {
507 if (FaceTags::isTheUnknownPerson(faces[i].tagId()))
508 {
509 // Reject signal was sent from an Unknown Face. Mark as Ignored.
510
511 d->editPipeline.editTag(infos[i], faces[i], FaceTags::ignoredPersonTagId());
512 }
513 else
514 {
515 // Reject face suggestion. Mark as Unknown.
516
517 d->editPipeline.editTag(infos[i], faces[i], FaceTags::unknownPersonTagId());
518 }
519 }
520 }
521
activated(const ItemInfo & info,Qt::KeyboardModifiers modifiers)522 void DigikamItemView::activated(const ItemInfo& info, Qt::KeyboardModifiers modifiers)
523 {
524 if (info.isNull())
525 {
526 return;
527 }
528
529 if (modifiers != Qt::AltModifier)
530 {
531 int leftClickAction = ApplicationSettings::instance()->getItemLeftClickAction();
532
533 if (leftClickAction == ApplicationSettings::ShowPreview)
534 {
535 emit previewRequested(info);
536 }
537 else if (leftClickAction == ApplicationSettings::StartEditor)
538 {
539 openFile(info);
540 }
541 else
542 {
543 d->utilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info);
544 }
545 }
546 else
547 {
548 d->utilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info);
549 }
550 }
551
showContextMenuOnInfo(QContextMenuEvent * event,const ItemInfo & info)552 void DigikamItemView::showContextMenuOnInfo(QContextMenuEvent* event, const ItemInfo& info)
553 {
554 emit signalShowContextMenuOnInfo(event, info, QList<QAction*>(), imageFilterModel());
555 }
556
showGroupContextMenu(const QModelIndex & index,QContextMenuEvent * event)557 void DigikamItemView::showGroupContextMenu(const QModelIndex& index, QContextMenuEvent* event)
558 {
559 Q_UNUSED(index);
560 emit signalShowGroupContextMenu(event, selectedItemInfosCurrentFirst(), imageFilterModel());
561 }
562
showContextMenu(QContextMenuEvent * event)563 void DigikamItemView::showContextMenu(QContextMenuEvent* event)
564 {
565 emit signalShowContextMenu(event);
566 }
567
openFile(const ItemInfo & info)568 void DigikamItemView::openFile(const ItemInfo& info)
569 {
570 d->utilities->openInfos(info, allItemInfos(), currentAlbum());
571 }
572
deleteSelected(const ItemViewUtilities::DeleteMode deleteMode)573 void DigikamItemView::deleteSelected(const ItemViewUtilities::DeleteMode deleteMode)
574 {
575 ItemInfoList imageInfoList = selectedItemInfos(true);
576
577 if (d->utilities->deleteImages(imageInfoList, deleteMode))
578 {
579 awayFromSelection();
580 }
581 }
582
deleteSelectedDirectly(const ItemViewUtilities::DeleteMode deleteMode)583 void DigikamItemView::deleteSelectedDirectly(const ItemViewUtilities::DeleteMode deleteMode)
584 {
585 ItemInfoList imageInfoList = selectedItemInfos(true);
586
587 d->utilities->deleteImagesDirectly(imageInfoList, deleteMode);
588 awayFromSelection();
589 }
590
assignRating(const QList<QModelIndex> & indexes,int rating)591 void DigikamItemView::assignRating(const QList<QModelIndex>& indexes, int rating)
592 {
593 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata);
594 FileActionMngr::instance()->assignRating(infos, rating);
595 }
596
groupIndicatorClicked(const QModelIndex & index)597 void DigikamItemView::groupIndicatorClicked(const QModelIndex& index)
598 {
599 ItemInfo info = imageFilterModel()->imageInfo(index);
600
601 if (info.isNull())
602 {
603 return;
604 }
605
606 setCurrentIndex(index);
607 imageFilterModel()->toggleGroupOpen(info.id());
608 imageAlbumModel()->ensureHasGroupedImages(info);
609 }
610
rename()611 void DigikamItemView::rename()
612 {
613 ItemInfoList infos = selectedItemInfos();
614
615 if (needGroupResolving(ApplicationSettings::Rename, infos))
616 {
617 infos = resolveGrouping(infos);
618 }
619
620 QList<QUrl> urls = infos.toImageUrlList();
621 bool loop = false;
622 NewNamesList newNamesList;
623
624 do
625 {
626 qCDebug(DIGIKAM_GENERAL_LOG) << "Selected URLs to rename: " << urls;
627
628 QPointer<AdvancedRenameDialog> dlg = new AdvancedRenameDialog(this);
629 dlg->slotAddImages(urls);
630
631 if (dlg->exec() != QDialog::Accepted)
632 {
633 delete dlg;
634 break;
635 }
636
637 if (!loop)
638 {
639 QUrl nextUrl = nextInOrder(infos.last(), 1).fileUrl();
640 setCurrentUrl(nextUrl);
641 loop = true;
642 }
643
644 newNamesList = dlg->newNames();
645 delete dlg;
646
647 setFocus();
648 qApp->processEvents();
649
650 if (!newNamesList.isEmpty())
651 {
652 QPointer<AdvancedRenameProcessDialog> dlg2 = new AdvancedRenameProcessDialog(newNamesList, this);
653 (void)dlg2->exec();
654
655 imageFilterModel()->invalidate();
656 urls = dlg2->failedUrls();
657 delete dlg2;
658 }
659 }
660 while (!urls.isEmpty() && !newNamesList.isEmpty());
661 }
662
slotRotateLeft(const QList<QModelIndex> & indexes)663 void DigikamItemView::slotRotateLeft(const QList<QModelIndex>& indexes)
664 {
665 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata);
666 FileActionMngr::instance()->transform(infos, MetaEngineRotation::Rotate270);
667 }
668
slotRotateRight(const QList<QModelIndex> & indexes)669 void DigikamItemView::slotRotateRight(const QList<QModelIndex>& indexes)
670 {
671 ItemInfoList infos = imageInfos(indexes, ApplicationSettings::Metadata);
672 FileActionMngr::instance()->transform(infos, MetaEngineRotation::Rotate90);
673 }
674
slotFullscreen(const QList<QModelIndex> & indexes)675 void DigikamItemView::slotFullscreen(const QList<QModelIndex>& indexes)
676 {
677 QList<ItemInfo> infos = imageInfos(indexes, ApplicationSettings::Slideshow);
678
679 if (infos.isEmpty())
680 {
681 return;
682 }
683
684 // Just fullscreen the first.
685
686 const ItemInfo& info = infos.at(0);
687
688 QList<DPluginAction*> actions = DPluginLoader::instance()->
689 pluginActions(QLatin1String("org.kde.digikam.plugin.generic.SlideShow"),
690 DigikamApp::instance());
691
692 if (actions.isEmpty())
693 {
694 return;
695 }
696
697 // Trigger SlideShow manual
698
699 actions[0]->setData(info.fileUrl());
700 actions[0]->trigger();
701 }
702
slotInitProgressIndicator()703 void DigikamItemView::slotInitProgressIndicator()
704 {
705 if (!ProgressManager::instance()->findItembyId(QLatin1String("FaceActionProgress")))
706 {
707 FileActionProgress* const item = new FileActionProgress(QLatin1String("FaceActionProgress"));
708
709 connect(&d->editPipeline, SIGNAL(started(QString)),
710 item, SLOT(slotProgressStatus(QString)));
711
712 connect(&d->editPipeline, SIGNAL(progressValueChanged(float)),
713 item, SLOT(slotProgressValue(float)));
714
715 connect(&d->editPipeline, SIGNAL(finished()),
716 item, SLOT(slotCompleted()));
717 }
718 }
719
720 } // namespace Digikam
721