File indexing completed on 2025-03-09 03:58:43
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2012-05-07 0007 * Description : QStackedWidget to handle different types of views 0008 * (icon view, image preview, media view) 0009 * 0010 * SPDX-FileCopyrightText: 2012 by Islam Wazery <wazery at ubuntu dot com> 0011 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "importstackedview.h" 0018 0019 // Qt includes 0020 0021 #include <QSplitter> 0022 0023 // KDE includes 0024 0025 #include <klocalizedstring.h> 0026 0027 // Local includes 0028 0029 #include "digikam_debug.h" 0030 #include "previewlayout.h" 0031 #include "importsettings.h" 0032 0033 namespace Digikam 0034 { 0035 0036 class MediaPlayerView; 0037 0038 class Q_DECL_HIDDEN ImportStackedView::Private 0039 { 0040 0041 public: 0042 0043 explicit Private() 0044 : dockArea(nullptr), 0045 splitter(nullptr), 0046 thumbBar(nullptr), 0047 thumbBarDock(nullptr), 0048 importIconView(nullptr), 0049 importPreviewView(nullptr), 0050 0051 #ifdef HAVE_GEOLOCATION 0052 0053 mapWidgetView(nullptr), 0054 0055 #endif // HAVE_GEOLOCATION 0056 0057 #ifdef HAVE_MEDIAPLAYER 0058 0059 mediaPlayerView(nullptr), 0060 0061 #endif // HAVE_MEDIAPLAYER 0062 0063 syncingSelection(false) 0064 { 0065 } 0066 0067 QMainWindow* dockArea; 0068 QSplitter* splitter; 0069 0070 ImportThumbnailBar* thumbBar; 0071 ThumbBarDock* thumbBarDock; 0072 ImportIconView* importIconView; 0073 ImportPreviewView* importPreviewView; 0074 0075 #ifdef HAVE_GEOLOCATION 0076 0077 MapWidgetView* mapWidgetView; 0078 0079 #endif // HAVE_GEOLOCATION 0080 0081 #ifdef HAVE_MEDIAPLAYER 0082 0083 MediaPlayerView* mediaPlayerView; ///< Reuse of albumgui mediaplayer view. 0084 0085 #endif // HAVE_MEDIAPLAYER 0086 0087 bool syncingSelection; 0088 }; 0089 0090 ImportStackedView::ImportStackedView(QWidget* const parent) 0091 : QStackedWidget(parent), 0092 d(new Private) 0093 { 0094 d->importIconView = new ImportIconView(this); 0095 d->importPreviewView = new ImportPreviewView(this); 0096 d->thumbBarDock = new ThumbBarDock(); 0097 d->thumbBar = new ImportThumbnailBar(d->thumbBarDock); 0098 d->thumbBar->setModelsFiltered(d->importIconView->importItemModel(), 0099 d->importIconView->importFilterModel()); 0100 d->thumbBar->installOverlays(); 0101 d->thumbBarDock->setWidget(d->thumbBar); 0102 d->thumbBarDock->setObjectName(QLatin1String("import_thumbbar")); 0103 0104 #ifdef HAVE_GEOLOCATION 0105 0106 // TODO refactor MapWidgetView not to require the models on startup? 0107 0108 d->mapWidgetView = new MapWidgetView(d->importIconView->getSelectionModel(), 0109 d->importIconView->importFilterModel(), this, 0110 MapWidgetView::ApplicationImportUI); 0111 d->mapWidgetView->setObjectName(QLatin1String("import_mapwidgetview")); 0112 0113 #endif // HAVE_GEOLOCATION 0114 0115 #ifdef HAVE_MEDIAPLAYER 0116 0117 d->mediaPlayerView = new MediaPlayerView(this); 0118 0119 #endif //HAVE_MEDIAPLAYER 0120 0121 insertWidget(PreviewCameraMode, d->importIconView); 0122 insertWidget(PreviewImageMode, d->importPreviewView); 0123 0124 #ifdef HAVE_GEOLOCATION 0125 0126 insertWidget(MapWidgetMode, d->mapWidgetView); 0127 0128 #endif // HAVE_GEOLOCATION 0129 0130 #ifdef HAVE_MEDIAPLAYER 0131 0132 insertWidget(MediaPlayerMode, d->mediaPlayerView); 0133 0134 #endif //HAVE_MEDIAPLAYER 0135 0136 setAttribute(Qt::WA_DeleteOnClose); 0137 0138 readSettings(); 0139 0140 // ----------------------------------------------------------------- 0141 /* 0142 FIXME 0143 connect(d->importPreviewView, SIGNAL(signalPopupTagsView()), 0144 d->importIconView, SIGNAL(signalPopupTagsView())); 0145 0146 connect(d->importPreviewView, SIGNAL(signalGotoFolderAndItem(CamItemInfo)), 0147 this, SIGNAL(signalGotoFolderAndItem(CamItemInfo))); 0148 0149 connect(d->importPreviewView, SIGNAL(signalGotoDateAndItem(CamItemInfo)), 0150 this, SIGNAL(signalGotoDateAndItem(CamItemInfo))); 0151 0152 connect(d->importPreviewView, SIGNAL(signalGotoTagAndItem(int)), 0153 this, SIGNAL(signalGotoTagAndItem(int))); 0154 */ 0155 connect(d->importPreviewView, SIGNAL(signalNextItem()), 0156 this, SIGNAL(signalNextItem())); 0157 0158 connect(d->importPreviewView, SIGNAL(signalPrevItem()), 0159 this, SIGNAL(signalPrevItem())); 0160 /* 0161 FIXME 0162 connect(d->importPreviewView, SIGNAL(signalDeleteItem()), 0163 this, SIGNAL(signalDeleteItem())); 0164 */ 0165 connect(d->importPreviewView, SIGNAL(signalEscapePreview()), 0166 this, SIGNAL(signalEscapePreview())); 0167 0168 // A workaround to assign pickLabel, colorLabel, and rating in the preview view. 0169 0170 connect(d->importPreviewView, SIGNAL(signalAssignPickLabel(int)), 0171 d->importIconView, SLOT(assignPickLabelToSelected(int))); 0172 0173 connect(d->importPreviewView, SIGNAL(signalAssignColorLabel(int)), 0174 d->importIconView, SLOT(assignColorLabelToSelected(int))); 0175 0176 connect(d->importPreviewView, SIGNAL(signalAssignRating(int)), 0177 d->importIconView, SLOT(assignRatingToSelected(int))); 0178 0179 connect(d->importPreviewView->layout(), SIGNAL(zoomFactorChanged(double)), 0180 this, SLOT(slotZoomFactorChanged(double))); 0181 /* 0182 FIXME 0183 connect(d->importPreviewView, SIGNAL(signalAddToExistingQueue(int)), 0184 this, SIGNAL(signalAddToExistingQueue(int))); 0185 */ 0186 connect(d->thumbBar, SIGNAL(selectionChanged()), 0187 this, SLOT(slotThumbBarSelectionChanged())); 0188 0189 connect(d->importIconView, SIGNAL(selectionChanged()), 0190 this, SLOT(slotIconViewSelectionChanged())); 0191 0192 connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 0193 d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); 0194 0195 connect(d->importPreviewView, SIGNAL(signalPreviewLoaded(bool)), 0196 this, SLOT(slotPreviewLoaded(bool))); 0197 0198 #ifdef HAVE_MEDIAPLAYER 0199 0200 connect(d->mediaPlayerView, SIGNAL(signalNextItem()), 0201 this, SIGNAL(signalNextItem())); 0202 0203 connect(d->mediaPlayerView, SIGNAL(signalPrevItem()), 0204 this, SIGNAL(signalPrevItem())); 0205 0206 connect(d->mediaPlayerView, SIGNAL(signalEscapePreview()), 0207 this, SIGNAL(signalEscapePreview())); 0208 0209 #endif //HAVE_MEDIAPLAYER 0210 0211 } 0212 0213 ImportStackedView::~ImportStackedView() 0214 { 0215 delete d; 0216 } 0217 0218 void ImportStackedView::readSettings() 0219 { 0220 ImportSettings* const settings = ImportSettings::instance(); 0221 bool showThumbbar = settings->getShowThumbbar(); 0222 d->thumbBarDock->setShouldBeVisible(showThumbbar); 0223 } 0224 0225 void ImportStackedView::setDockArea(QMainWindow* dockArea) 0226 { 0227 // Attach the thumbbar dock to the given dock area and place it initially on top. 0228 0229 d->dockArea = dockArea; 0230 d->thumbBarDock->setParent(d->dockArea); 0231 d->dockArea->addDockWidget(Qt::TopDockWidgetArea, d->thumbBarDock); 0232 d->thumbBarDock->setFloating(false); 0233 } 0234 0235 ThumbBarDock* ImportStackedView::thumbBarDock() const 0236 { 0237 return d->thumbBarDock; 0238 } 0239 0240 ImportThumbnailBar* ImportStackedView::thumbBar() const 0241 { 0242 return d->thumbBar; 0243 } 0244 0245 ImportIconView* ImportStackedView::importIconView() const 0246 { 0247 return d->importIconView; 0248 } 0249 0250 ImportPreviewView* ImportStackedView::importPreviewView() const 0251 { 0252 return d->importPreviewView; 0253 } 0254 0255 #ifdef HAVE_GEOLOCATION 0256 0257 MapWidgetView* ImportStackedView::mapWidgetView() const 0258 { 0259 return d->mapWidgetView; 0260 } 0261 0262 #endif // HAVE_GEOLOCATION 0263 0264 #ifdef HAVE_MEDIAPLAYER 0265 0266 MediaPlayerView* ImportStackedView::mediaPlayerView() const 0267 { 0268 return d->mediaPlayerView; 0269 } 0270 0271 #endif //HAVE_MEDIAPLAYER 0272 0273 bool ImportStackedView::isInSingleFileMode() const 0274 { 0275 return ((currentIndex() == PreviewImageMode) || (currentIndex() == MediaPlayerMode)); 0276 } 0277 0278 bool ImportStackedView::isInMultipleFileMode() const 0279 { 0280 return ((currentIndex() == PreviewCameraMode) || (currentIndex() == MapWidgetMode)); 0281 } 0282 0283 void ImportStackedView::setPreviewItem(const CamItemInfo& info, const CamItemInfo& previous, const CamItemInfo& next) 0284 { 0285 if (info.isNull()) 0286 { 0287 if (viewMode() == MediaPlayerMode) 0288 { 0289 0290 #ifdef HAVE_MEDIAPLAYER 0291 0292 d->mediaPlayerView->setCurrentItem(); 0293 0294 #endif //HAVE_MEDIAPLAYER 0295 0296 } 0297 else if (viewMode() == PreviewImageMode) 0298 { 0299 d->importPreviewView->setCamItemInfo(); 0300 } 0301 } 0302 else 0303 { 0304 if (identifyCategoryforMime(info.mime) == QLatin1String("audio") || 0305 identifyCategoryforMime(info.mime) == QLatin1String("video")) 0306 { 0307 // Stop image viewer 0308 0309 if (viewMode() == PreviewImageMode) 0310 { 0311 d->importPreviewView->setCamItemInfo(); 0312 } 0313 0314 #ifdef HAVE_MEDIAPLAYER 0315 0316 setViewMode(MediaPlayerMode); 0317 d->mediaPlayerView->setCurrentItem(info.url(), !previous.isNull(), !next.isNull()); 0318 0319 #endif //HAVE_MEDIAPLAYER 0320 0321 } 0322 else 0323 { 0324 // Stop media player if running... 0325 0326 if (viewMode() == MediaPlayerMode) 0327 { 0328 0329 #ifdef HAVE_MEDIAPLAYER 0330 0331 d->mediaPlayerView->setCurrentItem(); 0332 0333 #endif //HAVE_MEDIAPLAYER 0334 0335 } 0336 0337 d->importPreviewView->setCamItemInfo(info, previous, next); 0338 0339 // NOTE: No need to toggle immediately in PreviewImageMode here, 0340 // because we will receive a signal for that when the image preview will be loaded. 0341 // This will prevent a flicker effect with the old image preview loaded in stack. 0342 } 0343 0344 // do not touch the selection, only adjust current info 0345 0346 QModelIndex currentIndex = d->thumbBar->importSortFilterModel()->indexForCamItemInfo(info); 0347 d->thumbBar->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::NoUpdate); 0348 } 0349 } 0350 0351 QString ImportStackedView::identifyCategoryforMime(const QString& mime) const 0352 { 0353 return mime.split(QLatin1Char('/')).at(0); 0354 } 0355 0356 ImportStackedView::StackedViewMode ImportStackedView::viewMode() const 0357 { 0358 return (StackedViewMode)(indexOf(currentWidget())); 0359 } 0360 0361 void ImportStackedView::setViewMode(const StackedViewMode mode) 0362 { 0363 0364 #ifdef HAVE_MEDIAPLAYER 0365 0366 if ((viewMode() == MediaPlayerMode) && (mode != MediaPlayerMode)) 0367 { 0368 d->mediaPlayerView->escapePreview(); 0369 } 0370 0371 #endif // HAVE_MEDIAPLAYER 0372 0373 if ((mode != PreviewCameraMode) && (mode != PreviewImageMode) && 0374 (mode != MediaPlayerMode) && (mode != MapWidgetMode)) 0375 { 0376 return; 0377 } 0378 0379 if ((mode == PreviewImageMode) || (mode == MediaPlayerMode)) 0380 { 0381 d->thumbBarDock->restoreVisibility(); 0382 syncSelection(d->importIconView, d->thumbBar); 0383 } 0384 else 0385 { 0386 d->thumbBarDock->hide(); 0387 } 0388 0389 if ((mode == PreviewCameraMode) || (mode == MapWidgetMode)) 0390 { 0391 setPreviewItem(); 0392 setCurrentIndex(mode); 0393 } 0394 else 0395 { 0396 setCurrentIndex(mode); 0397 } 0398 0399 #ifdef HAVE_GEOLOCATION 0400 0401 d->mapWidgetView->setActive(mode == MapWidgetMode); 0402 0403 #endif // HAVE_GEOLOCATION 0404 0405 if (mode == PreviewCameraMode) 0406 { 0407 d->importIconView->setFocus(); 0408 } 0409 0410 #ifdef HAVE_GEOLOCATION 0411 0412 else if (mode == MapWidgetMode) 0413 { 0414 d->mapWidgetView->setFocus(); 0415 } 0416 0417 #endif // HAVE_GEOLOCATION 0418 0419 Q_EMIT signalViewModeChanged(); 0420 } 0421 0422 void ImportStackedView::syncSelection(ImportCategorizedView* const from, ImportCategorizedView* const to) 0423 { 0424 ImportSortFilterModel* const fromModel = from->importSortFilterModel(); 0425 ImportSortFilterModel* const toModel = to->importSortFilterModel(); 0426 QModelIndex currentIndex = toModel->indexForCamItemInfo(from->currentInfo()); 0427 0428 // sync selection 0429 0430 QItemSelection selection = from->selectionModel()->selection(); 0431 QItemSelection newSelection; 0432 0433 Q_FOREACH (const QItemSelectionRange& range, selection) 0434 { 0435 QModelIndex topLeft = toModel->indexForCamItemInfo(fromModel->camItemInfo(range.topLeft())); 0436 QModelIndex bottomRight = toModel->indexForCamItemInfo(fromModel->camItemInfo(range.bottomRight())); 0437 newSelection.select(topLeft, bottomRight); 0438 } 0439 0440 d->syncingSelection = true; 0441 0442 if (currentIndex.isValid()) 0443 { 0444 // set current info 0445 0446 to->setCurrentIndex(currentIndex); 0447 } 0448 0449 to->selectionModel()->select(newSelection, QItemSelectionModel::ClearAndSelect); 0450 d->syncingSelection = false; 0451 } 0452 0453 void ImportStackedView::slotThumbBarSelectionChanged() 0454 { 0455 if ((currentIndex() != PreviewImageMode) && (currentIndex() != MediaPlayerMode)) 0456 { 0457 return; 0458 } 0459 0460 if (d->syncingSelection) 0461 { 0462 return; 0463 } 0464 0465 syncSelection(d->thumbBar, d->importIconView); 0466 } 0467 0468 void ImportStackedView::slotIconViewSelectionChanged() 0469 { 0470 if (currentIndex() != PreviewCameraMode) 0471 { 0472 return; 0473 } 0474 0475 if (d->syncingSelection) 0476 { 0477 return; 0478 } 0479 0480 syncSelection(d->importIconView, d->thumbBar); 0481 } 0482 0483 void ImportStackedView::previewLoaded() 0484 { 0485 Q_EMIT signalViewModeChanged(); 0486 } 0487 0488 void ImportStackedView::slotZoomFactorChanged(double z) 0489 { 0490 if (viewMode() == PreviewImageMode) 0491 { 0492 Q_EMIT signalZoomFactorChanged(z); 0493 } 0494 } 0495 0496 void ImportStackedView::increaseZoom() 0497 { 0498 d->importPreviewView->layout()->increaseZoom(); 0499 } 0500 0501 void ImportStackedView::decreaseZoom() 0502 { 0503 d->importPreviewView->layout()->decreaseZoom(); 0504 } 0505 0506 void ImportStackedView::zoomTo100Percents() 0507 { 0508 d->importPreviewView->layout()->setZoomFactor(1.0); 0509 } 0510 0511 void ImportStackedView::fitToWindow() 0512 { 0513 d->importPreviewView->layout()->fitToWindow(); 0514 } 0515 0516 void ImportStackedView::toggleFitToWindowOr100() 0517 { 0518 d->importPreviewView->layout()->toggleFitToWindowOr100(); 0519 } 0520 0521 bool ImportStackedView::maxZoom() const 0522 { 0523 return d->importPreviewView->layout()->atMaxZoom(); 0524 } 0525 0526 bool ImportStackedView::minZoom() const 0527 { 0528 return d->importPreviewView->layout()->atMinZoom(); 0529 } 0530 0531 void ImportStackedView::setZoomFactor(double z) 0532 { 0533 // Giving a null anchor means to use the current view center 0534 0535 d->importPreviewView->layout()->setZoomFactor(z, QPoint()); 0536 } 0537 0538 void ImportStackedView::setZoomFactorSnapped(double z) 0539 { 0540 d->importPreviewView->layout()->setZoomFactor(z, QPoint(), SinglePhotoPreviewLayout::SnapZoomFactor); 0541 } 0542 0543 double ImportStackedView::zoomFactor() const 0544 { 0545 return d->importPreviewView->layout()->zoomFactor(); 0546 } 0547 0548 double ImportStackedView::zoomMin() const 0549 { 0550 return d->importPreviewView->layout()->minZoomFactor(); 0551 } 0552 0553 double ImportStackedView::zoomMax() const 0554 { 0555 return d->importPreviewView->layout()->maxZoomFactor(); 0556 } 0557 0558 void ImportStackedView::slotPreviewLoaded(bool) 0559 { 0560 setViewMode(ImportStackedView::PreviewImageMode); 0561 previewLoaded(); 0562 } 0563 0564 } // namespace Digikam 0565 0566 #include "moc_importstackedview.cpp"