File indexing completed on 2025-01-19 03:50:42
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2002-07-28 0007 * Description : main program from digiKam 0008 * 0009 * SPDX-FileCopyrightText: 2002-2006 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 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "digikam_config.h" 0017 0018 // Qt includes 0019 0020 #include <QDir> 0021 #include <QFile> 0022 #include <QString> 0023 #include <QFileInfo> 0024 #include <QSettings> 0025 #include <QStringList> 0026 #include <QMessageBox> 0027 #include <QSqlDatabase> 0028 #include <QApplication> 0029 #include <QImageReader> 0030 #include <QStandardPaths> 0031 #include <QCommandLineParser> 0032 #include <QCommandLineOption> 0033 0034 // KDE includes 0035 0036 #include <klocalizedstring.h> 0037 #include <ksharedconfig.h> 0038 #include <kconfiggroup.h> 0039 #include <kaboutdata.h> 0040 0041 // ImageMagick includes 0042 0043 #ifdef HAVE_IMAGE_MAGICK 0044 0045 // Pragma directives to reduce warnings from ImageMagick header files. 0046 # if !defined(Q_OS_DARWIN) && defined(Q_CC_GNU) 0047 # pragma GCC diagnostic push 0048 # pragma GCC diagnostic ignored "-Wignored-qualifiers" 0049 # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 0050 # endif 0051 0052 # if defined(Q_CC_CLANG) 0053 # pragma clang diagnostic push 0054 # pragma clang diagnostic ignored "-Wignored-qualifiers" 0055 # pragma clang diagnostic ignored "-Wkeyword-macro" 0056 # endif 0057 0058 # include <Magick++.h> 0059 using namespace Magick; 0060 0061 // Restore warnings 0062 # if !defined(Q_OS_DARWIN) && defined(Q_CC_GNU) 0063 # pragma GCC diagnostic pop 0064 # endif 0065 0066 # if defined(Q_CC_CLANG) 0067 # pragma clang diagnostic pop 0068 # endif 0069 0070 #endif // HAVE_IMAGE_MAGICK 0071 0072 // Local includes 0073 0074 #include "digikam_debug.h" 0075 #include "digikam_version.h" 0076 #include "digikam_globals.h" 0077 #include "systemsettings.h" 0078 #include "metaengine.h" 0079 #include "dmessagebox.h" 0080 #include "albummanager.h" 0081 #include "firstrundlg.h" 0082 #include "collectionlocation.h" 0083 #include "collectionmanager.h" 0084 #include "daboutdata.h" 0085 #include "dbengineparameters.h" 0086 #include "digikamapp.h" 0087 #include "scancontroller.h" 0088 #include "coredbaccess.h" 0089 #include "thumbsdbaccess.h" 0090 #include "facedbaccess.h" 0091 #include "dxmlguiwindow.h" 0092 #include "applicationsettings.h" 0093 #include "similaritydbaccess.h" 0094 #include "databaseserverstarter.h" 0095 #include "filesdownloader.h" 0096 #include "dfileoperations.h" 0097 0098 #ifdef Q_OS_WIN 0099 # include <windows.h> 0100 # include <shellapi.h> 0101 # include <objbase.h> 0102 #endif 0103 0104 #if defined Q_OS_WIN 0105 # define MAIN_EXPORT __declspec(dllexport) 0106 # define MAIN_FN digikam_main 0107 #else 0108 # define MAIN_EXPORT 0109 # define MAIN_FN main 0110 #endif 0111 0112 using namespace Digikam; 0113 0114 extern "C" MAIN_EXPORT int MAIN_FN(int argc, char** argv) 0115 { 0116 SystemSettings system(QLatin1String("digikam")); 0117 0118 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0119 0120 // These settings has no effect with Qt6 (always enabled) 0121 0122 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, 0123 system.useHighDpiPixmaps); 0124 0125 0126 if (system.useHighDpiScaling) 0127 { 0128 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0129 } 0130 else 0131 { 0132 QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); 0133 } 0134 0135 #else 0136 0137 QImageReader::setAllocationLimit(2048); 0138 0139 #endif 0140 0141 if (system.softwareOpenGL) 0142 { 0143 QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); 0144 } 0145 0146 // OpenCV crash with face engine with OpenCL support 0147 // https://bugs.kde.org/show_bug.cgi?id=423632 0148 // https://bugs.kde.org/show_bug.cgi?id=426175 0149 0150 if (system.disableOpenCL) 0151 { 0152 qputenv("OPENCV_OPENCL_RUNTIME", "disabled"); 0153 qputenv("OPENCV_OPENCL_DEVICE", "disabled"); 0154 } 0155 0156 QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor); 0157 0158 #ifdef HAVE_QWEBENGINE 0159 0160 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); 0161 0162 #endif 0163 0164 QApplication app(argc, argv); 0165 0166 digikamSetDebugFilterRules(system.enableLogging); 0167 0168 tryInitDrMingw(); 0169 0170 #ifdef HAVE_IMAGE_MAGICK 0171 0172 #ifdef Q_CC_MSVC 0173 0174 qputenv("MAGICK_CODER_MODULE_PATH", qApp->applicationDirPath().toUtf8()); 0175 qputenv("MAGICK_CODER_FILTER_PATH", qApp->applicationDirPath().toUtf8()); 0176 0177 #endif 0178 0179 InitializeMagick(nullptr); 0180 0181 #endif 0182 0183 #ifdef Q_OS_MACOS 0184 0185 // See bug #461734 0186 app.setAttribute(Qt::AA_DontShowIconsInMenus, true); 0187 0188 #endif 0189 0190 // if we have some local breeze icon resource, prefer it 0191 0192 DXmlGuiWindow::setupIconTheme(); 0193 0194 KLocalizedString::setApplicationDomain("digikam"); 0195 0196 KAboutData aboutData(QLatin1String("digikam"), // component name 0197 i18n("digiKam"), // display name 0198 digiKamVersion()); 0199 0200 aboutData.setShortDescription(QString::fromUtf8("%1 - %2").arg(DAboutData::digiKamSlogan()) 0201 .arg(DAboutData::digiKamFamily())); 0202 aboutData.setLicense(KAboutLicense::GPL); 0203 aboutData.setCopyrightStatement(DAboutData::copyright()); 0204 aboutData.setOtherText(additionalInformation()); 0205 aboutData.setHomepage(DAboutData::webProjectUrl().url()); 0206 aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), 0207 i18nc("EMAIL OF TRANSLATORS", "Your emails")); 0208 0209 DAboutData::authorsRegistration(aboutData); 0210 0211 QCommandLineParser parser; 0212 KAboutData::setApplicationData(aboutData); 0213 aboutData.setupCommandLine(&parser); 0214 parser.addOption(QCommandLineOption(QStringList() << QLatin1String("download-from"), 0215 i18n("Open camera dialog at \"path\""), 0216 QLatin1String("path"))); 0217 parser.addOption(QCommandLineOption(QStringList() << QLatin1String("download-from-udi"), 0218 i18n("Open camera dialog for the device with Solid UDI \"udi\""), 0219 QLatin1String("udi"))); 0220 parser.addOption(QCommandLineOption(QStringList() << QLatin1String("detect-camera"), 0221 i18n("Automatically detect and open a connected gphoto2 camera"))); 0222 parser.addOption(QCommandLineOption(QStringList() << QLatin1String("database-directory"), 0223 i18n("Start digikam with the SQLite database file found in the directory \"dir\""), 0224 QLatin1String("dir"))); 0225 parser.addOption(QCommandLineOption(QStringList() << QLatin1String("config"), 0226 i18n("Start digikam with the configuration file \"config\""), 0227 QLatin1String("config"))); 0228 0229 parser.process(app); 0230 aboutData.processCommandLine(&parser); 0231 0232 setupKSycocaDatabaseFile(); 0233 0234 // See bug #438701 0235 0236 installQtTranslationFiles(app); 0237 0238 // --- 0239 0240 MetaEngine::initializeExiv2(); 0241 0242 // Force to use application icon for non plasma desktop as Unity for ex. 0243 0244 QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("digikam"), app.windowIcon())); 0245 0246 #ifdef Q_OS_WIN 0247 0248 if (QSysInfo::currentCpuArchitecture().contains(QLatin1String("64")) && 0249 !QSysInfo::buildCpuArchitecture().contains(QLatin1String("64"))) 0250 { 0251 QMessageBox::critical(qApp->activeWindow(), 0252 qApp->applicationName(), 0253 i18n("<p>You are running digiKam as a 32-bit version on a 64-bit Windows.</p>" 0254 "<p>Please install the 64-bit version of digiKam to get " 0255 "a better experience with digiKam.</p>")); 0256 } 0257 0258 QString appPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 0259 QUrl appUrl = QUrl::fromLocalFile(appPath).adjusted(QUrl::RemoveFilename); 0260 appUrl.setPath(appUrl.path() + QLatin1String("digikam/facesengine")); 0261 0262 QFileInfo appInfo(appUrl.toLocalFile()); 0263 0264 if (appInfo.exists() && appInfo.isDir()) 0265 { 0266 QString appLocalPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); 0267 QUrl appLocalUrl = QUrl::fromLocalFile(appLocalPath).adjusted(QUrl::RemoveFilename); 0268 appLocalUrl.setPath(appLocalUrl.path() + QLatin1String("digikam")); 0269 0270 qCDebug(DIGIKAM_GENERAL_LOG) << "Copy faces engine data from" 0271 << appUrl.toLocalFile() << "to" 0272 << appLocalUrl.toLocalFile(); 0273 0274 if (DFileOperations::copyFolderRecursively(appUrl.toLocalFile(), appLocalUrl.toLocalFile())) 0275 { 0276 qCDebug(DIGIKAM_GENERAL_LOG) << "Delete faces engine data from" 0277 << appUrl.toLocalFile(); 0278 0279 QDir rmAppPath(appUrl.toLocalFile()); 0280 rmAppPath.removeRecursively(); 0281 } 0282 } 0283 0284 #endif 0285 0286 // Check if Qt database plugins are available. 0287 0288 if (!QSqlDatabase::isDriverAvailable(DbEngineParameters::SQLiteDatabaseType()) && 0289 !QSqlDatabase::isDriverAvailable(DbEngineParameters::MySQLDatabaseType())) 0290 { 0291 if (QSqlDatabase::drivers().isEmpty()) 0292 { 0293 QMessageBox::critical(qApp->activeWindow(), 0294 qApp->applicationName(), 0295 i18n("Run-time Qt SQLite or MySQL database plugin is not available. " 0296 "please install it.\n" 0297 "There is no database plugin installed on your computer.")); 0298 } 0299 else 0300 { 0301 DMessageBox::showInformationList(QMessageBox::Warning, 0302 qApp->activeWindow(), 0303 qApp->applicationName(), 0304 i18n("Run-time Qt SQLite or MySQL database plugin are not available. " 0305 "Please install it.\n" 0306 "Database plugins installed on your computer are listed below."), 0307 QSqlDatabase::drivers()); 0308 } 0309 0310 qCDebug(DIGIKAM_GENERAL_LOG) << "QT Sql drivers list: " << QSqlDatabase::drivers(); 0311 0312 return 1; 0313 } 0314 0315 QString commandLineDBPath; 0316 0317 if (parser.isSet(QLatin1String("database-directory"))) 0318 { 0319 QDir commandLineDBDir(parser.value(QLatin1String("database-directory"))); 0320 0321 if (!commandLineDBDir.exists()) 0322 { 0323 qCDebug(DIGIKAM_GENERAL_LOG) << "The given database-directory does not exist or is not readable. Ignoring." 0324 << commandLineDBDir.absolutePath(); 0325 } 0326 else 0327 { 0328 commandLineDBPath = commandLineDBDir.absolutePath(); 0329 } 0330 } 0331 0332 if (parser.isSet(QLatin1String("config"))) 0333 { 0334 QString configFilename = parser.value(QLatin1String("config")); 0335 QFileInfo configFile(configFilename); 0336 0337 if (configFile.isDir() || !configFile.dir().exists() || 0338 !configFile.isReadable() || !configFile.isWritable()) 0339 { 0340 QMessageBox::critical(qApp->activeWindow(), 0341 qApp->applicationName(), 0342 QLatin1String("--config ") + 0343 configFilename + 0344 i18n("<p>The given path for the config file " 0345 "is not valid. Either its parent " 0346 "directory does not exist, it is a " 0347 "directory itself or it cannot be read/" 0348 "written to.</p>")); 0349 qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid path: --config" 0350 << configFilename; 0351 return 1; 0352 } 0353 } 0354 0355 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0356 KConfigGroup group = config->group(QLatin1String("General Settings")); 0357 QString version = group.readEntry(QLatin1String("Version"), QString()); 0358 QString iconTheme = group.readEntry(QLatin1String("Icon Theme"), QString()); 0359 KConfigGroup mainConfig = config->group(QLatin1String("Album Settings")); 0360 0361 QString firstAlbumPath; 0362 DbEngineParameters params; 0363 0364 // Run the first run assistant if we have no or very old config 0365 0366 if (!mainConfig.exists() || (version.startsWith(QLatin1String("0.5")))) 0367 { 0368 FirstRunDlg firstRun; 0369 firstRun.show(); 0370 0371 if (firstRun.exec() == QDialog::Rejected) 0372 { 0373 return 1; 0374 } 0375 0376 // parameters are written to config 0377 0378 firstAlbumPath = firstRun.firstAlbumPath(); 0379 0380 if (firstRun.getDbEngineParameters().isSQLite()) 0381 { 0382 AlbumManager::checkDatabaseDirsAfterFirstRun(firstRun.getDbEngineParameters().getCoreDatabaseNameOrDir(), firstAlbumPath); 0383 } 0384 } 0385 0386 if (!commandLineDBPath.isNull()) 0387 { 0388 // command line option set? 0389 0390 params = DbEngineParameters::parametersForSQLiteDefaultFile(commandLineDBPath); 0391 ApplicationSettings::instance()->setDatabaseDirSetAtCmd(true); 0392 ApplicationSettings::instance()->setDbEngineParameters(params); 0393 } 0394 else 0395 { 0396 params = DbEngineParameters::parametersFromConfig(); 0397 params.legacyAndDefaultChecks(firstAlbumPath); 0398 0399 // sync to config, for all first-run or upgrade situations 0400 0401 params.writeToConfig(); 0402 ApplicationSettings::instance()->setDbEngineParameters(params); 0403 } 0404 0405 // initialize database 0406 0407 if (!AlbumManager::instance()->setDatabase(params, !commandLineDBPath.isNull(), firstAlbumPath)) 0408 { 0409 DatabaseServerStarter::instance()->stopServerManagerProcess(); 0410 0411 CoreDbAccess::cleanUpDatabase(); 0412 ThumbsDbAccess::cleanUpDatabase(); 0413 FaceDbAccess::cleanUpDatabase(); 0414 SimilarityDbAccess::cleanUpDatabase(); 0415 0416 return 0; 0417 } 0418 0419 if (!iconTheme.isEmpty()) 0420 { 0421 QIcon::setThemeName(iconTheme); 0422 } 0423 0424 #ifdef Q_OS_WIN 0425 0426 // Necessary to open native open with dialog on windows 0427 0428 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); 0429 0430 #endif 0431 0432 // create main window 0433 0434 DigikamApp* const digikam = new DigikamApp(); 0435 0436 // If application storage place in home directory to save customized XML settings files do not exist, create it, 0437 // else QFile will not able to create new files as well. 0438 0439 if (!QFile::exists(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) 0440 { 0441 QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); 0442 } 0443 0444 // If application cache place in home directory to save cached files do not exist, create it. 0445 if (!QFile::exists(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))) 0446 { 0447 QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); 0448 } 0449 0450 // Bug #247175: 0451 // Add a connection to the destroyed() signal when the digiKam mainwindow has been 0452 // closed. This should prevent digiKam from staying open in the background. 0453 // 0454 // Right now this is the easiest and cleanest fix for the described problem, but we might re-think the 0455 // solution later on, just in case there are better ways to do it. 0456 0457 QObject::connect(digikam, SIGNAL(destroyed(QObject*)), 0458 &app, SLOT(quit())); 0459 0460 digikam->restoreSession(); 0461 digikam->show(); 0462 0463 if (system.enableFaceEngine || system.enableAesthetic || system.enableAutoTags) 0464 { 0465 QPointer<FilesDownloader> floader = new FilesDownloader(qApp->activeWindow()); 0466 0467 if (!floader->checkDownloadFiles()) 0468 { 0469 floader->startDownload(); 0470 } 0471 0472 delete floader; 0473 } 0474 0475 if (parser.isSet(QLatin1String("download-from"))) 0476 { 0477 digikam->downloadFrom(parser.value(QLatin1String("download-from"))); 0478 } 0479 else if (parser.isSet(QLatin1String("download-from-udi"))) 0480 { 0481 digikam->downloadFromUdi(parser.value(QLatin1String("download-from-udi"))); 0482 } 0483 else if (parser.isSet(QLatin1String("detect-camera"))) 0484 { 0485 digikam->autoDetect(); 0486 } 0487 0488 int ret = app.exec(); 0489 0490 CoreDbAccess::cleanUpDatabase(); 0491 ThumbsDbAccess::cleanUpDatabase(); 0492 FaceDbAccess::cleanUpDatabase(); 0493 SimilarityDbAccess::cleanUpDatabase(); 0494 0495 #ifdef Q_OS_WIN 0496 0497 // Necessary to open native open with dialog on windows 0498 CoUninitialize(); 0499 0500 #endif 0501 0502 #ifdef HAVE_IMAGE_MAGICK 0503 # if MagickLibVersion >= 0x693 0504 0505 TerminateMagick(); 0506 0507 # endif 0508 #endif 0509 0510 return ret; 0511 }