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"