"Fossies" - the Fresh Open Source Software Archive

Member "digikam-6.3.0/core/libs/album/manager/albummanager_database.cpp" (4 Sep 2019, 30236 Bytes) of package /linux/misc/digikam-6.3.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "albummanager_database.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.2.0_vs_6.3.0.

    1 /* ============================================================
    2  *
    3  * This file is a part of digiKam project
    4  * https://www.digikam.org
    5  *
    6  * Date        : 2004-06-15
    7  * Description : Albums manager interface - Database helpers.
    8  *
    9  * Copyright (C) 2006-2019 by Gilles Caulier <caulier dot gilles at gmail dot com>
   10  * Copyright (C) 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
   11  * Copyright (C) 2015      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
   12  *
   13  * This program is free software; you can redistribute it
   14  * and/or modify it under the terms of the GNU General
   15  * Public License as published by the Free Software Foundation;
   16  * either version 2, or (at your option)
   17  * any later version.
   18  *
   19  * This program is distributed in the hope that it will be useful,
   20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22  * GNU General Public License for more details.
   23  *
   24  * ============================================================ */
   25 
   26 #include "albummanager_p.h"
   27 
   28 // KDE includes
   29 
   30 #include <ksharedconfig.h>
   31 
   32 namespace Digikam
   33 {
   34 
   35 bool AlbumManager::setDatabase(const DbEngineParameters& params, bool priority, const QString& suggestedAlbumRoot)
   36 {
   37     // This is to ensure that the setup does not overrule the command line.
   38     // TODO: there is a bug that setup is showing something different here.
   39     if (priority)
   40     {
   41         d->hasPriorizedDbPath = true;
   42     }
   43     else if (d->hasPriorizedDbPath)
   44     {
   45         // ignore change without priority
   46         return true;
   47     }
   48 
   49     // shutdown possibly running collection scans. Must call resumeCollectionScan further down.
   50     ScanController::instance()->cancelAllAndSuspendCollectionScan();
   51     QApplication::setOverrideCursor(Qt::WaitCursor);
   52 
   53     d->changed = true;
   54 
   55     disconnect(CollectionManager::instance(), nullptr, this, nullptr);
   56     CollectionManager::instance()->setWatchDisabled();
   57 
   58     if (CoreDbAccess::databaseWatch())
   59     {
   60         disconnect(CoreDbAccess::databaseWatch(), nullptr, this, nullptr);
   61     }
   62 
   63     DatabaseServerStarter::instance()->stopServerManagerProcess();
   64 
   65     d->albumWatch->clear();
   66 
   67     cleanUp();
   68 
   69     d->currentAlbums.clear();
   70     emit signalAlbumCurrentChanged(d->currentAlbums);
   71     emit signalAlbumsCleared();
   72 
   73     d->albumPathHash.clear();
   74     d->allAlbumsIdHash.clear();
   75     d->albumRootAlbumHash.clear();
   76 
   77     // deletes all child albums as well
   78     delete d->rootPAlbum;
   79     delete d->rootTAlbum;
   80     delete d->rootDAlbum;
   81     delete d->rootSAlbum;
   82 
   83     d->rootPAlbum = nullptr;
   84     d->rootTAlbum = nullptr;
   85     d->rootDAlbum = nullptr;
   86     d->rootSAlbum = nullptr;
   87 
   88     // -- Database initialization -------------------------------------------------
   89 
   90     // ensure, embedded database is loaded
   91     qCDebug(DIGIKAM_GENERAL_LOG) << params;
   92 
   93     // workaround for the problem mariaDB >= 10.2 and QTBUG-63108
   94     if (params.isMySQL())
   95     {
   96         addFakeConnection();
   97     }
   98 
   99     if (params.internalServer)
  100     {
  101         DatabaseServerError result = DatabaseServerStarter::instance()->startServerManagerProcess(params);
  102 
  103         if (result.getErrorType() != DatabaseServerError::NoErrors)
  104         {
  105             QWidget* const parent = QWidget::find(0);
  106             QString message       = i18n("<p><b>An error occurred during the internal server start.</b></p>"
  107                                          "Details:\n %1", result.getErrorText());
  108             QApplication::changeOverrideCursor(Qt::ArrowCursor);
  109             QMessageBox::critical(parent, qApp->applicationName(), message);
  110             QApplication::changeOverrideCursor(Qt::WaitCursor);
  111         }
  112     }
  113 
  114     CoreDbAccess::setParameters(params, CoreDbAccess::MainApplication);
  115 
  116     DbEngineGuiErrorHandler* const handler = new DbEngineGuiErrorHandler(CoreDbAccess::parameters());
  117     CoreDbAccess::initDbEngineErrorHandler(handler);
  118 
  119     if (!handler->checkDatabaseConnection())
  120     {
  121         QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(),
  122                               i18n("<p>Failed to open the database. "
  123                                    "</p><p>You cannot use digiKam without a working database. "
  124                                    "digiKam will attempt to start now, but it will <b>not</b> be functional. "
  125                                    "Please check the database settings in the <b>configuration menu</b>.</p>"
  126                                   ));
  127 
  128         CoreDbAccess::setParameters(DbEngineParameters(), CoreDbAccess::DatabaseSlave);
  129         QApplication::restoreOverrideCursor();
  130         return true;
  131     }
  132 
  133     d->albumWatch->setDbEngineParameters(params);
  134 
  135     // still suspended from above
  136     ScanController::instance()->resumeCollectionScan();
  137 
  138     ScanController::Advice advice = ScanController::instance()->databaseInitialization();
  139 
  140     QApplication::restoreOverrideCursor();
  141 
  142     switch (advice)
  143     {
  144         case ScanController::Success:
  145             break;
  146 
  147         case ScanController::ContinueWithoutDatabase:
  148         {
  149             QString errorMsg = CoreDbAccess().lastError();
  150 
  151             if (errorMsg.isEmpty())
  152             {
  153                 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(),
  154                                       i18n("<p>Failed to open the database. "
  155                                            "</p><p>You cannot use digiKam without a working database. "
  156                                            "digiKam will attempt to start now, but it will <b>not</b> be functional. "
  157                                            "Please check the database settings in the <b>configuration menu</b>.</p>"
  158                                           ));
  159             }
  160             else
  161             {
  162                 QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(),
  163                                       i18n("<p>Failed to open the database. Error message from database:</p>"
  164                                            "<p><b>%1</b></p>"
  165                                            "<p>You cannot use digiKam without a working database. "
  166                                            "digiKam will attempt to start now, but it will <b>not</b> be functional. "
  167                                            "Please check the database settings in the <b>configuration menu</b>.</p>",
  168                                            errorMsg));
  169             }
  170 
  171             return true;
  172         }
  173 
  174         case ScanController::AbortImmediately:
  175             return false;
  176     }
  177 
  178     // -- Locale Checking ---------------------------------------------------------
  179 
  180     QString currLocale = QString::fromUtf8((QTextCodec::codecForLocale()->name()));
  181     QString dbLocale   = CoreDbAccess().db()->getSetting(QLatin1String("Locale"));
  182 
  183     // guilty until proven innocent
  184     bool localeChanged = true;
  185 
  186     if (dbLocale.isNull())
  187     {
  188         qCDebug(DIGIKAM_GENERAL_LOG) << "No locale found in database";
  189 
  190         // Copy an existing locale from the settings file (used < 0.8)
  191         // to the database.
  192         KSharedConfig::Ptr config = KSharedConfig::openConfig();
  193         KConfigGroup group = config->group(QLatin1String("General Settings"));
  194 
  195         if (group.hasKey(QLatin1String("Locale")))
  196         {
  197             qCDebug(DIGIKAM_GENERAL_LOG) << "Locale found in configfile";
  198             dbLocale = group.readEntry(QLatin1String("Locale"), QString());
  199 
  200             // this hack is necessary, as we used to store the entire
  201             // locale info LC_ALL (for eg: en_US.UTF-8) earlier,
  202             // we now save only the encoding (UTF-8)
  203 
  204             QString oldConfigLocale = QString::fromUtf8(::setlocale(0, nullptr));
  205 
  206             if (oldConfigLocale == dbLocale)
  207             {
  208                 dbLocale = currLocale;
  209                 localeChanged = false;
  210                 CoreDbAccess().db()->setSetting(QLatin1String("Locale"), dbLocale);
  211             }
  212         }
  213         else
  214         {
  215             qCDebug(DIGIKAM_GENERAL_LOG) << "No locale found in config file";
  216             dbLocale = currLocale;
  217 
  218             localeChanged = false;
  219             CoreDbAccess().db()->setSetting(QLatin1String("Locale"), dbLocale);
  220         }
  221     }
  222     else
  223     {
  224         if (dbLocale == currLocale)
  225         {
  226             localeChanged = false;
  227         }
  228     }
  229 
  230     if (localeChanged)
  231     {
  232         // TODO it would be better to replace all yes/no confirmation dialogs with ones that has custom
  233         // buttons that denote the actions directly, i.e.:  ["Ignore and Continue"]  ["Adjust locale"]
  234 
  235         int result = QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(),
  236                                  i18n("Your locale has changed since this "
  237                                       "album was last opened.\n"
  238                                       "Old locale: %1, new locale: %2\n"
  239                                       "If you have recently changed your locale, you need not be concerned.\n"
  240                                       "Please note that if you switched to a locale "
  241                                       "that does not support some of the filenames in your collection, "
  242                                       "these files may no longer be found in the collection. "
  243                                       "If you are sure that you want to "
  244                                       "continue, click 'Yes'. "
  245                                       "Otherwise, click 'No' and correct your "
  246                                       "locale setting before restarting digiKam.",
  247                                       dbLocale, currLocale),
  248                                   QMessageBox::Yes | QMessageBox::No);
  249 
  250         if (result != QMessageBox::Yes)
  251         {
  252             return false;
  253         }
  254 
  255         CoreDbAccess().db()->setSetting(QLatin1String("Locale"), currLocale);
  256     }
  257 
  258     // -- UUID Checking ---------------------------------------------------------
  259 
  260     QList<CollectionLocation> disappearedLocations = CollectionManager::instance()->checkHardWiredLocations();
  261 
  262     foreach (const CollectionLocation& loc, disappearedLocations)
  263     {
  264         QString locDescription;
  265         QStringList candidateIds, candidateDescriptions;
  266         CollectionManager::instance()->migrationCandidates(loc, &locDescription, &candidateIds, &candidateDescriptions);
  267         qCDebug(DIGIKAM_GENERAL_LOG) << "Migration candidates for" << locDescription << ":" << candidateIds << candidateDescriptions;
  268 
  269         QDialog* const dialog         = new QDialog;
  270         QWidget* const widget         = new QWidget(dialog);
  271         QGridLayout* const mainLayout = new QGridLayout;
  272         mainLayout->setColumnStretch(1, 1);
  273 
  274         QLabel* const deviceIconLabel = new QLabel;
  275         deviceIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("drive-harddisk")).pixmap(64));
  276         mainLayout->addWidget(deviceIconLabel, 0, 0);
  277 
  278         QLabel* const mainLabel = new QLabel(i18n("<p>The collection </p><p><b>%1</b><br/>(%2)</p><p> is currently not found on your system.<br/> "
  279                                                   "Please choose the most appropriate option to handle this situation:</p>",
  280                                              loc.label(), QDir::toNativeSeparators(locDescription)));
  281         mainLabel->setWordWrap(true);
  282         mainLayout->addWidget(mainLabel, 0, 1);
  283 
  284         QGroupBox* const groupBox = new QGroupBox;
  285         mainLayout->addWidget(groupBox, 1, 0, 1, 2);
  286 
  287         QGridLayout* const layout = new QGridLayout;
  288         layout->setColumnStretch(1, 1);
  289 
  290         QRadioButton* migrateButton = nullptr;
  291         QComboBox* migrateChoices   = nullptr;
  292 
  293         if (!candidateIds.isEmpty())
  294         {
  295             migrateButton              = new QRadioButton;
  296             QLabel* const migrateLabel = new QLabel(i18n("<p>The collection is still available, but the identifier changed.<br/>"
  297                                                          "This can be caused by restoring a backup, changing the partition layout "
  298                                                          "or the file system settings.<br/>"
  299                                                          "The collection is now located at this place:</p>"));
  300             migrateLabel->setWordWrap(true);
  301 
  302             migrateChoices = new QComboBox;
  303 
  304             for (int i = 0 ; i < candidateIds.size() ; ++i)
  305             {
  306                 migrateChoices->addItem(QDir::toNativeSeparators(candidateDescriptions.at(i)), candidateIds.at(i));
  307             }
  308 
  309             layout->addWidget(migrateButton,  0, 0, Qt::AlignTop);
  310             layout->addWidget(migrateLabel,   0, 1);
  311             layout->addWidget(migrateChoices, 1, 1);
  312         }
  313 
  314         QRadioButton* const isRemovableButton = new QRadioButton;
  315         QLabel* const isRemovableLabel        = new QLabel(i18n("The collection is located on a storage device which is not always attached. "
  316                                                                 "Mark the collection as a removable collection."));
  317         isRemovableLabel->setWordWrap(true);
  318         layout->addWidget(isRemovableButton, 2, 0, Qt::AlignTop);
  319         layout->addWidget(isRemovableLabel,  2, 1);
  320 
  321         QRadioButton* const solveManuallyButton = new QRadioButton;
  322         QLabel* const solveManuallyLabel        = new QLabel(i18n("Take no action now. I would like to solve the problem "
  323                                                                   "later using the setup dialog"));
  324         solveManuallyLabel->setWordWrap(true);
  325         layout->addWidget(solveManuallyButton, 3, 0, Qt::AlignTop);
  326         layout->addWidget(solveManuallyLabel,  3, 1);
  327 
  328         groupBox->setLayout(layout);
  329         widget->setLayout(mainLayout);
  330 
  331         QVBoxLayout* const vbx          = new QVBoxLayout(dialog);
  332         QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok, dialog);
  333         vbx->addWidget(widget);
  334         vbx->addWidget(buttons);
  335         dialog->setLayout(vbx);
  336         dialog->setWindowTitle(i18n("Collection not found"));
  337 
  338         connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
  339                 dialog, SLOT(accept()));
  340 
  341         // Default option: If there is only one candidate, default to migration.
  342         // Otherwise default to do nothing now.
  343         if (migrateButton && candidateIds.size() == 1)
  344         {
  345             migrateButton->setChecked(true);
  346         }
  347         else
  348         {
  349             solveManuallyButton->setChecked(true);
  350         }
  351 
  352         if (dialog->exec())
  353         {
  354             if (migrateButton && migrateButton->isChecked())
  355             {
  356                 CollectionManager::instance()->migrateToVolume(loc, migrateChoices->itemData(migrateChoices->currentIndex()).toString());
  357             }
  358             else if (isRemovableButton->isChecked())
  359             {
  360                 CollectionManager::instance()->changeType(loc, CollectionLocation::TypeVolumeRemovable);
  361             }
  362         }
  363 
  364         delete dialog;
  365     }
  366 
  367     // -- ---------------------------------------------------------
  368 
  369     // check that we have one album root
  370     if (CollectionManager::instance()->allLocations().isEmpty())
  371     {
  372         if (suggestedAlbumRoot.isEmpty())
  373         {
  374             Setup::execSinglePage(Setup::CollectionsPage);
  375         }
  376         else
  377         {
  378             QUrl albumRoot(QUrl::fromLocalFile(suggestedAlbumRoot));
  379             CollectionManager::instance()->addLocation(albumRoot, albumRoot.fileName());
  380             // Not needed? See bug #188959
  381             //ScanController::instance()->completeCollectionScan();
  382         }
  383     }
  384 
  385     // -- ---------------------------------------------------------
  386 
  387     QApplication::setOverrideCursor(Qt::WaitCursor);
  388 
  389     ThumbnailLoadThread::initializeThumbnailDatabase(CoreDbAccess::parameters().thumbnailParameters(),
  390                                                      new ThumbsDbInfoProvider());
  391 
  392     DbEngineGuiErrorHandler* const thumbnailsDBHandler = new DbEngineGuiErrorHandler(ThumbsDbAccess::parameters());
  393     ThumbsDbAccess::initDbEngineErrorHandler(thumbnailsDBHandler);
  394 
  395     // Activate the similarity database.
  396 
  397     SimilarityDbAccess::setParameters(params.similarityParameters());
  398 
  399     DbEngineGuiErrorHandler* const similarityHandler = new DbEngineGuiErrorHandler(SimilarityDbAccess::parameters());
  400     SimilarityDbAccess::initDbEngineErrorHandler(similarityHandler);
  401 
  402     if (SimilarityDbAccess::checkReadyForUse(nullptr))
  403     {
  404         qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database ready for use";
  405     }
  406     else
  407     {
  408         qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Failed to initialize similarity database";
  409     }
  410 
  411     QApplication::restoreOverrideCursor();
  412 
  413     return true;
  414 }
  415 
  416 void AlbumManager::checkDatabaseDirsAfterFirstRun(const QString& dbPath, const QString& albumPath)
  417 {
  418     // for bug #193522
  419     QDir               newDir(dbPath);
  420     QDir               albumDir(albumPath);
  421     DbEngineParameters newParams = DbEngineParameters::parametersForSQLiteDefaultFile(newDir.path());
  422     QFileInfo          digikam4DB(newParams.SQLiteDatabaseFile());
  423 
  424     if (!digikam4DB.exists())
  425     {
  426         QFileInfo digikam3DB(newDir, QLatin1String("digikam3.db"));
  427         QFileInfo digikamVeryOldDB(newDir, QLatin1String("digikam.db"));
  428 
  429         if (digikam3DB.exists() || digikamVeryOldDB.exists())
  430         {
  431             QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning,
  432                      i18n("Database Folder"),
  433                      i18n("<p>You have chosen the folder \"%1\" as the place to store the database. "
  434                           "A database file from an older version of digiKam is found in this folder.</p> "
  435                           "<p>Would you like to upgrade the old database file - confirming "
  436                           "that this database file was indeed created for the pictures located in the folder \"%2\" - "
  437                           "or ignore the old file and start with a new database?</p> ",
  438                           QDir::toNativeSeparators(newDir.path()),
  439                           QDir::toNativeSeparators(albumDir.path())),
  440                       QMessageBox::Yes | QMessageBox::No,
  441                       qApp->activeWindow());
  442 
  443             msgBox->button(QMessageBox::Yes)->setText(i18n("Upgrade Database"));
  444             msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
  445             msgBox->button(QMessageBox::No)->setText(i18n("Create New Database"));
  446             msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new")));
  447             msgBox->setDefaultButton(QMessageBox::Yes);
  448 
  449             int result = msgBox->exec();
  450 
  451             if (result == QMessageBox::Yes)
  452             {
  453                 // CoreDbSchemaUpdater expects Album Path to point to the album root of the 0.9 db file.
  454                 // Restore this situation.
  455                 KSharedConfigPtr config = KSharedConfig::openConfig();
  456                 KConfigGroup group      = config->group("Album Settings");
  457                 group.writeEntry("Album Path", albumDir.path());
  458                 group.sync();
  459             }
  460             else if (result == QMessageBox::No)
  461             {
  462                 moveToBackup(digikam3DB);
  463                 moveToBackup(digikamVeryOldDB);
  464             }
  465 
  466             delete msgBox;
  467         }
  468     }
  469 }
  470 
  471 void AlbumManager::changeDatabase(const DbEngineParameters& newParams)
  472 {
  473     // if there is no file at the new place, copy old one
  474     DbEngineParameters params = CoreDbAccess::parameters();
  475 
  476     // New database type SQLITE
  477     if (newParams.isSQLite())
  478     {
  479         DatabaseServerStarter::instance()->stopServerManagerProcess();
  480 
  481         QDir newDir(newParams.getCoreDatabaseNameOrDir());
  482         QFileInfo newFile(newDir, QLatin1String("digikam4.db"));
  483 
  484         if (!newFile.exists())
  485         {
  486             QFileInfo digikam3DB(newDir, QLatin1String("digikam3.db"));
  487             QFileInfo digikamVeryOldDB(newDir, QLatin1String("digikam.db"));
  488 
  489             if (digikam3DB.exists() || digikamVeryOldDB.exists())
  490             {
  491                 int result = -1;
  492 
  493                 if (params.isSQLite())
  494                 {
  495                     QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning,
  496                              i18n("New database folder"),
  497                              i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. "
  498                                   "A database file from an older version of digiKam is found in this folder.</p> "
  499                                   "<p>Would you like to upgrade the old database file, start with a new database, "
  500                                   "or copy the current database to this location and continue using it?</p> ",
  501                                   QDir::toNativeSeparators(newDir.path())),
  502                              QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
  503                              qApp->activeWindow());
  504 
  505                     msgBox->button(QMessageBox::Yes)->setText(i18n("Upgrade Database"));
  506                     msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
  507                     msgBox->button(QMessageBox::No)->setText(i18n("Create New Database"));
  508                     msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new")));
  509                     msgBox->button(QMessageBox::Cancel)->setText(i18n("Copy Current Database"));
  510                     msgBox->button(QMessageBox::Cancel)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy")));
  511                     msgBox->setDefaultButton(QMessageBox::Yes);
  512 
  513                     result = msgBox->exec();
  514                     delete msgBox;
  515                 }
  516                 else
  517                 {
  518                     QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning,
  519                              i18n("New database folder"),
  520                              i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. "
  521                                   "A database file from an older version of digiKam is found in this folder.</p> "
  522                                   "<p>Would you like to upgrade the old database file or start with a new database?</p>",
  523                                   QDir::toNativeSeparators(newDir.path())),
  524                              QMessageBox::Yes | QMessageBox::No,
  525                              qApp->activeWindow());
  526 
  527                     msgBox->button(QMessageBox::Yes)->setText(i18n("Upgrade Database"));
  528                     msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
  529                     msgBox->button(QMessageBox::No)->setText(i18n("Create New Database"));
  530                     msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-new")));
  531                     msgBox->setDefaultButton(QMessageBox::Yes);
  532 
  533                     result = msgBox->exec();
  534                     delete msgBox;
  535                 }
  536 
  537                 if (result == QMessageBox::Yes)
  538                 {
  539                     // CoreDbSchemaUpdater expects Album Path to point to the album root of the 0.9 db file.
  540                     // Restore this situation.
  541                     KSharedConfigPtr config = KSharedConfig::openConfig();
  542                     KConfigGroup group      = config->group(QLatin1String("Album Settings"));
  543                     group.writeEntry(QLatin1String("Album Path"), newDir.path());
  544                     group.sync();
  545                 }
  546                 else if (result == QMessageBox::No)
  547                 {
  548                     moveToBackup(digikam3DB);
  549                     moveToBackup(digikamVeryOldDB);
  550                 }
  551                 else if (result == QMessageBox::Cancel)
  552                 {
  553                     QFileInfo oldFile(params.SQLiteDatabaseFile());
  554                     copyToNewLocation(oldFile, newFile, i18n("Failed to copy the old database file (\"%1\") "
  555                                                              "to its new location (\"%2\"). "
  556                                                              "Trying to upgrade old databases.",
  557                                                              QDir::toNativeSeparators(oldFile.filePath()),
  558                                                              QDir::toNativeSeparators(newFile.filePath())));
  559                 }
  560             }
  561             else
  562             {
  563                 int result = QMessageBox::Yes;
  564 
  565                 if (params.isSQLite())
  566                 {
  567                     QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning,
  568                              i18n("New database folder"),
  569                              i18n("<p>You have chosen the folder \"%1\" as the new place to store the database.</p>"
  570                                   "<p>Would you like to copy the current database to this location "
  571                                   "and continue using it, or start with a new database?</p> ",
  572                                   QDir::toNativeSeparators(newDir.path())),
  573                              QMessageBox::Yes | QMessageBox::No,
  574                              qApp->activeWindow());
  575 
  576                     msgBox->button(QMessageBox::Yes)->setText(i18n("Create New Database"));
  577                     msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("document-new")));
  578                     msgBox->button(QMessageBox::No)->setText(i18n("Copy Current Database"));
  579                     msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy")));
  580                     msgBox->setDefaultButton(QMessageBox::Yes);
  581 
  582                     result = msgBox->exec();
  583                     delete msgBox;
  584                 }
  585 
  586                 if (result == QMessageBox::No)
  587                 {
  588                     QFileInfo oldFile(params.SQLiteDatabaseFile());
  589                     copyToNewLocation(oldFile, newFile);
  590                 }
  591             }
  592         }
  593         else
  594         {
  595             int result = QMessageBox::No;
  596 
  597             if (params.isSQLite())
  598             {
  599                 QPointer<QMessageBox> msgBox = new QMessageBox(QMessageBox::Warning,
  600                          i18n("New database folder"),
  601                          i18n("<p>You have chosen the folder \"%1\" as the new place to store the database. "
  602                               "There is already a database file in this location.</p> "
  603                               "<p>Would you like to use this existing file as the new database, or remove it "
  604                               "and copy the current database to this place?</p> ",
  605                               QDir::toNativeSeparators(newDir.path())),
  606                          QMessageBox::Yes | QMessageBox::No,
  607                          qApp->activeWindow());
  608 
  609                 msgBox->button(QMessageBox::Yes)->setText(i18n("Copy Current Database"));
  610                 msgBox->button(QMessageBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("edit-copy")));
  611                 msgBox->button(QMessageBox::No)->setText(i18n("Use Existing File"));
  612                 msgBox->button(QMessageBox::No)->setIcon(QIcon::fromTheme(QLatin1String("document-open")));
  613                 msgBox->setDefaultButton(QMessageBox::Yes);
  614 
  615                 result = msgBox->exec();
  616                 delete msgBox;
  617             }
  618 
  619             if (result == QMessageBox::Yes)
  620             {
  621                 // first backup
  622                 if (moveToBackup(newFile))
  623                 {
  624                     QFileInfo oldFile(params.SQLiteDatabaseFile());
  625 
  626                     // then copy
  627                     copyToNewLocation(oldFile, newFile);
  628                 }
  629             }
  630         }
  631     }
  632 
  633     if (setDatabase(newParams, false))
  634     {
  635         QApplication::setOverrideCursor(Qt::WaitCursor);
  636         startScan();
  637         QApplication::restoreOverrideCursor();
  638         ScanController::instance()->completeCollectionScan();
  639     }
  640 }
  641 
  642 bool AlbumManager::databaseEqual(const DbEngineParameters& parameters) const
  643 {
  644     DbEngineParameters params = CoreDbAccess::parameters();
  645 
  646     return (params == parameters);
  647 }
  648 
  649 void AlbumManager::addFakeConnection()
  650 {
  651     if (!d->dbFakeConnection)
  652     {
  653         // workaround for the problem mariaDB >= 10.2 and QTBUG-63108
  654         QSqlDatabase::addDatabase(QLatin1String("QMYSQL"), QLatin1String("FakeConnection"));
  655         d->dbFakeConnection = true;
  656     }
  657 }
  658 
  659 void AlbumManager::removeFakeConnection()
  660 {
  661     if (d->dbFakeConnection)
  662     {
  663         QSqlDatabase::removeDatabase(QLatin1String("FakeConnection"));
  664     }
  665 }
  666 
  667 bool AlbumManager::moveToBackup(const QFileInfo& info)
  668 {
  669     if (info.exists())
  670     {
  671         QFileInfo backup(info.dir(), info.fileName() + QLatin1String("-backup-") + QDateTime::currentDateTime().toString(Qt::ISODate));
  672 
  673         bool ret = QDir().rename(info.filePath(), backup.filePath());
  674 
  675         if (!ret)
  676         {
  677             QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(),
  678                                   i18n("Failed to backup the existing database file (\"%1\"). "
  679                                        "Refusing to replace file without backup, using the existing file.",
  680                                        QDir::toNativeSeparators(info.filePath())));
  681             return false;
  682         }
  683     }
  684 
  685     return true;
  686 }
  687 
  688 bool AlbumManager::copyToNewLocation(const QFileInfo& oldFile,
  689                                      const QFileInfo& newFile,
  690                                      const QString otherMessage)
  691 {
  692     QString message = otherMessage;
  693 
  694     if (message.isNull())
  695     {
  696         message = i18n("Failed to copy the old database file (\"%1\") "
  697                        "to its new location (\"%2\"). "
  698                        "Starting with an empty database.",
  699                        QDir::toNativeSeparators(oldFile.filePath()),
  700                        QDir::toNativeSeparators(newFile.filePath()));
  701     }
  702 
  703     bool ret = QFile::copy(oldFile.filePath(), newFile.filePath());
  704 
  705     if (!ret)
  706     {
  707         QMessageBox::critical(qApp->activeWindow(), qApp->applicationName(), message);
  708         return false;
  709     }
  710 
  711     return true;
  712 }
  713 
  714 } // namespace Digikam