File indexing completed on 2025-03-09 03:50:02
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2002-16-10 0007 * Description : main digiKam interface implementation 0008 * 0009 * SPDX-FileCopyrightText: 2002-2005 by Renchi Raju <renchi dot raju at gmail dot com> 0010 * SPDX-FileCopyrightText: 2006 by Tom Albers <tomalbers at kde dot nl> 0011 * SPDX-FileCopyrightText: 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com> 0012 * SPDX-FileCopyrightText: 2013 by Michael G. Hansen <mike at mghansen dot de> 0013 * SPDX-FileCopyrightText: 2014-2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0014 * SPDX-FileCopyrightText: 2002-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0015 * 0016 * SPDX-License-Identifier: GPL-2.0-or-later 0017 * 0018 * ============================================================ */ 0019 0020 #include "digikamapp_p.h" 0021 0022 namespace Digikam 0023 { 0024 0025 DigikamApp* DigikamApp::m_instance = nullptr; 0026 0027 DigikamApp::DigikamApp() 0028 : DXmlGuiWindow(nullptr), 0029 d (new Private) 0030 { 0031 setObjectName(QLatin1String("Digikam")); 0032 setConfigGroupName(ApplicationSettings::instance()->generalConfigGroupName()); 0033 setFullScreenOptions(FS_ALBUMGUI); 0034 setXMLFile(QLatin1String("digikamui5.rc")); 0035 0036 m_instance = this; 0037 d->config = KSharedConfig::openConfig(); 0038 KConfigGroup group = d->config->group(configGroupName()); 0039 0040 #ifdef HAVE_DBUS 0041 0042 new DigikamAdaptor(this); 0043 QDBusConnection::sessionBus().registerObject(QLatin1String("/Digikam"), this); 0044 QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.digikam-") + 0045 QString::number(QCoreApplication::instance()->applicationPid())); 0046 #endif 0047 0048 // collection scan 0049 0050 if (!CollectionScanner::databaseInitialScanDone()) 0051 { 0052 ScanController::instance()->completeCollectionScanDeferFiles(); 0053 } 0054 0055 if (ApplicationSettings::instance()->getShowSplashScreen() && 0056 !qApp->isSessionRestored()) 0057 { 0058 d->splashScreen = new DSplashScreen(); 0059 d->splashScreen->show(); 0060 } 0061 0062 // We need here QCoreApplication::processEvents(). 0063 0064 qApp->processEvents(); 0065 0066 if (d->splashScreen) 0067 { 0068 d->splashScreen->setMessage(i18n("Initializing...")); 0069 } 0070 0071 // Ensure creation 0072 0073 AlbumManager::instance(); 0074 LoadingCacheInterface::initialize(); 0075 IccSettings::instance()->loadAllProfilesProperties(); 0076 MetaEngineSettings::instance(); 0077 DMetadataSettings::instance(); 0078 ProgressManager::instance(); 0079 ThumbnailLoadThread::setDisplayingWidget(this); 0080 DIO::instance(); 0081 LocalizeSettings::instance(); 0082 NetworkManager::instance(); 0083 0084 #ifdef HAVE_GEOLOCATION 0085 0086 connect(GeolocationSettings::instance(), &GeolocationSettings::signalSetupGeolocation, 0087 this, [=](int tab) 0088 { 0089 Setup::execGeolocation(this, tab); 0090 } 0091 ); 0092 0093 qCDebug(DIGIKAM_GENERAL_LOG) << GeolocationSettings::instance()->settings(); 0094 0095 #endif 0096 0097 connect(LocalizeSettings::instance(), &LocalizeSettings::signalOpenLocalizeSetup, 0098 this, [=]() 0099 { 0100 Setup::execLocalize(this); 0101 } 0102 ); 0103 0104 if (!ExifToolProcess::isCreated()) 0105 { 0106 ExifToolThread* const exifToolThread = new ExifToolThread(qApp); 0107 exifToolThread->start(); 0108 } 0109 0110 // creation of the engine on first use - when drawing - 0111 // can take considerable time and cause a noticeable hang in the UI thread. 0112 0113 QFontMetrics fm(font()); 0114 fm.horizontalAdvance(QLatin1String("a")); 0115 0116 connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), 0117 this, SLOT(slotSetupChanged())); 0118 0119 connect(IccSettings::instance(), SIGNAL(signalSettingsChanged()), 0120 this, SLOT(slotColorManagementOptionsChanged())); 0121 0122 d->cameraMenu = new QMenu(this); 0123 d->usbMediaMenu = new QMenu(this); 0124 d->cardReaderMenu = new QMenu(this); 0125 d->quickImportMenu = new QMenu(this); 0126 0127 d->cameraList = new CameraList(this, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + 0128 QLatin1String("/cameras.xml")); 0129 0130 connect(d->cameraList, SIGNAL(signalCameraAdded(CameraType*)), 0131 this, SLOT(slotCameraAdded(CameraType*))); 0132 0133 connect(d->cameraList, SIGNAL(signalCameraRemoved(QAction*)), 0134 this, SLOT(slotCameraRemoved(QAction*))); 0135 0136 d->modelCollection = new DModelFactory; 0137 0138 // This manager must be created after collection setup and before accelerators setup. 0139 0140 d->tagsActionManager = new TagsActionMngr(this); 0141 0142 // Load plugins 0143 0144 if (d->splashScreen) 0145 { 0146 d->splashScreen->setMessage(i18n("Load Plugins...")); 0147 } 0148 0149 DPluginLoader* const dpl = DPluginLoader::instance(); 0150 dpl->init(); 0151 0152 // First create everything, then connect. 0153 // Otherwise some items may send signals and the slots can try 0154 // to access items which were not created yet. 0155 0156 setupView(); 0157 setupAccelerators(); 0158 setupActions(); 0159 setupStatusBar(); 0160 0161 initGui(); 0162 0163 setupViewConnections(); 0164 applyMainWindowSettings(group); 0165 slotColorManagementOptionsChanged(); 0166 0167 // Check ICC profiles repository availability 0168 0169 if (d->splashScreen) 0170 { 0171 d->splashScreen->setMessage(i18n("Checking ICC repository...")); 0172 } 0173 0174 d->validIccPath = SetupICC::iccRepositoryIsValid(); 0175 0176 // Clean up database if enabled in the settings 0177 0178 if (ApplicationSettings::instance()->getCleanAtStart() && 0179 CollectionScanner::databaseInitialScanDone()) 0180 { 0181 if (d->splashScreen) 0182 { 0183 d->splashScreen->setMessage(i18n("Clean up Database...")); 0184 } 0185 0186 QEventLoop loop; 0187 0188 DbCleaner* const tool = new DbCleaner(false, false); 0189 0190 connect(tool, SIGNAL(signalComplete()), 0191 &loop, SLOT(quit())); 0192 0193 tool->start(); 0194 loop.exec(); 0195 } 0196 0197 // Build trash counters from all collections 0198 0199 DIO::buildCollectionTrashCounters(); 0200 0201 // Read albums from database 0202 0203 if (d->splashScreen) 0204 { 0205 d->splashScreen->setMessage(i18n("Loading albums...")); 0206 } 0207 0208 if (CoreDbAccess().backend()->isOpen()) 0209 { 0210 AlbumManager::instance()->startScan(); 0211 } 0212 0213 // Setting the initial menu options after all tools have been loaded 0214 0215 QList<Album*> albumList = AlbumManager::instance()->currentAlbums(); 0216 d->view->slotAlbumSelected(albumList); 0217 0218 // preload additional windows 0219 0220 preloadWindows(); 0221 0222 readFullScreenSettings(group); 0223 0224 #ifdef HAVE_KFILEMETADATA 0225 0226 // Create BalooWrap object, because it need to register a listener 0227 // to update digiKam data when changes in Baloo occur 0228 BalooWrap* const baloo = BalooWrap::instance(); 0229 Q_UNUSED(baloo); 0230 0231 #endif // HAVE_KFILEMETADATA 0232 0233 setAutoSaveSettings(group, true); 0234 0235 LoadSaveThread::setInfoProvider(new DatabaseLoadSaveFileInfoProvider); 0236 0237 setupSelectToolsAction(); 0238 } 0239 0240 DigikamApp::~DigikamApp() 0241 { 0242 ProgressManager::instance()->slotAbortAll(); 0243 0244 ItemAttributesWatch::shutDown(); 0245 0246 // Close and delete image editor instance. 0247 0248 if (ImageWindow::imageWindowCreated()) 0249 { 0250 ImageWindow::imageWindow()->setAttribute(Qt::WA_DeleteOnClose, true); 0251 ImageWindow::imageWindow()->close(); 0252 qApp->processEvents(); 0253 } 0254 0255 // Close and delete light table instance. 0256 0257 if (LightTableWindow::lightTableWindowCreated()) 0258 { 0259 LightTableWindow::lightTableWindow()->setAttribute(Qt::WA_DeleteOnClose, true); 0260 LightTableWindow::lightTableWindow()->close(); 0261 qApp->processEvents(); 0262 } 0263 0264 // Close and delete Batch Queue Manager instance. 0265 0266 if (QueueMgrWindow::queueManagerWindowCreated()) 0267 { 0268 QueueMgrWindow::queueManagerWindow()->setAttribute(Qt::WA_DeleteOnClose, true); 0269 QueueMgrWindow::queueManagerWindow()->close(); 0270 qApp->processEvents(); 0271 } 0272 0273 // Close and delete Tags Manager instance. 0274 0275 if (TagsManager::isCreated()) 0276 { 0277 TagsManager::instance()->setAttribute(Qt::WA_DeleteOnClose, true); 0278 TagsManager::instance()->close(); 0279 } 0280 0281 if (MetadataHubMngr::isCreated()) 0282 { 0283 delete MetadataHubMngr::internalPtr; 0284 } 0285 0286 #ifdef HAVE_KFILEMETADATA 0287 0288 if (BalooWrap::isCreated()) 0289 { 0290 delete BalooWrap::internalPtr; 0291 } 0292 0293 #endif 0294 0295 delete d->view; 0296 d->view = nullptr; 0297 0298 DPluginLoader::instance()->cleanUp(); 0299 0300 ApplicationSettings::instance()->setRecurseAlbums(d->recurseAlbumsAction->isChecked()); 0301 ApplicationSettings::instance()->setRecurseTags(d->recurseTagsAction->isChecked()); 0302 ApplicationSettings::instance()->setShowThumbbar(d->showBarAction->isChecked()); 0303 ApplicationSettings::instance()->saveSettings(); 0304 0305 ScanController::instance()->shutDown(); 0306 AlbumManager::instance()->cleanUp(); 0307 ItemAttributesWatch::cleanUp(); 0308 AlbumThumbnailLoader::instance()->cleanUp(); 0309 ThumbnailLoadThread::cleanUp(); 0310 LoadingCacheInterface::cleanUp(); 0311 DIO::cleanUp(); 0312 0313 // close database server 0314 0315 DatabaseServerStarter::instance()->stopServerManagerProcess(); 0316 0317 delete d->modelCollection; 0318 0319 m_instance = nullptr; 0320 0321 delete d; 0322 } 0323 0324 DigikamApp* DigikamApp::instance() 0325 { 0326 return m_instance; 0327 } 0328 0329 ItemIconView* DigikamApp::view() const 0330 { 0331 return d->view; 0332 } 0333 0334 void DigikamApp::show() 0335 { 0336 // Remove Splashscreen. 0337 0338 if (d->splashScreen) 0339 { 0340 d->splashScreen->finish(this); 0341 } 0342 0343 // Display application window. 0344 0345 KMainWindow::show(); 0346 0347 // Report errors from ICC repository path. 0348 0349 if (!d->validIccPath) 0350 { 0351 QString message = i18n("<p>The ICC profiles folder seems to be invalid.</p>" 0352 "<p>If you want to try setting it again, choose \"Yes\" here, otherwise " 0353 "choose \"No\", and the \"Color Management\" feature " 0354 "will be disabled until you solve this issue.</p>"); 0355 0356 if (QMessageBox::warning(this, qApp->applicationName(), message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) 0357 { 0358 if (!setupICC()) 0359 { 0360 d->config->group(QLatin1String("Color Management")).writeEntry(QLatin1String("EnableCM"), false); 0361 d->config->sync(); 0362 } 0363 } 0364 else 0365 { 0366 d->config->group(QLatin1String("Color Management")).writeEntry(QLatin1String("EnableCM"), false); 0367 d->config->sync(); 0368 } 0369 } 0370 0371 // Init album icon view zoom factor. 0372 0373 ApplicationSettings* const settings = ApplicationSettings::instance(); 0374 0375 slotThumbSizeChanged(settings->getDefaultIconSize()); 0376 slotZoomSliderChanged(settings->getDefaultIconSize()); 0377 d->autoShowZoomToolTip = true; 0378 0379 // Enable finished the collection scan as deferred process 0380 0381 if (settings->getScanAtStart() || 0382 !CollectionScanner::databaseInitialScanDone()) 0383 { 0384 NewItemsFinder* const tool = new NewItemsFinder(NewItemsFinder::ScanDeferredFiles); 0385 0386 if (settings->getDetectFacesInNewImages()) 0387 { 0388 connect(tool, SIGNAL(signalComplete()), 0389 this, SLOT(slotDetectFaces())); 0390 } 0391 0392 QTimer::singleShot(1000, tool, SLOT(start())); 0393 } 0394 0395 if (d->splashScreen) 0396 { 0397 delete d->splashScreen; 0398 d->splashScreen = nullptr; 0399 } 0400 } 0401 0402 void DigikamApp::restoreSession() 0403 { 0404 // TODO: show and restore ImageEditor, Lighttable, and Batch Queue Manager main windows 0405 0406 if (qApp->isSessionRestored()) 0407 { 0408 int n = 1; 0409 0410 while (KMainWindow::canBeRestored(n)) 0411 { 0412 const QString className = KMainWindow::classNameOfToplevel(n); 0413 0414 if (className == QLatin1String(Digikam::DigikamApp::staticMetaObject.className())) 0415 { 0416 restore(n, false); 0417 break; 0418 } 0419 0420 ++n; 0421 } 0422 } 0423 } 0424 0425 void DigikamApp::closeEvent(QCloseEvent* e) 0426 { 0427 // may show a progress dialog to finish actions 0428 0429 FileActionMngr::instance()->requestShutDown(); 0430 0431 // may show a progress dialog to apply pending metadata 0432 0433 if (MetadataHubMngr::isCreated()) 0434 { 0435 MetadataHubMngr::instance()->requestShutDown(); 0436 } 0437 0438 DXmlGuiWindow::closeEvent(e); 0439 } 0440 0441 bool DigikamApp::queryClose() 0442 { 0443 bool ret = true; 0444 0445 if (ImageWindow::imageWindowCreated()) 0446 { 0447 ret &= ImageWindow::imageWindow()->queryClose(); 0448 } 0449 0450 if (QueueMgrWindow::queueManagerWindowCreated()) 0451 { 0452 ret &= QueueMgrWindow::queueManagerWindow()->queryClose(); 0453 } 0454 0455 return ret; 0456 } 0457 0458 void DigikamApp::enableZoomPlusAction(bool val) 0459 { 0460 d->zoomPlusAction->setEnabled(val); 0461 } 0462 0463 void DigikamApp::enableZoomMinusAction(bool val) 0464 { 0465 d->zoomMinusAction->setEnabled(val); 0466 } 0467 0468 void DigikamApp::enableAlbumBackwardHistory(bool enable) 0469 { 0470 d->backwardActionMenu->setEnabled(enable); 0471 } 0472 0473 void DigikamApp::enableAlbumForwardHistory(bool enable) 0474 { 0475 d->forwardActionMenu->setEnabled(enable); 0476 } 0477 0478 void DigikamApp::slotAboutToShowBackwardMenu() 0479 { 0480 0481 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0482 0483 d->backwardActionMenu->popupMenu()->clear(); 0484 0485 #else 0486 0487 d->backwardActionMenu->menu()->clear(); 0488 0489 #endif 0490 0491 QStringList titles; 0492 d->view->getBackwardHistory(titles); 0493 0494 for (int i = 0 ; i < titles.size() ; ++i) 0495 { 0496 0497 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0498 0499 QAction* const action = d->backwardActionMenu->popupMenu()->addAction(titles.at(i)); 0500 0501 #else 0502 0503 QAction* const action = d->backwardActionMenu->menu()->addAction(titles.at(i)); 0504 0505 #endif 0506 0507 int id = i + 1; 0508 0509 connect(action, &QAction::triggered, 0510 this, [this, id]() { d->view->slotAlbumHistoryBack(id); }); 0511 } 0512 } 0513 0514 void DigikamApp::slotAboutToShowForwardMenu() 0515 { 0516 0517 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0518 0519 d->forwardActionMenu->popupMenu()->clear(); 0520 0521 #else 0522 0523 d->forwardActionMenu->menu()->clear(); 0524 0525 #endif 0526 0527 QStringList titles; 0528 d->view->getForwardHistory(titles); 0529 0530 for (int i = 0 ; i < titles.size() ; ++i) 0531 { 0532 0533 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0534 0535 QAction* const action = d->forwardActionMenu->popupMenu()->addAction(titles.at(i)); 0536 0537 #else 0538 0539 QAction* const action = d->forwardActionMenu->menu()->addAction(titles.at(i)); 0540 0541 #endif 0542 0543 int id = i + 1; 0544 0545 connect(action, &QAction::triggered, 0546 this, [this, id]() { d->view->slotAlbumHistoryForward(id); }); 0547 } 0548 } 0549 0550 void DigikamApp::slotAlbumSelected(Album* album) 0551 { 0552 if (album && !album->isTrashAlbum()) 0553 { 0554 PAlbum* const palbum = dynamic_cast<PAlbum*>(album); 0555 0556 if (album->type() != Album::PHYSICAL || !palbum) 0557 { 0558 // Rules if not Physical album. 0559 0560 d->deleteAction->setEnabled(false); 0561 d->renameAction->setEnabled(false); 0562 d->propsEditAction->setEnabled(false); 0563 d->openInFileManagerAction->setEnabled(false); 0564 d->newAction->setEnabled(false); 0565 d->writeAlbumMetadataAction->setEnabled(true); 0566 d->readAlbumMetadataAction->setEnabled(true); 0567 0568 d->pasteItemsAction->setEnabled(!album->isRoot()); 0569 0570 d->selectInvertAction->setEnabled(!album->isRoot()); 0571 d->selectNoneAction->setEnabled(!album->isRoot()); 0572 d->selectAllAction->setEnabled(!album->isRoot()); 0573 0574 // Special case if Tag album. 0575 0576 bool enabled = ( 0577 (album->type() == Album::TAG) && 0578 !album->isRoot() && 0579 (album->id() != FaceTags::unconfirmedPersonTagId()) && 0580 (album->id() != FaceTags::unknownPersonTagId()) 0581 ); 0582 0583 d->newTagAction->setEnabled(enabled); 0584 d->deleteTagAction->setEnabled(enabled); 0585 d->editTagAction->setEnabled(enabled); 0586 } 0587 else 0588 { 0589 // Rules if Physical album. 0590 0591 // We have either the abstract root album, 0592 // the album root album for collection base dirs, or normal albums. 0593 0594 bool isRoot = palbum->isRoot(); 0595 bool isAlbumRoot = palbum->isAlbumRoot(); 0596 bool isNormalAlbum = !isRoot && !isAlbumRoot; 0597 0598 d->deleteAction->setEnabled(isNormalAlbum); 0599 d->renameAction->setEnabled(isNormalAlbum || isAlbumRoot); 0600 d->propsEditAction->setEnabled(isNormalAlbum); 0601 d->openInFileManagerAction->setEnabled(isNormalAlbum || isAlbumRoot); 0602 d->newAction->setEnabled(isNormalAlbum || isAlbumRoot); 0603 d->writeAlbumMetadataAction->setEnabled(isNormalAlbum || isAlbumRoot); 0604 d->readAlbumMetadataAction->setEnabled(isNormalAlbum || isAlbumRoot); 0605 0606 d->pasteItemsAction->setEnabled(isNormalAlbum || isAlbumRoot); 0607 0608 d->selectInvertAction->setEnabled(isNormalAlbum || isAlbumRoot); 0609 d->selectNoneAction->setEnabled(isNormalAlbum || isAlbumRoot); 0610 d->selectAllAction->setEnabled(isNormalAlbum || isAlbumRoot); 0611 } 0612 } 0613 else 0614 { 0615 // Rules if album is trash or no current album. 0616 0617 d->deleteAction->setEnabled(false); 0618 d->renameAction->setEnabled(false); 0619 d->propsEditAction->setEnabled(false); 0620 d->openInFileManagerAction->setEnabled(false); 0621 d->newAction->setEnabled(false); 0622 d->writeAlbumMetadataAction->setEnabled(false); 0623 d->readAlbumMetadataAction->setEnabled(false); 0624 0625 d->pasteItemsAction->setEnabled(false); 0626 d->copyItemsAction->setEnabled(false); 0627 d->cutItemsAction->setEnabled(false); 0628 0629 d->selectInvertAction->setEnabled(false); 0630 d->selectNoneAction->setEnabled(false); 0631 d->selectAllAction->setEnabled(false); 0632 0633 d->newTagAction->setEnabled(false); 0634 d->deleteTagAction->setEnabled(false); 0635 d->editTagAction->setEnabled(false); 0636 } 0637 } 0638 0639 void DigikamApp::slotImageSelected(const ItemInfoList& selection, const ItemInfoList& listAll) 0640 { 0641 qint64 listAllFileSize = 0; 0642 qint64 selectionFileSize = 0; 0643 0644 int numOfImagesInModel = 0; 0645 int numImagesWithGrouped = listAll.count(); 0646 int numImagesWithoutGrouped = d->view->allUrls(false).count(); 0647 0648 ItemInfoList selectionWithoutGrouped = d->view->selectedInfoList(true, false); 0649 0650 Q_FOREACH (const ItemInfo& info, selection) 0651 { 0652 // cppcheck-suppress useStlAlgorithm 0653 selectionFileSize += info.fileSize(); 0654 } 0655 0656 Q_FOREACH (const ItemInfo& info, listAll) 0657 { 0658 // cppcheck-suppress useStlAlgorithm 0659 listAllFileSize += info.fileSize(); 0660 } 0661 0662 Album* const album = d->view->currentAlbum(); 0663 0664 if (album && (album->type() == Album::PHYSICAL)) 0665 { 0666 numOfImagesInModel = d->view->itemCount(); 0667 } 0668 0669 QString statusBarSelectionText; 0670 QString statusBarSelectionToolTip; 0671 0672 switch (selection.count()) 0673 { 0674 case 0: 0675 { 0676 if (numImagesWithGrouped == numImagesWithoutGrouped) 0677 { 0678 statusBarSelectionText = i18np("No item selected (%1 item)", 0679 "No item selected (%1 items)", 0680 numImagesWithoutGrouped); 0681 break; 0682 } 0683 0684 statusBarSelectionText = i18np("No item selected (%1 [%2] item)", 0685 "No item selected (%1 [%2] items)", 0686 numImagesWithoutGrouped, 0687 numImagesWithGrouped); 0688 0689 statusBarSelectionToolTip = i18np("No item selected (%1 item. With grouped items: %2)", 0690 "No item selected (%1 items. With grouped items: %2)", 0691 numImagesWithoutGrouped, 0692 numImagesWithGrouped); 0693 break; 0694 } 0695 0696 default: 0697 { 0698 if (numImagesWithGrouped == numImagesWithoutGrouped) 0699 { 0700 statusBarSelectionText = i18np("1/%2 item selected (%3/%4)", 0701 "%1/%2 items selected (%3/%4)", 0702 selection.count(), 0703 numImagesWithoutGrouped, 0704 ItemPropertiesTab::humanReadableBytesCount(selectionFileSize), 0705 ItemPropertiesTab::humanReadableBytesCount(listAllFileSize)); 0706 break; 0707 } 0708 0709 if (selectionWithoutGrouped.count() > 1) 0710 { 0711 if (selection.count() == selectionWithoutGrouped.count()) 0712 { 0713 statusBarSelectionText = i18np("1/%2 [%3] item selected (%4/%5)", 0714 "%1/%2 [%3] items selected (%4/%5)", 0715 selectionWithoutGrouped.count(), 0716 numImagesWithoutGrouped, 0717 numImagesWithGrouped, 0718 ItemPropertiesTab::humanReadableBytesCount(selectionFileSize), 0719 ItemPropertiesTab::humanReadableBytesCount(listAllFileSize)); 0720 0721 statusBarSelectionToolTip = i18np("1/%2 item selected. Total with grouped items: %3", 0722 "%1/%2 items selected. Total with grouped items: %3", 0723 selectionWithoutGrouped.count(), 0724 numImagesWithoutGrouped, 0725 numImagesWithGrouped); 0726 } 0727 else 0728 { 0729 statusBarSelectionText = i18np("1/%2 [%3/%4] item selected (%5/%6)", 0730 "%1/%2 [%3/%4] items selected (%5/%6)", 0731 selectionWithoutGrouped.count(), 0732 numImagesWithoutGrouped, 0733 selection.count(), 0734 numImagesWithGrouped, 0735 ItemPropertiesTab::humanReadableBytesCount(selectionFileSize), 0736 ItemPropertiesTab::humanReadableBytesCount(listAllFileSize)); 0737 0738 statusBarSelectionToolTip = i18np("1/%2 item selected. With grouped items: %3/%4", 0739 "%1/%2 items selected. With grouped items: %3/%4", 0740 selectionWithoutGrouped.count(), 0741 numImagesWithoutGrouped, 0742 selection.count(), 0743 numImagesWithGrouped); 0744 } 0745 0746 break; 0747 } 0748 0749 #if __GNUC__ >= 7 // krazy:exclude=cpp 0750 0751 // no break; is completely intentional, arriving here is equivalent to case 1: 0752 [[fallthrough]]; 0753 0754 #endif 0755 } 0756 0757 case 1: 0758 { 0759 if (!selectionWithoutGrouped.isEmpty()) 0760 { 0761 slotSetCheckedExifOrientationAction(selectionWithoutGrouped.first()); 0762 } 0763 0764 int index = listAll.indexOf(selection.first()) + 1; 0765 0766 if (numImagesWithGrouped == numImagesWithoutGrouped) 0767 { 0768 statusBarSelectionText = selection.first().fileUrl().fileName() 0769 + i18n(" (%1 of %2)", 0770 index, numImagesWithoutGrouped); 0771 } 0772 else 0773 { 0774 int indexWithoutGrouped = 0; 0775 0776 if (!selectionWithoutGrouped.isEmpty()) 0777 { 0778 indexWithoutGrouped = d->view->allInfo(false).indexOf(selectionWithoutGrouped.first()) + 1; 0779 } 0780 0781 statusBarSelectionText 0782 = selection.first().fileUrl().fileName() 0783 + i18n(" (%1 of %2 [%3] )", indexWithoutGrouped, 0784 numImagesWithoutGrouped, numImagesWithGrouped); 0785 statusBarSelectionToolTip 0786 = selection.first().fileUrl().fileName() 0787 + i18n(" (%1 of %2. Total with grouped items: %3)", indexWithoutGrouped, 0788 numImagesWithoutGrouped, numImagesWithGrouped); 0789 } 0790 0791 break; 0792 } 0793 } 0794 0795 if (numImagesWithGrouped < numOfImagesInModel) 0796 { 0797 statusBarSelectionText += QLatin1String(" - "); 0798 statusBarSelectionText += i18np("%1 item hidden", "%1 items hidden", 0799 numOfImagesInModel - numImagesWithGrouped); 0800 } 0801 0802 d->statusLabel->setAdjustedText(statusBarSelectionText); 0803 d->statusLabel->setToolTip(statusBarSelectionToolTip); 0804 } 0805 0806 void DigikamApp::slotTrashSelectionChanged(const QString& text) 0807 { 0808 d->statusLabel->setAdjustedText(text); 0809 d->statusLabel->setToolTip(text); 0810 } 0811 0812 void DigikamApp::slotSelectionChanged(int selectionCount) 0813 { 0814 // The preview can either be activated when only one image is selected, 0815 // or if multiple images are selected, but one image is the 'current image'. 0816 0817 bool hasAtLeastCurrent = (selectionCount == 1) || ((selectionCount > 0) && d->view->hasCurrentItem()); 0818 0819 d->imagePreviewAction->setEnabled(hasAtLeastCurrent); 0820 d->imageViewAction->setEnabled(hasAtLeastCurrent); 0821 d->imageScanForFacesAction->setEnabled(selectionCount > 0); 0822 d->imageRemoveAllFacesAction->setEnabled(selectionCount > 0); 0823 d->imageFindSimilarAction->setEnabled(selectionCount == 1); 0824 d->imageRenameAction->setEnabled(selectionCount > 0); 0825 d->imageLightTableAction->setEnabled(selectionCount > 0); 0826 d->imageAddLightTableAction->setEnabled(selectionCount > 0); 0827 d->imageAddCurrentQueueAction->setEnabled((selectionCount > 0) && !QueueMgrWindow::queueManagerWindow()->isBusy()); 0828 d->imageAddNewQueueAction->setEnabled((selectionCount > 0) && !QueueMgrWindow::queueManagerWindow()->isBusy()); 0829 d->imageWriteMetadataAction->setEnabled(selectionCount > 0); 0830 d->imageReadMetadataAction->setEnabled(selectionCount > 0); 0831 d->imageDeleteAction->setEnabled(selectionCount > 0); 0832 d->imageRotateActionMenu->setEnabled(selectionCount > 0); 0833 d->imageFlipActionMenu->setEnabled(selectionCount > 0); 0834 d->imageExifOrientationActionMenu->setEnabled(selectionCount > 0); 0835 d->moveSelectionToAlbumAction->setEnabled(selectionCount > 0); 0836 d->copySelectionToAction->setEnabled(selectionCount > 0); 0837 d->cutItemsAction->setEnabled(selectionCount > 0); 0838 d->copyItemsAction->setEnabled(selectionCount > 0); 0839 d->openWithAction->setEnabled(selectionCount > 0); 0840 d->imageAutoExifActionMenu->setEnabled(selectionCount > 0); 0841 0842 Q_FOREACH (DPluginAction* const ac, DPluginLoader::instance()->pluginsActions(DPluginAction::GenericMetadata, this)) 0843 { 0844 ac->setEnabled(selectionCount > 0); 0845 } 0846 0847 if (selectionCount > 0) 0848 { 0849 d->imageWriteMetadataAction->setText(i18np("Write Metadata to File", 0850 "Write Metadata to Selected Files", selectionCount)); 0851 d->imageReadMetadataAction->setText(i18np("Reread Metadata From File", 0852 "Reread Metadata From Selected Files", selectionCount)); 0853 0854 slotResetExifOrientationActions(); 0855 } 0856 } 0857 0858 void DigikamApp::slotExit() 0859 { 0860 close(); 0861 } 0862 0863 void DigikamApp::slotDBStat() 0864 { 0865 showDigikamDatabaseStat(); 0866 } 0867 0868 void DigikamApp::slotRecurseAlbums(bool checked) 0869 { 0870 d->view->setRecurseAlbums(checked); 0871 } 0872 0873 void DigikamApp::slotRecurseTags(bool checked) 0874 { 0875 d->view->setRecurseTags(checked); 0876 } 0877 0878 void DigikamApp::slotAllGroupsOpen(bool checked) 0879 { 0880 d->view->setAllGroupsOpen(checked); 0881 } 0882 0883 void DigikamApp::slotZoomSliderChanged(int size) 0884 { 0885 d->view->setThumbSize(size); 0886 } 0887 0888 void DigikamApp::slotThumbSizeChanged(int size) 0889 { 0890 d->zoomBar->setThumbsSize(size); 0891 0892 if (!fullScreenIsActive() && d->autoShowZoomToolTip) 0893 { 0894 d->zoomBar->triggerZoomTrackerToolTip(); 0895 } 0896 } 0897 0898 void DigikamApp::slotZoomChanged(double zoom) 0899 { 0900 double zmin = d->view->zoomMin(); 0901 double zmax = d->view->zoomMax(); 0902 d->zoomBar->setZoom(zoom, zmin, zmax); 0903 0904 if (!fullScreenIsActive() && d->autoShowZoomToolTip) 0905 { 0906 d->zoomBar->triggerZoomTrackerToolTip(); 0907 } 0908 } 0909 0910 void DigikamApp::slotToggleShowBar() 0911 { 0912 d->view->toggleShowBar(d->showBarAction->isChecked()); 0913 } 0914 0915 void DigikamApp::moveEvent(QMoveEvent*) 0916 { 0917 Q_EMIT signalWindowHasMoved(); 0918 } 0919 0920 void DigikamApp::slotTransformAction() 0921 { 0922 if (sender()->objectName() == QLatin1String("rotate_ccw")) 0923 { 0924 d->view->imageTransform(MetaEngineRotation::Rotate270); 0925 } 0926 else if (sender()->objectName() == QLatin1String("rotate_cw")) 0927 { 0928 d->view->imageTransform(MetaEngineRotation::Rotate90); 0929 } 0930 else if (sender()->objectName() == QLatin1String("flip_horizontal")) 0931 { 0932 d->view->imageTransform(MetaEngineRotation::FlipHorizontal); 0933 } 0934 else if (sender()->objectName() == QLatin1String("flip_vertical")) 0935 { 0936 d->view->imageTransform(MetaEngineRotation::FlipVertical); 0937 } 0938 else if (sender()->objectName() == QLatin1String("image_transform_exif")) 0939 { 0940 // special value for FileActionMngr 0941 0942 d->view->imageTransform(MetaEngineRotation::NoTransformation); 0943 } 0944 } 0945 0946 void DigikamApp::slotResetExifOrientationActions() 0947 { 0948 d->imageSetExifOrientation1Action->setChecked(false); 0949 d->imageSetExifOrientation2Action->setChecked(false); 0950 d->imageSetExifOrientation3Action->setChecked(false); 0951 d->imageSetExifOrientation4Action->setChecked(false); 0952 d->imageSetExifOrientation5Action->setChecked(false); 0953 d->imageSetExifOrientation6Action->setChecked(false); 0954 d->imageSetExifOrientation7Action->setChecked(false); 0955 d->imageSetExifOrientation8Action->setChecked(false); 0956 } 0957 0958 void DigikamApp::slotSetCheckedExifOrientationAction(const ItemInfo& info) 0959 { 0960 /* 0961 QScopedPointer<DMetadata> meta(new DMetadata(info.fileUrl().toLocalFile())); 0962 int orientation = (meta->isEmpty()) ? 0 : meta->getItemOrientation(); 0963 */ 0964 int orientation = info.orientation(); 0965 0966 switch (orientation) 0967 { 0968 case 1: 0969 d->imageSetExifOrientation1Action->setChecked(true); 0970 break; 0971 0972 case 2: 0973 d->imageSetExifOrientation2Action->setChecked(true); 0974 break; 0975 0976 case 3: 0977 d->imageSetExifOrientation3Action->setChecked(true); 0978 break; 0979 0980 case 4: 0981 d->imageSetExifOrientation4Action->setChecked(true); 0982 break; 0983 0984 case 5: 0985 d->imageSetExifOrientation5Action->setChecked(true); 0986 break; 0987 0988 case 6: 0989 d->imageSetExifOrientation6Action->setChecked(true); 0990 break; 0991 0992 case 7: 0993 d->imageSetExifOrientation7Action->setChecked(true); 0994 break; 0995 0996 case 8: 0997 d->imageSetExifOrientation8Action->setChecked(true); 0998 break; 0999 1000 default: 1001 slotResetExifOrientationActions(); 1002 break; 1003 } 1004 } 1005 1006 void DigikamApp::showSideBars(bool visible) 1007 { 1008 visible ? d->view->showSideBars() 1009 : d->view->hideSideBars(); 1010 } 1011 1012 void DigikamApp::slotToggleLeftSideBar() 1013 { 1014 d->view->toggleLeftSidebar(); 1015 } 1016 1017 void DigikamApp::slotToggleRightSideBar() 1018 { 1019 d->view->toggleRightSidebar(); 1020 } 1021 1022 void DigikamApp::slotPreviousLeftSideBarTab() 1023 { 1024 d->view->previousLeftSideBarTab(); 1025 } 1026 1027 void DigikamApp::slotNextLeftSideBarTab() 1028 { 1029 d->view->nextLeftSideBarTab(); 1030 } 1031 1032 void DigikamApp::slotNextRightSideBarTab() 1033 { 1034 d->view->nextRightSideBarTab(); 1035 } 1036 1037 void DigikamApp::slotPreviousRightSideBarTab() 1038 { 1039 d->view->previousRightSideBarTab(); 1040 } 1041 1042 void DigikamApp::showThumbBar(bool visible) 1043 { 1044 view()->toggleShowBar(visible); 1045 } 1046 1047 bool DigikamApp::thumbbarVisibility() const 1048 { 1049 return d->showBarAction->isChecked(); 1050 } 1051 1052 void DigikamApp::slotSwitchedToPreview() 1053 { 1054 d->zoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); 1055 d->imagePreviewAction->setChecked(true); 1056 customizedTrashView(true); 1057 toggleShowBar(); 1058 } 1059 1060 void DigikamApp::slotSwitchedToIconView() 1061 { 1062 d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); 1063 d->imageIconViewAction->setChecked(true); 1064 customizedTrashView(true); 1065 toggleShowBar(); 1066 } 1067 1068 void DigikamApp::slotSwitchedToMapView() 1069 { 1070 // TODO: Link to map view's zoom actions 1071 1072 d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); 1073 1074 #ifdef HAVE_GEOLOCATION 1075 1076 d->imageMapViewAction->setChecked(true); 1077 1078 #endif // HAVE_GEOLOCATION 1079 1080 customizedTrashView(true); 1081 toggleShowBar(); 1082 } 1083 1084 void DigikamApp::slotSwitchedToTableView() 1085 { 1086 d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); 1087 d->imageTableViewAction->setChecked(true); 1088 customizedTrashView(true); 1089 toggleShowBar(); 1090 } 1091 1092 void DigikamApp::slotSwitchedToTrashView() 1093 { 1094 d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl); 1095 customizedTrashView(false); 1096 toggleShowBar(); 1097 } 1098 1099 void DigikamApp::customizedFullScreenMode(bool set) 1100 { 1101 toolBarMenuAction()->setEnabled(!set); 1102 showMenuBarAction()->setEnabled(!set); 1103 showStatusBarAction()->setEnabled(!set); 1104 1105 set ? d->showBarAction->setEnabled(false) 1106 : toggleShowBar(); 1107 1108 d->view->toggleFullScreen(set); 1109 } 1110 1111 void DigikamApp::customizedTrashView(bool set) 1112 { 1113 d->imageTableViewAction->setEnabled(set); 1114 d->imageIconViewAction->setEnabled(set); 1115 1116 #ifdef HAVE_GEOLOCATION 1117 1118 d->imageMapViewAction->setEnabled(set); 1119 1120 #endif 1121 1122 d->imagePreviewAction->setEnabled(set); 1123 d->bqmAction->setEnabled(set); 1124 d->ltAction->setEnabled(set); 1125 d->ieAction->setEnabled(set); 1126 1127 d->imageSeparationSortOrderAction->setEnabled(set); 1128 d->imageSeparationAction->setEnabled(set); 1129 d->imageSortOrderAction->setEnabled(set); 1130 d->imageSortAction->setEnabled(set); 1131 d->albumSortAction->setEnabled(set); 1132 1133 d->zoomFitToWindowAction->setEnabled(set); 1134 d->recurseAlbumsAction->setEnabled(set); 1135 d->recurseTagsAction->setEnabled(set); 1136 d->refreshAction->setEnabled(set); 1137 1138 Q_FOREACH (DPluginAction* const ac, DPluginLoader::instance()->pluginsActions(DPluginAction::GenericView, this)) 1139 { 1140 ac->setEnabled(set); 1141 } 1142 } 1143 1144 void DigikamApp::toggleShowBar() 1145 { 1146 switch (d->view->viewMode()) 1147 { 1148 case StackedView::PreviewImageMode: 1149 case StackedView::MediaPlayerMode: 1150 d->showBarAction->setEnabled(true); 1151 break; 1152 1153 default: 1154 d->showBarAction->setEnabled(false); 1155 break; 1156 } 1157 } 1158 1159 void DigikamApp::slotComponentsInfo() 1160 { 1161 showDigikamComponentsInfo(); 1162 } 1163 1164 void DigikamApp::slotOnlineVersionCheck() 1165 { 1166 Setup::onlineVersionCheck(); 1167 } 1168 1169 void DigikamApp::slotToggleColorManagedView() 1170 { 1171 if (!IccSettings::instance()->isEnabled()) 1172 { 1173 return; 1174 } 1175 1176 bool cmv = !IccSettings::instance()->settings().useManagedPreviews; 1177 IccSettings::instance()->setUseManagedPreviews(cmv); 1178 } 1179 1180 void DigikamApp::slotColorManagementOptionsChanged() 1181 { 1182 ICCSettingsContainer settings = IccSettings::instance()->settings(); 1183 1184 ThumbnailLoadThread::setDisplayingWidget(this); 1185 1186 d->viewCMViewAction->blockSignals(true); 1187 d->viewCMViewAction->setEnabled(settings.enableCM); 1188 d->viewCMViewAction->setChecked(settings.useManagedPreviews); 1189 d->viewCMViewAction->blockSignals(false); 1190 } 1191 1192 DInfoInterface* DigikamApp::infoIface(DPluginAction* const ac) 1193 { 1194 ApplicationSettings::OperationType aset = ApplicationSettings::Unspecified; 1195 1196 switch (ac->actionCategory()) 1197 { 1198 case DPluginAction::GenericExport: 1199 case DPluginAction::GenericImport: 1200 aset = ApplicationSettings::ImportExport; 1201 break; 1202 1203 case DPluginAction::GenericMetadata: 1204 aset = ApplicationSettings::Metadata; 1205 break; 1206 1207 case DPluginAction::GenericTool: 1208 aset = ApplicationSettings::Tools; 1209 break; 1210 1211 case DPluginAction::GenericView: 1212 aset = ApplicationSettings::Slideshow; 1213 break; 1214 1215 default: 1216 break; 1217 } 1218 1219 DBInfoIface* const iface = new DBInfoIface(this, QList<QUrl>(), aset); 1220 1221 connect(iface, SIGNAL(signalImportedImage(QUrl)), 1222 this, SLOT(slotImportedImagefromScanner(QUrl))); 1223 1224 if (aset == ApplicationSettings::Slideshow) 1225 { 1226 connect(iface, SIGNAL(signalLastItemUrl(QUrl)), 1227 d->view, SLOT(slotSetCurrentUrlWhenAvailable(QUrl))); 1228 } 1229 1230 return iface; 1231 } 1232 1233 } // namespace Digikam 1234 1235 #include "moc_digikamapp.cpp"