File indexing completed on 2025-01-19 03:50:46

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2002-16-10
0007  * Description : Item icon view interface - View methods.
0008  *
0009  * SPDX-FileCopyrightText: 2002-2005 by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2002-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2009-2011 by Johannes Wienke <languitar at semipol dot de>
0012  * SPDX-FileCopyrightText: 2010-2011 by Andi Clemens <andi dot clemens at gmail dot com>
0013  * SPDX-FileCopyrightText: 2011-2013 by Michael G. Hansen <mike at mghansen dot de>
0014  * SPDX-FileCopyrightText: 2014-2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0015  * SPDX-FileCopyrightText: 2017      by Simon Frei <freisim93 at gmail dot com>
0016  *
0017  * SPDX-License-Identifier: GPL-2.0-or-later
0018  *
0019  * ============================================================ */
0020 
0021 #include "itemiconview_p.h"
0022 
0023 namespace Digikam
0024 {
0025 
0026 void ItemIconView::connectIconViewFilter(FilterStatusBar* const filterbar)
0027 {
0028     ItemAlbumFilterModel* const model = d->iconView->imageAlbumFilterModel();
0029 
0030     connect(model, SIGNAL(filterMatches(bool)),
0031             filterbar, SLOT(slotFilterMatches(bool)));
0032 
0033     connect(model, SIGNAL(filterSettingsChanged(ItemFilterSettings)),
0034             filterbar, SLOT(slotFilterSettingsChanged(ItemFilterSettings)));
0035 
0036     connect(filterbar, SIGNAL(signalResetFilters()),
0037             d->filterWidget, SLOT(slotResetFilters()));
0038 
0039     connect(filterbar, SIGNAL(signalPopupFiltersView()),
0040             this, SLOT(slotPopupFiltersView()));
0041 }
0042 
0043 void ItemIconView::slotEscapePreview()
0044 {
0045     if (
0046         (viewMode() == StackedView::IconViewMode)  ||
0047         (viewMode() == StackedView::MapWidgetMode) ||
0048         (viewMode() == StackedView::TableViewMode) ||
0049         (viewMode() == StackedView::TrashViewMode) ||
0050         (viewMode() == StackedView::WelcomePageMode)
0051        )
0052     {
0053         return;
0054     }
0055 
0056     // pass a null image info, because we want to fall back to the old view mode
0057 
0058     slotTogglePreviewMode(ItemInfo());
0059 }
0060 
0061 void ItemIconView::slotMapWidgetView()
0062 {
0063     d->stackedView->setViewMode(StackedView::MapWidgetMode);
0064 }
0065 
0066 void ItemIconView::slotTableView()
0067 {
0068     d->stackedView->setViewMode(StackedView::TableViewMode);
0069 }
0070 
0071 void ItemIconView::slotIconView()
0072 {
0073     if (viewMode() == StackedView::PreviewImageMode)
0074     {
0075         Q_EMIT signalThumbSizeChanged(d->thumbSize);
0076     }
0077 
0078     // and switch to icon view
0079 
0080     d->stackedView->setViewMode(StackedView::IconViewMode);
0081 
0082     // make sure the next/previous buttons are updated
0083 
0084     slotImageSelected();
0085 }
0086 
0087 void ItemIconView::slotImagePreview()
0088 {
0089     slotTogglePreviewMode(currentInfo());
0090 }
0091 
0092 /**
0093  * @brief This method toggles between AlbumView/MapWidgetView and ImagePreview modes, depending on the context.
0094  */
0095 void ItemIconView::slotTogglePreviewMode(const ItemInfo& info)
0096 {
0097     if (((viewMode() == StackedView::IconViewMode)   ||
0098          (viewMode() == StackedView::TableViewMode)  ||
0099          (viewMode() == StackedView::MapWidgetMode)) && !info.isNull())
0100     {
0101         if (info.isLocationAvailable())
0102         {
0103             d->lastViewMode = viewMode();
0104 
0105             if (viewMode() == StackedView::IconViewMode)
0106             {
0107                 d->stackedView->setPreviewItem(info, d->iconView->previousInfo(info), d->iconView->nextInfo(info));
0108             }
0109             else
0110             {
0111                 d->stackedView->setPreviewItem(info, ItemInfo(), ItemInfo());
0112             }
0113         }
0114         else
0115         {
0116             QModelIndex index = d->iconView->indexForInfo(info);
0117             d->iconView->showIndexNotification(index,
0118                                                i18nc("@info: item icon view", "The storage location of this image\nis currently not available"));
0119         }
0120     }
0121     else
0122     {
0123         // go back to either AlbumViewMode or MapWidgetMode
0124 
0125         d->stackedView->setViewMode(d->lastViewMode);
0126     }
0127 
0128     // make sure the next/previous buttons are updated
0129 
0130     slotImageSelected();
0131 }
0132 
0133 void ItemIconView::slotViewModeChanged()
0134 {
0135     toggleZoomActions();
0136 
0137     switch (viewMode())
0138     {
0139         case StackedView::IconViewMode:
0140         {
0141             Q_EMIT signalSwitchedToIconView();
0142             Q_EMIT signalThumbSizeChanged(d->thumbSize);
0143             break;
0144         }
0145 
0146         case StackedView::PreviewImageMode:
0147         {
0148             Q_EMIT signalSwitchedToPreview();
0149             slotZoomFactorChanged(d->stackedView->zoomFactor());
0150             break;
0151         }
0152 
0153         case StackedView::WelcomePageMode:
0154         {
0155             Q_EMIT signalSwitchedToIconView();
0156             break;
0157         }
0158 
0159         case StackedView::MediaPlayerMode:
0160         {
0161             Q_EMIT signalSwitchedToPreview();
0162             break;
0163         }
0164 
0165         case StackedView::MapWidgetMode:
0166         {
0167             Q_EMIT signalSwitchedToMapView();
0168             // TODO: connect map view's zoom buttons to main status bar zoom buttons
0169             break;
0170         }
0171 
0172         case StackedView::TableViewMode:
0173         {
0174             Q_EMIT signalSwitchedToTableView();
0175             Q_EMIT signalThumbSizeChanged(d->thumbSize);
0176             break;
0177         }
0178 
0179         case StackedView::TrashViewMode:
0180         {
0181             d->msgNotifyTimer->stop();
0182             d->errorWidget->animatedHide();
0183 
0184             Q_EMIT signalSwitchedToTrashView();
0185             break;
0186         }
0187     }
0188 }
0189 
0190 void ItemIconView::toggleShowBar(bool b)
0191 {
0192     d->stackedView->thumbBarDock()->showThumbBar(b);
0193 
0194     // See bug #319876 : force to reload current view mode to set thumbbar visibility properly.
0195 
0196     d->stackedView->setViewMode(viewMode());
0197 }
0198 
0199 StackedView::StackedViewMode ItemIconView::viewMode() const
0200 {
0201     return d->stackedView->viewMode();
0202 }
0203 
0204 void ItemIconView::slotSetupMetadataFilters(int tab)
0205 {
0206     Setup::execMetadataFilters(this, tab);
0207 }
0208 
0209 void ItemIconView::slotSetupExifTool()
0210 {
0211     Setup::execExifTool(this);
0212 }
0213 
0214 void ItemIconView::toggleFullScreen(bool set)
0215 {
0216     d->stackedView->imagePreviewView()->toggleFullScreen(set);
0217 }
0218 
0219 void ItemIconView::setToolsIconView(DCategorizedView* const view)
0220 {
0221     d->rightSideBar->appendTab(view,
0222                                QIcon::fromTheme(QLatin1String("document-edit")),
0223                                i18nc("@title: item icon view", "Tools"));
0224 }
0225 
0226 void ItemIconView::refreshView()
0227 {
0228     d->rightSideBar->refreshTagsView();
0229 }
0230 
0231 void ItemIconView::slotShowContextMenu(QContextMenuEvent* event,
0232                                       const QList<QAction*>& extraGroupingActions)
0233 {
0234     Album* const album = currentAlbum();
0235 
0236     if (!album          ||
0237         album->isRoot() ||
0238         ((album->type() != Album::PHYSICAL) && (album->type() != Album::TAG)))
0239     {
0240         return;
0241     }
0242 
0243     QMenu menu(this);
0244     ContextMenuHelper cmHelper(&menu);
0245 
0246     cmHelper.addAction(QLatin1String("full_screen"));
0247     cmHelper.addAction(QLatin1String("options_show_menubar"));
0248     cmHelper.addSeparator();
0249     cmHelper.addStandardActionPaste(this, SLOT(slotImagePaste()));
0250 
0251     if (!extraGroupingActions.isEmpty())
0252     {
0253         cmHelper.addSeparator();
0254         cmHelper.addGroupMenu(QList<qlonglong>(), extraGroupingActions);
0255     }
0256 
0257     cmHelper.exec(event->globalPos());
0258 }
0259 
0260 void ItemIconView::slotShowContextMenuOnInfo(QContextMenuEvent* event, const ItemInfo& info,
0261                                             const QList<QAction*>& extraGroupingActions,
0262                                             ItemFilterModel* imageFilterModel)
0263 {
0264     QList<qlonglong> selectedImageIds = selectedInfoList(true, true).toImageIdList();
0265 
0266     // --------------------------------------------------------
0267 
0268     QMenu menu(this);
0269     ContextMenuHelper cmHelper(&menu);
0270     cmHelper.setItemFilterModel(imageFilterModel);
0271 
0272     cmHelper.addAction(QLatin1String("full_screen"));
0273     cmHelper.addAction(QLatin1String("options_show_menubar"));
0274     cmHelper.addSeparator();
0275 
0276     // --------------------------------------------------------
0277 
0278     QAction* const viewAction = new QAction(i18nc("@action: View the selected image", "Preview"), this);
0279     viewAction->setIcon(QIcon::fromTheme(QLatin1String("view-preview")));
0280     viewAction->setEnabled(selectedImageIds.count() == 1);
0281     cmHelper.addAction(viewAction);
0282 
0283     cmHelper.addOpenAndNavigateActions(selectedImageIds);
0284     cmHelper.addSeparator();
0285 
0286     // --------------------------------------------------------
0287 
0288     cmHelper.addAction(QLatin1String("image_scan_for_faces"));
0289     cmHelper.addAction(QLatin1String("image_recognize_faces"));
0290     cmHelper.addAction(QLatin1String("image_remove_all_faces"));
0291     cmHelper.addSeparator();
0292 
0293     // --------------------------------------------------------
0294 
0295     cmHelper.addAction(QLatin1String("image_find_similar"));
0296     cmHelper.addStandardActionLightTable();
0297     cmHelper.addQueueManagerMenu();
0298     cmHelper.addSeparator();
0299 
0300     // --------------------------------------------------------
0301 
0302     cmHelper.addAction(QLatin1String("image_rotate"));
0303     cmHelper.addAction(QLatin1String("cut_album_selection"));
0304     cmHelper.addAction(QLatin1String("copy_album_selection"));
0305     cmHelper.addAction(QLatin1String("paste_album_selection"));
0306     cmHelper.addAction(QLatin1String("image_rename"));
0307     cmHelper.addStandardActionItemDelete(this, SLOT(slotImageDelete()), selectedImageIds.count());
0308     cmHelper.addSeparator();
0309 
0310     // --------------------------------------------------------
0311 
0312     cmHelper.addIQSAction(this, SLOT(slotImageQualitySorter()));
0313     cmHelper.addSeparator();
0314 
0315     // --------------------------------------------------------
0316 
0317     cmHelper.addStandardActionThumbnail(selectedImageIds, currentAlbum());
0318     cmHelper.addAssignTagsMenu(selectedImageIds);
0319     cmHelper.addRemoveTagsMenu(selectedImageIds);
0320     cmHelper.addRemoveAllTags(selectedImageIds);
0321     cmHelper.addLabelsAction();
0322 
0323     if (d->leftSideBar->getActiveTab() != d->peopleSideBar)
0324     {
0325         cmHelper.addSeparator();
0326 
0327         cmHelper.addGroupMenu(selectedImageIds, extraGroupingActions);
0328     }
0329 
0330     // special action handling --------------------------------
0331 
0332     connect(&cmHelper, SIGNAL(signalAssignColorLabel(int)),
0333             this, SLOT(slotAssignColorLabel(int)));
0334 
0335     connect(&cmHelper, SIGNAL(signalAssignPickLabel(int)),
0336             this, SLOT(slotAssignPickLabel(int)));
0337 
0338     connect(&cmHelper, SIGNAL(signalAssignRating(int)),
0339             this, SLOT(slotAssignRating(int)));
0340 
0341     connect(&cmHelper, SIGNAL(signalAssignTag(int)),
0342             this, SLOT(slotAssignTag(int)));
0343 
0344     connect(&cmHelper, SIGNAL(signalRemoveTag(int)),
0345             this, SLOT(slotRemoveTag(int)));
0346 
0347     connect(&cmHelper, SIGNAL(signalPopupTagsView()),
0348             d->rightSideBar, SLOT(slotPopupTagsView()));
0349 
0350     connect(&cmHelper, SIGNAL(signalGotoTag(int)),
0351             this, SLOT(slotGotoTagAndItem(int)));
0352 
0353     connect(&cmHelper, SIGNAL(signalGotoTag(int)),
0354             d->albumHistory, SLOT(slotClearSelectTAlbum(int)));
0355 
0356     connect(&cmHelper, SIGNAL(signalGotoAlbum(ItemInfo)),
0357             this, SLOT(slotGotoAlbumAndItem(ItemInfo)));
0358 
0359     connect(&cmHelper, SIGNAL(signalGotoAlbum(ItemInfo)),
0360             d->albumHistory, SLOT(slotClearSelectPAlbum(ItemInfo)));
0361 
0362     connect(&cmHelper, SIGNAL(signalGotoDate(ItemInfo)),
0363             this, SLOT(slotGotoDateAndItem(ItemInfo)));
0364 
0365     connect(&cmHelper, SIGNAL(signalSetThumbnail(ItemInfo)),
0366             this, SLOT(slotSetAsAlbumThumbnail(ItemInfo)));
0367 
0368     connect(&cmHelper, SIGNAL(signalAddToExistingQueue(int)),
0369             this, SLOT(slotImageAddToExistingQueue(int)));
0370 
0371     connect(&cmHelper, SIGNAL(signalCreateGroup()),
0372             this, SLOT(slotCreateGroupFromSelection()));
0373 
0374     connect(&cmHelper, SIGNAL(signalCreateGroupByTime()),
0375             this, SLOT(slotCreateGroupByTimeFromSelection()));
0376 
0377     connect(&cmHelper, SIGNAL(signalCreateGroupByFilename()),
0378             this, SLOT(slotCreateGroupByFilenameFromSelection()));
0379 
0380     connect(&cmHelper, SIGNAL(signalCreateGroupByTimelapse()),
0381             this, SLOT(slotCreateGroupByTimelapseFromSelection()));
0382 
0383     connect(&cmHelper, SIGNAL(signalRemoveFromGroup()),
0384             this, SLOT(slotRemoveSelectedFromGroup()));
0385 
0386     connect(&cmHelper, SIGNAL(signalUngroup()),
0387             this, SLOT(slotUngroupSelected()));
0388 
0389     // --------------------------------------------------------
0390 
0391     QAction* const choice = cmHelper.exec(event->globalPos());
0392 
0393     if (choice && (choice == viewAction))
0394     {
0395         slotTogglePreviewMode(info);
0396     }
0397 }
0398 
0399 void ItemIconView::slotShowGroupContextMenu(QContextMenuEvent* event,
0400                                            const QList<ItemInfo>& selectedInfos,
0401                                            ItemFilterModel* imageFilterModel)
0402 {
0403     QList<qlonglong> selectedImageIDs;
0404 
0405     Q_FOREACH (const ItemInfo& info, selectedInfos)
0406     {
0407         selectedImageIDs << info.id();
0408     }
0409 
0410     QMenu popmenu(this);
0411     ContextMenuHelper cmhelper(&popmenu);
0412     cmhelper.setItemFilterModel(imageFilterModel);
0413     cmhelper.addGroupActions(selectedImageIDs);
0414 
0415     // special action handling --------------------------------
0416 
0417     connect(&cmhelper, SIGNAL(signalCreateGroup()),
0418             this, SLOT(slotCreateGroupFromSelection()));
0419 
0420     connect(&cmhelper, SIGNAL(signalCreateGroupByTime()),
0421             this, SLOT(slotCreateGroupByTimeFromSelection()));
0422 
0423     connect(&cmhelper, SIGNAL(signalCreateGroupByFilename()),
0424             this, SLOT(slotCreateGroupByFilenameFromSelection()));
0425 
0426     connect(&cmhelper, SIGNAL(signalCreateGroupByTimelapse()),
0427             this, SLOT(slotCreateGroupByTimelapseFromSelection()));
0428 
0429     connect(&cmhelper, SIGNAL(signalUngroup()),
0430             this, SLOT(slotUngroupSelected()));
0431 
0432     connect(&cmhelper, SIGNAL(signalRemoveFromGroup()),
0433             this, SLOT(slotRemoveSelectedFromGroup()));
0434 
0435     cmhelper.exec(event->globalPos());
0436 }
0437 
0438 } // namespace Digikam