File indexing completed on 2025-01-19 03:53:20
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2004-06-15 0007 * Description : Albums manager interface - Database helpers. 0008 * 0009 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0011 * SPDX-FileCopyrightText: 2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "albummanager_p.h" 0018 0019 // Qt includes 0020 0021 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0022 #include <QTextCodec> 0023 #else 0024 #include <QStringConverter> 0025 #endif 0026 0027 // KDE includes 0028 0029 #include <kconfiggroup.h> 0030 #include <ksharedconfig.h> 0031 0032 namespace Digikam 0033 { 0034 0035 bool AlbumManager::setDatabase(const DbEngineParameters& params, bool priority, const QString& suggestedAlbumRoot, bool ignoreDisappearedLocations) 0036 { 0037 // This is to ensure that the setup does not overrule the command line. 0038 // TODO: there is a bug that setup is showing something different here. 0039 0040 if (priority) 0041 { 0042 d->hasPriorizedDbPath = true; 0043 } 0044 else if (d->hasPriorizedDbPath) 0045 { 0046 // ignore change without priority 0047 0048 return true; 0049 } 0050 0051 d->changed = true; 0052 0053 QApplication::setOverrideCursor(Qt::WaitCursor); 0054 0055 DatabaseServerStarter::instance()->stopServerManagerProcess(); 0056 0057 // Shutdown possibly running collection scans. 0058 // Must call restartCollectionScan further down. 0059 0060 ScanController::instance()->cancelAllAndSuspendCollectionScan(); 0061 0062 disconnect(CollectionManager::instance(), nullptr, this, nullptr); 0063 CollectionManager::instance()->setWatchDisabled(); 0064 0065 if (CoreDbAccess::databaseWatch()) 0066 { 0067 disconnect(CoreDbAccess::databaseWatch(), nullptr, this, nullptr); 0068 } 0069 0070 ItemAttributesWatch::shutDown(); 0071 ItemAttributesWatch::cleanUp(); 0072 d->albumWatch->clear(); 0073 0074 cleanUp(); 0075 0076 d->currentAlbums.clear(); 0077 Q_EMIT signalAlbumCurrentChanged(d->currentAlbums); 0078 Q_EMIT signalAlbumsCleared(); 0079 0080 d->albumPathHash.clear(); 0081 d->allAlbumsIdHash.clear(); 0082 d->albumRootAlbumHash.clear(); 0083 0084 // deletes all child albums as well 0085 0086 delete d->rootPAlbum; 0087 delete d->rootTAlbum; 0088 delete d->rootDAlbum; 0089 delete d->rootSAlbum; 0090 0091 d->rootPAlbum = nullptr; 0092 d->rootTAlbum = nullptr; 0093 d->rootDAlbum = nullptr; 0094 d->rootSAlbum = nullptr; 0095 0096 // -- Database initialization ------------------------------------------------- 0097 0098 // ensure, embedded database is loaded 0099 0100 qCDebug(DIGIKAM_GENERAL_LOG) << params; 0101 0102 QString databaseError; 0103 0104 ApplicationSettings* const settings = ApplicationSettings::instance(); 0105 0106 if (params.internalServer && suggestedAlbumRoot.isEmpty()) 0107 { 0108 if (!QFileInfo::exists(params.internalServerPath())) 0109 { 0110 databaseError = i18n("The MySQL database directory was not found."); 0111 } 0112 else if ( 0113 (!QFileInfo::exists(params.internalServerMysqlUpgradeCmd) && 0114 QStandardPaths::findExecutable(params.internalServerMysqlUpgradeCmd).isEmpty()) || 0115 (!QFileInfo::exists(params.internalServerMysqlServerCmd) && 0116 QStandardPaths::findExecutable(params.internalServerMysqlServerCmd).isEmpty()) || 0117 (!QFileInfo::exists(params.internalServerMysqlAdminCmd) && 0118 QStandardPaths::findExecutable(params.internalServerMysqlAdminCmd).isEmpty()) 0119 ) 0120 { 0121 databaseError = i18n("The MySQL binary tools was not found."); 0122 } 0123 } 0124 else if (params.isSQLite() && suggestedAlbumRoot.isEmpty() && !settings->getDatabaseDirSetAtCmd()) 0125 { 0126 if (!QFileInfo::exists(params.databaseNameCore)) 0127 { 0128 databaseError = i18n("The SQLite core database was not found."); 0129 } 0130 } 0131 0132 if (!databaseError.isEmpty()) 0133 { 0134 QString configPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, 0135 QLatin1String("digikamrc")); 0136 0137 databaseError += i18n("<p>If you want to start with a new configuration and " 0138 "with a first run wizard, delete the file:<br>%1</p>", 0139 QDir::toNativeSeparators(configPath)); 0140 0141 return showDatabaseSetupPage(databaseError, priority, suggestedAlbumRoot); 0142 } 0143 0144 if (params.internalServer) 0145 { 0146 DatabaseServerError result = DatabaseServerStarter::instance()->startServerManagerProcess(params); 0147 0148 if (result.getErrorType() != DatabaseServerError::NoErrors) 0149 { 0150 databaseError = i18n("An error occurred during the internal server start." 0151 "<p>Details:\n%1</p>", result.getErrorText()); 0152 0153 return showDatabaseSetupPage(databaseError, priority, suggestedAlbumRoot); 0154 } 0155 } 0156 0157 CoreDbAccess::setParameters(params, CoreDbAccess::MainApplication); 0158 0159 DbEngineGuiErrorHandler* const handler = new DbEngineGuiErrorHandler(CoreDbAccess::parameters()); 0160 CoreDbAccess::initDbEngineErrorHandler(handler); 0161 0162 QApplication::restoreOverrideCursor(); 0163 0164 if (!handler->checkDatabaseConnection()) 0165 { 0166 databaseError = i18n("Failed to open the database."); 0167 0168 if (!showDatabaseSetupPage(databaseError, priority, suggestedAlbumRoot)) 0169 { 0170 if (params.isSQLite()) 0171 { 0172 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), 0173 i18n("<p>digiKam will attempt to start now, " 0174 "but it will <b>not</b> be functional.</p>")); 0175 0176 CoreDbAccess::setParameters(DbEngineParameters(), CoreDbAccess::DatabaseSlave); 0177 0178 return true; 0179 } 0180 0181 return false; 0182 } 0183 0184 return true; 0185 } 0186 0187 QApplication::setOverrideCursor(Qt::WaitCursor); 0188 0189 d->albumWatch->setDbEngineParameters(params); 0190 0191 ScanController::Advice advice = ScanController::instance()->databaseInitialization(); 0192 0193 QApplication::restoreOverrideCursor(); 0194 0195 switch (advice) 0196 { 0197 case ScanController::Success: 0198 { 0199 break; 0200 } 0201 0202 case ScanController::ContinueWithoutDatabase: 0203 { 0204 QString errorMsg = CoreDbAccess().lastError(); 0205 0206 if (errorMsg.isEmpty()) 0207 { 0208 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), 0209 i18n("<p>Failed to open the database.</p>" 0210 "<p>You cannot use digiKam without a working database. " 0211 "digiKam will attempt to start now, but it will <b>not</b> be functional. " 0212 "Please check the database settings in the <b>configuration menu</b>.</p>" 0213 )); 0214 } 0215 else 0216 { 0217 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), 0218 i18n("<p>Failed to open the database. Error message from database:</p>" 0219 "<p><b>%1</b></p>" 0220 "<p>You cannot use digiKam without a working database. " 0221 "digiKam will attempt to start now, but it will <b>not</b> be functional. " 0222 "Please check the database settings in the <b>configuration menu</b>.</p>", 0223 errorMsg)); 0224 } 0225 0226 return true; 0227 } 0228 0229 case ScanController::AbortImmediately: 0230 { 0231 databaseError = i18n("Failed to initialize the database."); 0232 0233 return showDatabaseSetupPage(databaseError, priority, suggestedAlbumRoot); 0234 } 0235 } 0236 0237 // -- Locale Checking --------------------------------------------------------- 0238 0239 QString currLocale = CoreDbAccess().db()->getDatabaseEncoding(); 0240 QString dbLocale = CoreDbAccess().db()->getSetting(QLatin1String("Locale")); 0241 0242 if (dbLocale.isEmpty()) 0243 { 0244 qCDebug(DIGIKAM_GENERAL_LOG) << "No locale found in database"; 0245 CoreDbAccess().db()->setSetting(QLatin1String("Locale"), currLocale); 0246 } 0247 else if (dbLocale != currLocale) 0248 { 0249 // TODO it would be better to replace all yes/no confirmation dialogs with ones that has custom 0250 // buttons that denote the actions directly, i.e.: ["Ignore and Continue"] ["Adjust locale"] 0251 0252 int result = QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(), 0253 i18n("Your database character set has changed since this " 0254 "album was last opened.\n" 0255 "Old character set: %1, new character set: %2\n" 0256 "If you have recently changed your database character set, " 0257 "you need not be concerned.\n" 0258 "Please note that if you switched to a database character set " 0259 "that does not support some of the filenames in your collection, " 0260 "these files may no longer be found in the collection. " 0261 "If you are sure that you want to " 0262 "continue, click 'Yes'. " 0263 "Otherwise, click 'No' and correct your " 0264 "database character set setting before restarting digiKam.", 0265 dbLocale, currLocale), 0266 QMessageBox::Yes | QMessageBox::No); 0267 0268 if (result != QMessageBox::Yes) 0269 { 0270 return false; 0271 } 0272 0273 CoreDbAccess().db()->setSetting(QLatin1String("Locale"), currLocale); 0274 } 0275 0276 // -- UUID Checking --------------------------------------------------------- 0277 0278 QList<CollectionLocation> disappearedLocations = CollectionManager::instance()->checkHardWiredLocations(); 0279 0280 Q_FOREACH (const CollectionLocation& loc, disappearedLocations) 0281 { 0282 QString locDescription; 0283 QStringList candidateIds, candidateDescriptions; 0284 CollectionManager::instance()->migrationCandidates(loc, &locDescription, &candidateIds, &candidateDescriptions); 0285 qCDebug(DIGIKAM_GENERAL_LOG) << "Migration candidates for" << locDescription << ":" << candidateIds << candidateDescriptions; 0286 0287 QDialog* const dialog = new QDialog; 0288 QWidget* const widget = new QWidget(dialog); 0289 QGridLayout* const mainLayout = new QGridLayout; 0290 mainLayout->setColumnStretch(1, 1); 0291 0292 QLabel* const deviceIconLabel = new QLabel; 0293 deviceIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("drive-harddisk")).pixmap(64)); 0294 mainLayout->addWidget(deviceIconLabel, 0, 0); 0295 0296 QLabel* const mainLabel = new QLabel(i18n("<p>The collection </p><p><b>%1</b><br/>(%2)</p><p> is currently " 0297 "not found on your system.<br/> Please choose the most " 0298 "appropriate option to handle this situation:</p>", 0299 loc.label(), QDir::toNativeSeparators(locDescription))); 0300 mainLabel->setWordWrap(true); 0301 mainLayout->addWidget(mainLabel, 0, 1); 0302 0303 QGroupBox* const groupBox = new QGroupBox; 0304 mainLayout->addWidget(groupBox, 1, 0, 1, 2); 0305 0306 QGridLayout* const layout = new QGridLayout; 0307 layout->setColumnStretch(1, 1); 0308 0309 QRadioButton* migrateButton = nullptr; 0310 QComboBox* migrateChoices = nullptr; 0311 0312 if (!candidateIds.isEmpty()) 0313 { 0314 migrateButton = new QRadioButton; 0315 QLabel* const migrateLabel = new QLabel(i18n("<p>The collection is still available, but the identifier changed.<br/>" 0316 "This can be caused by restoring a backup, changing the partition layout " 0317 "or the file system settings.<br/>" 0318 "The collection is now located at this place:</p>")); 0319 migrateLabel->setWordWrap(true); 0320 0321 migrateChoices = new QComboBox; 0322 0323 for (int i = 0 ; i < candidateIds.size() ; ++i) 0324 { 0325 migrateChoices->addItem(QDir::toNativeSeparators(candidateDescriptions.at(i)), candidateIds.at(i)); 0326 } 0327 0328 layout->addWidget(migrateButton, 0, 0, Qt::AlignTop); 0329 layout->addWidget(migrateLabel, 0, 1); 0330 layout->addWidget(migrateChoices, 1, 1); 0331 } 0332 0333 QRadioButton* const isRemovableButton = new QRadioButton; 0334 QLabel* const isRemovableLabel = new QLabel(i18n("The collection is located on a storage device which is not " 0335 "always attached. Mark the collection as a removable collection.")); 0336 isRemovableLabel->setWordWrap(true); 0337 layout->addWidget(isRemovableButton, 2, 0, Qt::AlignTop); 0338 layout->addWidget(isRemovableLabel, 2, 1); 0339 0340 QRadioButton* const solveManuallyButton = new QRadioButton; 0341 QLabel* const solveManuallyLabel = new QLabel(i18n("Take no action now. I would like to solve the problem " 0342 "later using the setup dialog")); 0343 solveManuallyLabel->setWordWrap(true); 0344 layout->addWidget(solveManuallyButton, 3, 0, Qt::AlignTop); 0345 layout->addWidget(solveManuallyLabel, 3, 1); 0346 0347 groupBox->setLayout(layout); 0348 widget->setLayout(mainLayout); 0349 0350 QVBoxLayout* const vbx = new QVBoxLayout(dialog); 0351 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok, dialog); 0352 vbx->addWidget(widget); 0353 vbx->addWidget(buttons); 0354 dialog->setLayout(vbx); 0355 dialog->setWindowTitle(i18nc("@title:window", "Collection not Found")); 0356 0357 connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), 0358 dialog, SLOT(accept())); 0359 0360 // Default option: If there is only one candidate, default to migration. 0361 // Otherwise default to do nothing now. 0362 0363 if (migrateButton && (candidateIds.size() == 1)) 0364 { 0365 migrateButton->setChecked(true); 0366 } 0367 else 0368 { 0369 solveManuallyButton->setChecked(true); 0370 } 0371 0372 if (!ignoreDisappearedLocations && dialog->exec()) 0373 { 0374 if (migrateButton && migrateButton->isChecked()) 0375 { 0376 CollectionManager::instance()->migrateToVolume(loc, migrateChoices->itemData(migrateChoices->currentIndex()).toString()); 0377 } 0378 else if (isRemovableButton->isChecked()) 0379 { 0380 CollectionManager::instance()->changeType(loc, CollectionLocation::VolumeRemovable); 0381 } 0382 } 0383 0384 delete dialog; 0385 } 0386 0387 // -- --------------------------------------------------------- 0388 0389 // check that we have one album root 0390 0391 if (CollectionManager::instance()->allLocations().isEmpty()) 0392 { 0393 if (suggestedAlbumRoot.isEmpty()) 0394 { 0395 Setup::execSinglePage(Setup::CollectionsPage); 0396 } 0397 else 0398 { 0399 QUrl albumRoot(QUrl::fromLocalFile(suggestedAlbumRoot)); 0400 CollectionManager::instance()->addLocation(albumRoot, albumRoot.fileName()); 0401 0402 // Not needed? See bug #188959 0403 /* 0404 ScanController::instance()->completeCollectionScan(); 0405 */ 0406 } 0407 } 0408 0409 // -- --------------------------------------------------------- 0410 0411 QApplication::setOverrideCursor(Qt::WaitCursor); 0412 0413 ThumbnailLoadThread::initializeThumbnailDatabase(CoreDbAccess::parameters().thumbnailParameters(), 0414 new ThumbsDbInfoProvider()); 0415 0416 DbEngineGuiErrorHandler* const thumbnailsDBHandler = new DbEngineGuiErrorHandler(ThumbsDbAccess::parameters()); 0417 ThumbsDbAccess::initDbEngineErrorHandler(thumbnailsDBHandler); 0418 0419 // Activate the similarity database. 0420 0421 SimilarityDbAccess::setParameters(params.similarityParameters()); 0422 0423 DbEngineGuiErrorHandler* const similarityHandler = new DbEngineGuiErrorHandler(SimilarityDbAccess::parameters()); 0424 SimilarityDbAccess::initDbEngineErrorHandler(similarityHandler); 0425 0426 if (SimilarityDbAccess::checkReadyForUse(nullptr)) 0427 { 0428 qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database ready for use"; 0429 } 0430 else 0431 { 0432 qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Failed to initialize similarity database"; 0433 } 0434 0435 QApplication::restoreOverrideCursor(); 0436 0437 // still suspended from above 0438 0439 ScanController::instance()->restartCollectionScan(); 0440 0441 return true; 0442 } 0443 0444 void AlbumManager::checkDatabaseDirsAfterFirstRun(const QString& dbPath, const QString& albumPath) 0445 { 0446 // for bug #193522 0447 0448 QDir newDir(dbPath); 0449 QDir albumDir(albumPath); 0450 DbEngineParameters newParams = DbEngineParameters::parametersForSQLiteDefaultFile(newDir.path()); 0451 QFileInfo digikam4DB(newParams.SQLiteDatabaseFile()); 0452 0453 if (!digikam4DB.exists()) 0454 { 0455 QFileInfo digikam3DB(newDir, QLatin1String("digikam3.db")); 0456 QFileInfo digikamVeryOldDB(newDir, QLatin1String("digikam.db")); 0457 0458 if (digikam3DB.exists() || digikamVeryOldDB.exists()) 0459 { 0460 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning, 0461 i18nc("@title:window", "Database Folder"), 0462 i18n("<p>You have chosen the folder \"%1\" as the place to store the database. " 0463 "A database file from an older version of digiKam is found in this folder.</p> " 0464 "<p>Would you like to upgrade the old database file - confirming " 0465 "that this database file was indeed created for the pictures located in the folder \"%2\" - " 0466 "or ignore the old file and start with a new database?</p> ", 0467 QDir::toNativeSeparators(newDir.path()), 0468 QDir::toNativeSeparators(albumDir.path())), 0469 QMessageBox::Yes | QMessageBox::No, 0470 qApp->activeWindow()); 0471 0472 msgBox->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Upgrade Database")); 0473 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); 0474 msgBox->button(QMessageBox::No)->setText(i18nc("@action:button", "Create New Database")); 0475 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new"))); 0476 msgBox->setDefaultButton(QMessageBox::Yes); 0477 0478 int result = msgBox->exec(); 0479 0480 if (result == QMessageBox::Yes) 0481 { 0482 // CoreDbSchemaUpdater expects Album Path to point to the album root of the 0.9 db file. 0483 // Restore this situation. 0484 0485 KSharedConfigPtr config = KSharedConfig::openConfig(); 0486 KConfigGroup group = config->group(QLatin1String("Album Settings")); 0487 group.writeEntry("Album Path", albumDir.path()); 0488 group.sync(); 0489 } 0490 else if (result == QMessageBox::No) 0491 { 0492 moveToBackup(digikam3DB); 0493 moveToBackup(digikamVeryOldDB); 0494 } 0495 0496 delete msgBox; 0497 } 0498 } 0499 } 0500 0501 void AlbumManager::changeDatabase(const DbEngineParameters& newParams) 0502 { 0503 ScanController::instance()->shutDown(); 0504 0505 // if there is no file at the new place, copy old one 0506 0507 DbEngineParameters params = CoreDbAccess::parameters(); 0508 0509 // New database type SQLITE 0510 0511 if (newParams.isSQLite()) 0512 { 0513 bool walModeChanged = ((params.walMode != newParams.walMode) && 0514 (params.getCoreDatabaseNameOrDir() == newParams.getCoreDatabaseNameOrDir())); 0515 0516 QDir newDir(newParams.getCoreDatabaseNameOrDir()); 0517 QFileInfo newFile(newDir, QLatin1String("digikam4.db")); 0518 0519 if (!newFile.exists() && !walModeChanged) 0520 { 0521 QFileInfo digikam3DB(newDir, QLatin1String("digikam3.db")); 0522 QFileInfo digikamVeryOldDB(newDir, QLatin1String("digikam.db")); 0523 0524 if (digikam3DB.exists() || digikamVeryOldDB.exists()) 0525 { 0526 int result = -1; 0527 0528 if (params.isSQLite()) 0529 { 0530 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning, 0531 i18nc("@title:window", "New Database Folder"), 0532 i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. " 0533 "A database file from an older version of digiKam is found in this folder.</p> " 0534 "<p>Would you like to upgrade the old database file, start with a new database, " 0535 "or copy the current database to this location and continue using it?</p> ", 0536 QDir::toNativeSeparators(newDir.path())), 0537 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, 0538 qApp->activeWindow()); 0539 0540 msgBox->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Upgrade Database")); 0541 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); 0542 msgBox->button(QMessageBox::No)->setText(i18nc("@action:button", "Create New Database")); 0543 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new"))); 0544 msgBox->button(QMessageBox::Cancel)->setText(i18nc("@action:button", "Copy Current Database")); 0545 msgBox->button(QMessageBox::Cancel)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy"))); 0546 msgBox->setDefaultButton(QMessageBox::Yes); 0547 0548 result = msgBox->exec(); 0549 delete msgBox; 0550 } 0551 else 0552 { 0553 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning, 0554 i18nc("@title:window", "New Database Folder"), 0555 i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. " 0556 "A database file from an older version of digiKam is found in this folder.</p> " 0557 "<p>Would you like to upgrade the old database file or start with a new database?</p>", 0558 QDir::toNativeSeparators(newDir.path())), 0559 QMessageBox::Yes | QMessageBox::No, 0560 qApp->activeWindow()); 0561 0562 msgBox->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Upgrade Database")); 0563 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); 0564 msgBox->button(QMessageBox::No)->setText(i18nc("@action:button", "Create New Database")); 0565 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new"))); 0566 msgBox->setDefaultButton(QMessageBox::Yes); 0567 0568 result = msgBox->exec(); 0569 delete msgBox; 0570 } 0571 0572 if (result == QMessageBox::Yes) 0573 { 0574 // CoreDbSchemaUpdater expects Album Path to point to the album root of the 0.9 db file. 0575 // Restore this situation. 0576 0577 KSharedConfigPtr config = KSharedConfig::openConfig(); 0578 KConfigGroup group = config->group(QLatin1String("Album Settings")); 0579 group.writeEntry(QLatin1String("Album Path"), newDir.path()); 0580 group.sync(); 0581 } 0582 else if (result == QMessageBox::No) 0583 { 0584 moveToBackup(digikam3DB); 0585 moveToBackup(digikamVeryOldDB); 0586 } 0587 else if (result == QMessageBox::Cancel) 0588 { 0589 QFileInfo oldFile(params.SQLiteDatabaseFile()); 0590 copyToNewLocation(oldFile, newFile, i18n("Failed to copy the old database file (\"%1\") " 0591 "to its new location (\"%2\"). " 0592 "Trying to upgrade old databases.", 0593 QDir::toNativeSeparators(oldFile.filePath()), 0594 QDir::toNativeSeparators(newFile.filePath()))); 0595 } 0596 } 0597 else 0598 { 0599 int result = QMessageBox::Yes; 0600 0601 if (params.isSQLite()) 0602 { 0603 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning, 0604 i18nc("@title:window", "New Database Folder"), 0605 i18n("<p>You have chosen the folder \"%1\" as the new place to store the database.</p>" 0606 "<p>Would you like to copy the current database to this location " 0607 "and continue using it, or start with a new database?</p> ", 0608 QDir::toNativeSeparators(newDir.path())), 0609 QMessageBox::Yes | QMessageBox::No, 0610 qApp->activeWindow()); 0611 0612 msgBox->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Create New Database")); 0613 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("document-new"))); 0614 msgBox->button(QMessageBox::No)->setText(i18nc("@action:button", "Copy Current Database")); 0615 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy"))); 0616 msgBox->setDefaultButton(QMessageBox::Yes); 0617 0618 result = msgBox->exec(); 0619 delete msgBox; 0620 } 0621 0622 if (result == QMessageBox::No) 0623 { 0624 QFileInfo oldFile(params.SQLiteDatabaseFile()); 0625 copyToNewLocation(oldFile, newFile); 0626 } 0627 } 0628 } 0629 else if (!walModeChanged) 0630 { 0631 int result = QMessageBox::No; 0632 0633 if (params.isSQLite()) 0634 { 0635 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning, 0636 i18nc("@title:window", "New Database Folder"), 0637 i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. " 0638 "There is already a database file in this location.</p> " 0639 "<p>Would you like to use this existing file as the new database, or remove it " 0640 "and copy the current database to this place?</p> ", 0641 QDir::toNativeSeparators(newDir.path())), 0642 QMessageBox::Yes | QMessageBox::No, 0643 qApp->activeWindow()); 0644 0645 msgBox->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Copy Current Database")); 0646 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy"))); 0647 msgBox->button(QMessageBox::No)->setText(i18nc("@action:button", "Use Existing File")); 0648 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-open"))); 0649 msgBox->setDefaultButton(QMessageBox::Yes); 0650 0651 result = msgBox->exec(); 0652 delete msgBox; 0653 } 0654 0655 if (result == QMessageBox::Yes) 0656 { 0657 // first backup 0658 0659 if (moveToBackup(newFile)) 0660 { 0661 QFileInfo oldFile(params.SQLiteDatabaseFile()); 0662 0663 // then copy 0664 0665 copyToNewLocation(oldFile, newFile); 0666 } 0667 } 0668 } 0669 } 0670 0671 ScanController::instance()->restart(); 0672 0673 if (setDatabase(newParams, false)) 0674 { 0675 QApplication::setOverrideCursor(Qt::WaitCursor); 0676 startScan(); 0677 QApplication::restoreOverrideCursor(); 0678 ScanController::instance()->completeCollectionScan(); 0679 } 0680 } 0681 0682 bool AlbumManager::databaseEqual(const DbEngineParameters& parameters) const 0683 { 0684 DbEngineParameters params = CoreDbAccess::parameters(); 0685 0686 return (params == parameters); 0687 } 0688 0689 bool AlbumManager::moveToBackup(const QFileInfo& info) 0690 { 0691 if (info.exists()) 0692 { 0693 QFileInfo backup(info.dir(), info.fileName() + 0694 QLatin1String("-backup-") + 0695 QDateTime::currentDateTime().toString(Qt::ISODate)); 0696 0697 bool ret = QDir().rename(info.filePath(), backup.filePath()); 0698 0699 if (!ret) 0700 { 0701 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), 0702 i18n("Failed to backup the existing database file (\"%1\"). " 0703 "Refusing to replace file without backup, using the existing file.", 0704 QDir::toNativeSeparators(info.filePath()))); 0705 return false; 0706 } 0707 } 0708 0709 return true; 0710 } 0711 0712 bool AlbumManager::copyToNewLocation(const QFileInfo& oldFile, 0713 const QFileInfo& newFile, 0714 const QString& otherMessage) 0715 { 0716 QString message = otherMessage; 0717 0718 if (message.isNull()) 0719 { 0720 message = i18n("Failed to copy the old database file (\"%1\") " 0721 "to its new location (\"%2\"). " 0722 "Starting with an empty database.", 0723 QDir::toNativeSeparators(oldFile.filePath()), 0724 QDir::toNativeSeparators(newFile.filePath())); 0725 } 0726 0727 bool ret = QFile::copy(oldFile.filePath(), newFile.filePath()); 0728 0729 if (!ret) 0730 { 0731 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), message); 0732 return false; 0733 } 0734 0735 return true; 0736 } 0737 0738 bool AlbumManager::showDatabaseSetupPage(const QString& error, bool priority, const QString& suggestedAlbumRoot) 0739 { 0740 QApplication::restoreOverrideCursor(); 0741 0742 QString errorMsg = error + i18n("<p><b>Please check the database settings in this dialog.</b></p>"); 0743 0744 // We cannot use Setup::execSinglePage() as this already requires a core database. 0745 0746 QPointer<QDialog> setup = new QDialog(qApp->activeWindow()); 0747 QVBoxLayout* const layout = new QVBoxLayout(setup); 0748 QLabel* const errorLabel = new QLabel(errorMsg, setup); 0749 errorLabel->setWordWrap(true); 0750 errorLabel->setTextFormat(Qt::RichText); 0751 errorLabel->setAlignment(Qt::AlignCenter); 0752 errorLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); 0753 errorLabel->setStyleSheet(QLatin1String("QLabel { background-color: #FFDDDD; color: black; }")); 0754 DatabaseSettingsWidget* const dbsettings = new DatabaseSettingsWidget(setup); 0755 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | 0756 QDialogButtonBox::Reset | 0757 QDialogButtonBox::Cancel, setup); 0758 buttons->button(QDialogButtonBox::Reset)->setText(i18nc("@action:button", "New database")); 0759 buttons->button(QDialogButtonBox::Ok)->setDefault(true); 0760 0761 layout->addWidget(errorLabel); 0762 layout->addWidget(dbsettings); 0763 layout->addStretch(10); 0764 layout->addWidget(buttons); 0765 0766 bool newDatabase = false; 0767 0768 connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), 0769 setup, SLOT(accept())); 0770 0771 connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), 0772 setup, SLOT(reject())); 0773 0774 connect(buttons->button(QDialogButtonBox::Reset), &QPushButton::clicked, 0775 this, [&]() 0776 { 0777 newDatabase = true; 0778 setup->accept(); 0779 } 0780 ); 0781 0782 ApplicationSettings* const settings = ApplicationSettings::instance(); 0783 dbsettings->setParametersFromSettings(settings); 0784 0785 if (setup->exec() != QDialog::Accepted) 0786 { 0787 delete setup; 0788 0789 return false; 0790 } 0791 0792 DbEngineParameters dbParams = dbsettings->getDbEngineParameters(); 0793 settings->setDbEngineParameters(dbParams); 0794 settings->saveSettings(); 0795 0796 delete setup; 0797 0798 if (newDatabase) 0799 { 0800 if (dbParams.internalServer) 0801 { 0802 DatabaseServerError result = DatabaseServerStarter::instance()->startServerManagerProcess(dbParams); 0803 0804 if (result.getErrorType() != DatabaseServerError::NoErrors) 0805 { 0806 return false; 0807 } 0808 } 0809 0810 CoreDbAccess::setParameters(dbParams); 0811 0812 if (!CoreDbAccess::checkReadyForUse()) 0813 { 0814 return false; 0815 } 0816 } 0817 0818 return (setDatabase(dbParams, priority, suggestedAlbumRoot)); 0819 } 0820 0821 } // namespace Digikam