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        : 2006-06-13
0007  * Description : A widget stack to embedded album content view
0008  *               or the current image preview.
0009  *
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2013      by Michael G. Hansen <mike at mghansen dot de>
0012  * SPDX-FileCopyrightText: 2015      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "stackedview.h"
0019 
0020 // Qt includes
0021 
0022 #include <QWidget>
0023 
0024 // KDE includes
0025 
0026 #include <klocalizedstring.h>
0027 #include <kconfiggroup.h>
0028 
0029 // Local includes
0030 
0031 #include "digikam_debug.h"
0032 #include "applicationsettings.h"
0033 #include "welcomepageview.h"
0034 #include "digikamitemview.h"
0035 #include "itemiconview.h"
0036 #include "dbinfoiface.h"
0037 #include "itemalbummodel.h"
0038 #include "itemalbumfiltermodel.h"
0039 #include "dtrashitemmodel.h"
0040 #include "itempreviewview.h"
0041 #include "itemthumbnailbar.h"
0042 #include "loadingcacheinterface.h"
0043 #include "previewlayout.h"
0044 #include "tableview.h"
0045 #include "trashview.h"
0046 #include "dimg.h"
0047 
0048 #ifdef HAVE_MEDIAPLAYER
0049 #   include "mediaplayerview.h"
0050 #endif // HAVE_MEDIAPLAYER
0051 
0052 #ifdef HAVE_GEOLOCATION
0053 #   include "mapwidgetview.h"
0054 #endif // HAVE_GEOLOCATION
0055 
0056 namespace Digikam
0057 {
0058 
0059 class Q_DECL_HIDDEN StackedView::Private
0060 {
0061 public:
0062 
0063     explicit Private()
0064       : needUpdateBar   (false),
0065         syncingSelection(false),
0066         dockArea        (nullptr),
0067         imageIconView   (nullptr),
0068         thumbBar        (nullptr),
0069         imagePreviewView(nullptr),
0070         thumbBarDock    (nullptr),
0071         welcomePageView (nullptr),
0072 
0073 #ifdef HAVE_MEDIAPLAYER
0074 
0075         mediaPlayerView (nullptr),
0076 
0077 #endif // HAVE_MEDIAPLAYER
0078 
0079 #ifdef HAVE_GEOLOCATION
0080 
0081         mapWidgetView   (nullptr),
0082 
0083 #endif // HAVE_GEOLOCATION
0084 
0085         tableView       (nullptr),
0086         trashView       (nullptr)
0087     {
0088     }
0089 
0090     bool              needUpdateBar;
0091     bool              syncingSelection;
0092 
0093     QMainWindow*      dockArea;
0094 
0095     DigikamItemView*  imageIconView;
0096     ItemThumbnailBar* thumbBar;
0097     ItemPreviewView*  imagePreviewView;
0098     ThumbBarDock*     thumbBarDock;
0099     WelcomePageView*  welcomePageView;
0100 
0101     QMap<int, int>    stackMap;
0102 
0103 #ifdef HAVE_MEDIAPLAYER
0104 
0105     MediaPlayerView*  mediaPlayerView;
0106 
0107 #endif // HAVE_MEDIAPLAYER
0108 
0109 #ifdef HAVE_GEOLOCATION
0110 
0111     MapWidgetView*    mapWidgetView;
0112 
0113 #endif // HAVE_GEOLOCATION
0114 
0115     TableView*        tableView;
0116     TrashView*        trashView;
0117 };
0118 
0119 StackedView::StackedView(QWidget* const parent)
0120     : QStackedWidget(parent),
0121       d             (new Private)
0122 {
0123     d->imageIconView    = new DigikamItemView(this);
0124     d->imagePreviewView = new ItemPreviewView(this);
0125     d->thumbBarDock     = new ThumbBarDock();
0126     d->thumbBar         = new ItemThumbnailBar(d->thumbBarDock);
0127     d->thumbBar->setModelsFiltered(d->imageIconView->imageModel(),
0128                                    d->imageIconView->imageFilterModel());
0129     d->thumbBar->installOverlays();
0130     d->thumbBarDock->setWidget(d->thumbBar);
0131     d->thumbBarDock->setObjectName(QLatin1String("mainwindow_thumbbar"));
0132 
0133     d->welcomePageView  = new WelcomePageView(this);
0134 
0135     d->tableView        = new TableView(d->imageIconView->getSelectionModel(),
0136                                         d->imageIconView->imageFilterModel(),
0137                                         this);
0138     d->tableView->setObjectName(QLatin1String("mainwindow_tableview"));
0139 
0140     d->trashView        = new TrashView(this);
0141 
0142 #ifdef HAVE_GEOLOCATION
0143 
0144     d->mapWidgetView    = new MapWidgetView(d->imageIconView->getSelectionModel(),
0145                                             d->imageIconView->imageFilterModel(), this,
0146                                             MapWidgetView::ApplicationDigikam);
0147     d->mapWidgetView->setObjectName(QLatin1String("mainwindow_mapwidgetview"));
0148 
0149 #endif // HAVE_GEOLOCATION
0150 
0151 #ifdef HAVE_MEDIAPLAYER
0152 
0153     d->mediaPlayerView  = new MediaPlayerView(this);
0154     d->mediaPlayerView->setObjectName(QLatin1String("main_media_player"));
0155     d->mediaPlayerView->setInfoInterface(new DBInfoIface(this, QList<QUrl>()));
0156 
0157 #endif // HAVE_MEDIAPLAYER
0158 
0159     d->stackMap[addWidget(d->imageIconView)]    = IconViewMode;
0160     d->stackMap[addWidget(d->imagePreviewView)] = PreviewImageMode;
0161     d->stackMap[addWidget(d->welcomePageView)]  = WelcomePageMode;
0162     d->stackMap[addWidget(d->tableView)]        = TableViewMode;
0163     d->stackMap[addWidget(d->trashView)]        = TrashViewMode;
0164 
0165 #ifdef HAVE_GEOLOCATION
0166 
0167     d->stackMap[addWidget(d->mapWidgetView)]    = MapWidgetMode;
0168 
0169 #endif // HAVE_GEOLOCATION
0170 
0171 #ifdef HAVE_MEDIAPLAYER
0172 
0173     d->stackMap[addWidget(d->mediaPlayerView)]  = MediaPlayerMode;
0174 
0175 #endif // HAVE_MEDIAPLAYER
0176 
0177     setViewMode(IconViewMode);
0178     setAttribute(Qt::WA_DeleteOnClose);
0179 
0180     readSettings();
0181 
0182     // -----------------------------------------------------------------
0183 
0184     connect(d->imagePreviewView, SIGNAL(signalPopupTagsView()),
0185             this, SIGNAL(signalPopupTagsView()));
0186 
0187     connect(d->imagePreviewView, SIGNAL(signalGotoAlbumAndItem(ItemInfo)),
0188             this, SIGNAL(signalGotoAlbumAndItem(ItemInfo)));
0189 
0190     connect(d->imagePreviewView, SIGNAL(signalGotoDateAndItem(ItemInfo)),
0191             this, SIGNAL(signalGotoDateAndItem(ItemInfo)));
0192 
0193     connect(d->imagePreviewView, SIGNAL(signalGotoTagAndItem(int)),
0194             this, SIGNAL(signalGotoTagAndItem(int)));
0195 
0196     connect(d->imagePreviewView, SIGNAL(signalNextItem()),
0197             this, SIGNAL(signalNextItem()));
0198 
0199     connect(d->imagePreviewView, SIGNAL(signalPrevItem()),
0200             this, SIGNAL(signalPrevItem()));
0201 
0202     connect(d->imagePreviewView, SIGNAL(signalDeleteItem()),
0203             this, SIGNAL(signalDeleteItem()));
0204 
0205     connect(d->imagePreviewView, SIGNAL(signalEscapePreview()),
0206             this, SIGNAL(signalEscapePreview()));
0207 
0208     connect(d->imagePreviewView->layout(), SIGNAL(zoomFactorChanged(double)),
0209             this, SLOT(slotZoomFactorChanged(double)));
0210 
0211     connect(d->imagePreviewView, SIGNAL(signalAddToExistingQueue(int)),
0212             this, SIGNAL(signalAddToExistingQueue(int)));
0213 
0214     connect(d->thumbBar, SIGNAL(selectionChanged()),
0215             this, SLOT(slotThumbBarSelectionChanged()));
0216 
0217     connect(d->imageIconView, SIGNAL(selectionChanged()),
0218             this, SLOT(slotIconViewSelectionChanged()));
0219 
0220     connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
0221             d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea)));
0222 
0223     connect(d->imagePreviewView, SIGNAL(signalPreviewLoaded(bool)),
0224             this, SLOT(slotPreviewLoaded(bool)));
0225 
0226 #ifdef HAVE_MEDIAPLAYER
0227 
0228     connect(d->mediaPlayerView, SIGNAL(signalNextItem()),
0229             this, SIGNAL(signalNextItem()));
0230 
0231     connect(d->mediaPlayerView, SIGNAL(signalPrevItem()),
0232             this, SIGNAL(signalPrevItem()));
0233 
0234     connect(d->mediaPlayerView, SIGNAL(signalEscapePreview()),
0235             this, SIGNAL(signalEscapePreview()));
0236 
0237 #endif // HAVE_MEDIAPLAYER
0238 
0239 }
0240 
0241 StackedView::~StackedView()
0242 {
0243     delete d;
0244 }
0245 
0246 void StackedView::readSettings()
0247 {
0248     ApplicationSettings* settings = ApplicationSettings::instance();
0249     bool showThumbbar             = settings->getShowThumbbar();
0250     d->thumbBarDock->setShouldBeVisible(showThumbbar);
0251 }
0252 
0253 void StackedView::setDockArea(QMainWindow* dockArea)
0254 {
0255     // Attach the thumbbar dock to the given dock area and place it initially on top.
0256 
0257     d->dockArea = dockArea;
0258     d->thumbBarDock->setParent(d->dockArea);
0259     d->dockArea->addDockWidget(Qt::TopDockWidgetArea, d->thumbBarDock);
0260     d->thumbBarDock->setFloating(false);
0261 }
0262 
0263 ThumbBarDock* StackedView::thumbBarDock() const
0264 {
0265     return d->thumbBarDock;
0266 }
0267 
0268 ItemThumbnailBar* StackedView::thumbBar() const
0269 {
0270     return d->thumbBar;
0271 }
0272 
0273 DigikamItemView* StackedView::imageIconView() const
0274 {
0275     return d->imageIconView;
0276 }
0277 
0278 ItemPreviewView* StackedView::imagePreviewView() const
0279 {
0280     return d->imagePreviewView;
0281 }
0282 
0283 #ifdef HAVE_GEOLOCATION
0284 
0285 MapWidgetView* StackedView::mapWidgetView() const
0286 {
0287     return d->mapWidgetView;
0288 }
0289 
0290 #endif // HAVE_GEOLOCATION
0291 
0292 TableView* StackedView::tableView() const
0293 {
0294     return d->tableView;
0295 }
0296 
0297 TrashView* StackedView::trashView() const
0298 {
0299     return d->trashView;
0300 }
0301 
0302 #ifdef HAVE_MEDIAPLAYER
0303 
0304 MediaPlayerView* StackedView::mediaPlayerView() const
0305 {
0306     return d->mediaPlayerView;
0307 }
0308 
0309 #endif // HAVE_MEDIAPLAYER
0310 
0311 bool StackedView::isInSingleFileMode() const
0312 {
0313     return ((viewMode() == PreviewImageMode) ||
0314             (viewMode() == MediaPlayerMode));
0315 }
0316 
0317 bool StackedView::isInMultipleFileMode() const
0318 {
0319     return ((viewMode() == IconViewMode)  ||
0320             (viewMode() == MapWidgetMode) ||
0321             (viewMode() == TableViewMode));
0322 }
0323 
0324 bool StackedView::isInAbstractMode() const
0325 {
0326     return (viewMode() == WelcomePageMode);
0327 }
0328 
0329 void StackedView::setPreviewItem(const ItemInfo& info, const ItemInfo& previous, const ItemInfo& next)
0330 {
0331     if (info.isNull())
0332     {
0333         if (viewMode() == MediaPlayerMode)
0334         {
0335 
0336 #ifdef HAVE_MEDIAPLAYER
0337 
0338             d->mediaPlayerView->setCurrentItem();
0339 
0340 #endif // HAVE_MEDIAPLAYER
0341 
0342         }
0343         else if (viewMode() == PreviewImageMode)
0344         {
0345             d->imagePreviewView->setItemInfo();
0346         }
0347     }
0348     else
0349     {
0350         if ((info.category() == DatabaseItem::Audio)      ||
0351             (info.category() == DatabaseItem::Video)      ||
0352             DImg::isAnimatedImage(info.fileUrl().toLocalFile()))    // Special case for animated image as GIF or NMG
0353         {
0354             // Stop image viewer
0355 
0356             if (viewMode() == PreviewImageMode)
0357             {
0358                 d->imagePreviewView->setItemInfo();
0359             }
0360 
0361 #ifdef HAVE_MEDIAPLAYER
0362 
0363             setViewMode(MediaPlayerMode);
0364             d->mediaPlayerView->setCurrentItem(info.fileUrl(), !previous.isNull(), !next.isNull());
0365 
0366 #endif // HAVE_MEDIAPLAYER
0367 
0368         }
0369         else // Static image or Raw image.
0370         {
0371             // Stop media player if running...
0372 
0373             if (viewMode() == MediaPlayerMode)
0374             {
0375 
0376 #ifdef HAVE_MEDIAPLAYER
0377 
0378                 d->mediaPlayerView->setCurrentItem();
0379 
0380 #endif // HAVE_MEDIAPLAYER
0381 
0382             }
0383 
0384             d->imagePreviewView->setItemInfo(info, previous, next);
0385 
0386             // NOTE: No need to toggle immediately in PreviewImageMode here,
0387             // because we will receive a signal for that when the image preview will be loaded.
0388             // This will prevent a flicker effect with the old image preview loaded in stack.
0389         }
0390 
0391         // do not touch the selection, only adjust current info
0392 
0393         QModelIndex currentIndex = d->thumbBar->imageSortFilterModel()->indexForItemInfo(info);
0394         d->thumbBar->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate);
0395     }
0396 }
0397 
0398 StackedView::StackedViewMode StackedView::viewMode() const
0399 {
0400     return StackedViewMode(d->stackMap.value(currentIndex()));
0401 }
0402 
0403 void StackedView::setViewMode(const StackedViewMode mode)
0404 {
0405     qCDebug(DIGIKAM_GENERAL_LOG) << "Stacked View Mode : " << mode;
0406 
0407 #ifdef HAVE_MEDIAPLAYER
0408 
0409     if ((viewMode() == MediaPlayerMode) && (mode != MediaPlayerMode))
0410     {
0411         d->mediaPlayerView->escapePreview();
0412     }
0413 
0414 #endif // HAVE_MEDIAPLAYER
0415 
0416     if ((viewMode() == TrashViewMode) && (mode != TrashViewMode))
0417     {
0418         d->trashView->model()->stopLoadingTrash();
0419     }
0420 
0421     if ((mode < StackedViewModeFirst) || (mode > StackedViewModeLast))
0422     {
0423         return;
0424     }
0425 
0426     if ((mode == PreviewImageMode) || (mode == MediaPlayerMode))
0427     {
0428         d->thumbBarDock->restoreVisibility();
0429         syncSelection(d->imageIconView, d->thumbBar);
0430     }
0431     else
0432     {
0433         d->thumbBarDock->hide();
0434     }
0435 
0436     if ((mode == IconViewMode)    ||
0437         (mode == WelcomePageMode) ||
0438         (mode == MapWidgetMode)   ||
0439         (mode == TableViewMode))
0440     {
0441         setPreviewItem();
0442         setCurrentIndex(d->stackMap.key(mode));
0443     }
0444     else
0445     {
0446         setCurrentIndex(d->stackMap.key(mode));
0447     }
0448 
0449 #ifdef HAVE_GEOLOCATION
0450 
0451     d->mapWidgetView->setActive(mode == MapWidgetMode);
0452 
0453 #endif // HAVE_GEOLOCATION
0454 
0455     d->tableView->slotSetActive(mode == TableViewMode);
0456 
0457     if (mode == IconViewMode)
0458     {
0459         d->imageIconView->setFocus();
0460     }
0461 
0462 #ifdef HAVE_GEOLOCATION
0463 
0464     else if (mode == MapWidgetMode)
0465     {
0466         d->mapWidgetView->setFocus();
0467     }
0468 
0469 #endif // HAVE_GEOLOCATION
0470 
0471     else if (mode == TableViewMode)
0472     {
0473         d->tableView->setFocus();
0474     }
0475 
0476     Q_EMIT signalViewModeChanged();
0477 }
0478 
0479 void StackedView::syncSelection(ItemCategorizedView* const from, ItemCategorizedView* const to)
0480 {
0481     ImageSortFilterModel* const fromModel = from->imageSortFilterModel();
0482     ImageSortFilterModel* const toModel   = to->imageSortFilterModel();
0483     QModelIndex currentIndex              = toModel->indexForItemInfo(from->currentInfo());
0484 
0485     // sync selection
0486 
0487     QItemSelection selection              = from->selectionModel()->selection();
0488     QItemSelection newSelection;
0489 
0490     Q_FOREACH (const QItemSelectionRange& range, selection)
0491     {
0492         QModelIndex topLeft     = toModel->indexForItemInfo(fromModel->imageInfo(range.topLeft()));
0493         QModelIndex bottomRight = toModel->indexForItemInfo(fromModel->imageInfo(range.bottomRight()));
0494         newSelection.select(topLeft, bottomRight);
0495     }
0496 
0497     d->syncingSelection = true;
0498 
0499     if (currentIndex.isValid())
0500     {
0501         // set current info
0502 
0503         to->setCurrentIndex(currentIndex);
0504     }
0505 
0506     to->selectionModel()->select(newSelection, QItemSelectionModel::ClearAndSelect);
0507     d->syncingSelection = false;
0508 }
0509 
0510 void StackedView::slotThumbBarSelectionChanged()
0511 {
0512     if ((viewMode() != PreviewImageMode) && (viewMode() != MediaPlayerMode))
0513     {
0514         return;
0515     }
0516 
0517     if (d->syncingSelection)
0518     {
0519         return;
0520     }
0521 
0522     syncSelection(d->thumbBar, d->imageIconView);
0523 }
0524 
0525 void StackedView::slotIconViewSelectionChanged()
0526 {
0527     if (viewMode() != IconViewMode)
0528     {
0529         return;
0530     }
0531 
0532     if (d->syncingSelection)
0533     {
0534         return;
0535     }
0536 
0537     syncSelection(d->imageIconView, d->thumbBar);
0538 }
0539 
0540 void StackedView::previewLoaded()
0541 {
0542     Q_EMIT signalViewModeChanged();
0543 }
0544 
0545 void StackedView::slotZoomFactorChanged(double z)
0546 {
0547     if (viewMode() == PreviewImageMode)
0548     {
0549         Q_EMIT signalZoomFactorChanged(z);
0550     }
0551 }
0552 
0553 void StackedView::increaseZoom()
0554 {
0555     d->imagePreviewView->layout()->increaseZoom();
0556 }
0557 
0558 void StackedView::decreaseZoom()
0559 {
0560     d->imagePreviewView->layout()->decreaseZoom();
0561 }
0562 
0563 void StackedView::zoomTo100Percents()
0564 {
0565     d->imagePreviewView->layout()->setZoomFactor(1.0, QPoint());
0566 }
0567 
0568 void StackedView::fitToWindow()
0569 {
0570     d->imagePreviewView->layout()->fitToWindow();
0571 }
0572 
0573 void StackedView::toggleFitToWindowOr100()
0574 {
0575     d->imagePreviewView->layout()->toggleFitToWindowOr100();
0576 }
0577 
0578 bool StackedView::maxZoom()
0579 {
0580     return d->imagePreviewView->layout()->atMaxZoom();
0581 }
0582 
0583 bool StackedView::minZoom()
0584 {
0585     return d->imagePreviewView->layout()->atMinZoom();
0586 }
0587 
0588 void StackedView::setZoomFactor(double z)
0589 {
0590     // Giving a null anchor means to use the current view center
0591 
0592     d->imagePreviewView->layout()->setZoomFactor(z, QPoint());
0593 }
0594 
0595 void StackedView::setZoomFactorSnapped(double z)
0596 {
0597     d->imagePreviewView->layout()->setZoomFactor(z, QPoint(), SinglePhotoPreviewLayout::SnapZoomFactor);
0598 }
0599 
0600 double StackedView::zoomFactor()
0601 {
0602     return d->imagePreviewView->layout()->zoomFactor();
0603 }
0604 
0605 double StackedView::zoomMin()
0606 {
0607     return d->imagePreviewView->layout()->minZoomFactor();
0608 }
0609 
0610 double StackedView::zoomMax()
0611 {
0612     return d->imagePreviewView->layout()->maxZoomFactor();
0613 }
0614 
0615 void StackedView::slotPreviewLoaded(bool)
0616 {
0617     setViewMode(StackedView::PreviewImageMode);
0618     previewLoaded();
0619 }
0620 
0621 } // namespace Digikam
0622 
0623 #include "moc_stackedview.cpp"