File indexing completed on 2025-01-05 03:58:23

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2016-09-29
0007  * Description : migration page from digikam4
0008  *
0009  * SPDX-FileCopyrightText: 2016 by Antonio Larrosa <alarrosa at suse dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "migratefromdigikam4page.h"
0016 
0017 // Qt includes
0018 
0019 #include <QLabel>
0020 #include <QRadioButton>
0021 #include <QButtonGroup>
0022 #include <QDir>
0023 #include <QFileInfo>
0024 #include <QFile>
0025 #include <QStringList>
0026 #include <QVBoxLayout>
0027 #include <QApplication>
0028 #include <QStyle>
0029 #include <QSqlDatabase>
0030 #include <QSqlQuery>
0031 #include <QSqlError>
0032 #include <QStandardPaths>
0033 
0034 // KDE includes
0035 
0036 #include <klocalizedstring.h>
0037 #include <kdelibs4configmigrator.h>
0038 #include <kdelibs4migration.h>
0039 
0040 // Local includes
0041 
0042 #include "digikam_debug.h"
0043 #include "dbengineparameters.h"
0044 #include "dlayoutbox.h"
0045 
0046 namespace Digikam
0047 {
0048 
0049 class Q_DECL_HIDDEN MigrateFromDigikam4Page::Private
0050 {
0051 public:
0052 
0053     explicit Private()
0054       : migrateBehavior(nullptr),
0055         migrate        (nullptr),
0056         createnew      (nullptr)
0057     {
0058     }
0059 
0060     QButtonGroup* migrateBehavior;
0061     QRadioButton* migrate;
0062     QRadioButton* createnew;
0063 };
0064 
0065 MigrateFromDigikam4Page::MigrateFromDigikam4Page(QWizard* const dlg)
0066     : DWizardPage(dlg, i18n("Migration from digiKam 4")),
0067       d          (new Private)
0068 {
0069     const int spacing        = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0070                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0071     DVBox* const vbox        = new DVBox(this);
0072     QLabel* const title      = new QLabel(vbox);
0073     title->setWordWrap(true);
0074     title->setText(i18n("<qt>"
0075                         "<p><h1><b>Migrate configuration and metadata from digiKam 4</b></h1></p>"
0076                         "<p>You can choose here if you want to use the configuration and albums from digiKam 4 in new digiKam. "
0077                         "Please note the following warnings:</p>"
0078                         "<p>Migration is done <b>at your own risk</b>. digiKam developers "
0079                         "do not recommend it and do not support it. On the other hand, creating "
0080                         "a new configuration might result in loss of tags and other metadata that was not embedded inside "
0081                         "the pictures and was only available in digiKam 4's database.</p>"
0082                         "<p>In either case you are recommended to backup "
0083                         "the configuration files and databases before proceeding.</p>"
0084                         "</qt>"));
0085 
0086     QWidget* const btns      = new QWidget(vbox);
0087     QVBoxLayout* const vlay  = new QVBoxLayout(btns);
0088 
0089     d->migrateBehavior       = new QButtonGroup(btns);
0090     d->migrate               = new QRadioButton(btns);
0091     d->migrate->setText(i18n("Migrate configuration from digiKam 4"));
0092     d->migrate->setChecked(true);
0093 
0094     connect(d->migrate, SIGNAL(toggled(bool)),
0095             this, SLOT(migrationToggled(bool)));
0096 
0097     d->migrateBehavior->addButton(d->migrate);
0098 
0099     d->createnew             = new QRadioButton(btns);
0100     d->createnew->setText(i18n("Create a new configuration"));
0101     d->migrateBehavior->addButton(d->createnew);
0102 
0103     vlay->addWidget(d->migrate);
0104     vlay->addWidget(d->createnew);
0105     vlay->setContentsMargins(spacing, spacing, spacing, spacing);
0106     vlay->setSpacing(spacing);
0107 
0108 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
0109 
0110     connect(d->migrateBehavior, SIGNAL(idClicked(int)),
0111             this, SIGNAL(completeChanged()));
0112 
0113 #else
0114 
0115     connect(d->migrateBehavior, SIGNAL(buttonClicked(int)),
0116             this, SIGNAL(completeChanged()));
0117 
0118 #endif
0119 
0120     setPageWidget(vbox);
0121 }
0122 
0123 MigrateFromDigikam4Page::~MigrateFromDigikam4Page()
0124 {
0125     delete d;
0126 }
0127 
0128 void MigrateFromDigikam4Page::doMigration()
0129 {
0130     // Migrate digiKam config files from $KDEHOME/share/config/
0131 
0132     Kdelibs4ConfigMigrator migrator(QLatin1String("digikam"));
0133     QStringList configFiles;
0134     configFiles << QLatin1String("digikamrc")
0135                 << QLatin1String("digikam_tagsmanagerrc")
0136                 << QLatin1String("showfotorc");
0137     migrator.setConfigFiles(configFiles);
0138     migrator.migrate();
0139 
0140     // Migrate digiKam config files from $KDEHOME/share/apps/digikam/
0141 
0142     Kdelibs4Migration migration;
0143     QString oldappdatadir   = migration.locateLocal("data", QLatin1String("digikam"));
0144     QStringList oldAppFiles = QDir(oldappdatadir).entryList(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
0145 
0146     Q_FOREACH (const QString& configFileName, oldAppFiles)
0147     {
0148         const QString newConfigLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
0149                                           QLatin1Char('/') + configFileName + QLatin1Char('5');
0150 
0151         if (QFile(newConfigLocation).exists())
0152         {
0153             qCDebug(DIGIKAM_GENERAL_LOG) << newConfigLocation << " already exists. Skipping";
0154             continue;
0155         }
0156 
0157         QFileInfo fileInfo(newConfigLocation);
0158         QDir().mkpath(fileInfo.absolutePath());
0159 
0160         const QString oldConfigFile = oldappdatadir + QLatin1Char('/') + configFileName;
0161 
0162         if (!oldConfigFile.isEmpty())
0163         {
0164             if (QFile(oldConfigFile).copy(newConfigLocation))
0165             {
0166                 qCDebug(DIGIKAM_GENERAL_LOG) << "Config file" << oldConfigFile << "was migrated to" << newConfigLocation;
0167             }
0168         }
0169     }
0170 
0171     // Migrate $KDEHOME/share/apps/kipi/geobookmarks.xml to ./.local/share/digikam/geobookmarks.xml
0172 
0173     QString oldGeobookmarksFile       = migration.locateLocal("data", QLatin1String("kipi/geobookmarks.xml"));
0174     const QString newGeobookmarksFile = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
0175                                         QLatin1String("/geobookmarks.xml");
0176 
0177     if (QFile(newGeobookmarksFile).exists())
0178     {
0179         qCDebug(DIGIKAM_GENERAL_LOG) << newGeobookmarksFile << " already exists. Skipping";
0180     }
0181     else
0182     {
0183         QFileInfo fileInfo(newGeobookmarksFile);
0184         QDir().mkpath(fileInfo.absolutePath());
0185 
0186         if (!oldGeobookmarksFile.isEmpty())
0187         {
0188             if (QFile(oldGeobookmarksFile).copy(newGeobookmarksFile))
0189             {
0190                 qCDebug(DIGIKAM_GENERAL_LOG) << "Config file" << oldGeobookmarksFile << "was migrated to" << newGeobookmarksFile;
0191             }
0192         }
0193     }
0194 
0195     // Fix albumroot identifier since digiKam 5 doesn't interpret correctly
0196     // values like volumeid:?path=%2Fhome%2Fantonio%2FPictures and it needs
0197     // to be url-decoded.
0198 
0199     DbEngineParameters parameters = DbEngineParameters::parametersFromConfig();
0200     QSqlDatabase databaseHandler  = QSqlDatabase::addDatabase(parameters.databaseType, QLatin1String("digikam4migration"));
0201 
0202     databaseHandler.setHostName(parameters.hostName);
0203     databaseHandler.setPort(parameters.port);
0204     databaseHandler.setDatabaseName(parameters.databaseNameCore);
0205     databaseHandler.setUserName(parameters.userName);
0206     databaseHandler.setPassword(parameters.password);
0207     databaseHandler.setConnectOptions(parameters.connectOptions);
0208 
0209     if (!databaseHandler.open())
0210     {
0211         qCDebug(DIGIKAM_GENERAL_LOG) << "Cannot open database:" << databaseHandler.lastError().text();
0212         return;
0213     }
0214 
0215     QSqlQuery query(QLatin1String("SELECT id,identifier FROM albumroots"), databaseHandler);
0216 
0217     while (query.next())
0218     {
0219         int id             = query.value(0).toInt();
0220         QString identifier = query.value(1).toString();
0221 
0222         if (identifier.startsWith(QLatin1String("volumeid:?path=%2F")))
0223         {
0224             QUrl url(identifier);
0225             url.setQuery(url.query(QUrl::FullyDecoded), QUrl::DecodedMode);
0226             qCDebug(DIGIKAM_GENERAL_LOG) << "Updating albumroot " << id << " from " << identifier << " to " << url.toString();
0227             QSqlQuery uquery(QLatin1String("UPDATE albumroots SET identifier=? WHERE id=?"), databaseHandler);
0228             uquery.bindValue(0, url.toString());
0229             uquery.bindValue(1, id);
0230             bool ret = uquery.exec();
0231 
0232             if (!ret)
0233             {
0234                 qCDebug(DIGIKAM_GENERAL_LOG) << "Cannot query database for migration:" << databaseHandler.lastError().text();
0235             }
0236         }
0237     }
0238 
0239     databaseHandler.close();
0240 
0241     qCDebug(DIGIKAM_GENERAL_LOG) << "Migration finished";
0242 }
0243 
0244 bool MigrateFromDigikam4Page::isMigrationChecked() const
0245 {
0246     return d->migrate->isChecked();
0247 }
0248 
0249 void MigrateFromDigikam4Page::migrationToggled(bool b)
0250 {
0251     setFinalPage(b);
0252 }
0253 
0254 int MigrateFromDigikam4Page::nextId() const
0255 {
0256     if (d->migrate->isChecked())
0257     {
0258         return (-1);
0259     }
0260     else
0261     {
0262         return QWizardPage::nextId();
0263     }
0264 }
0265 
0266 bool MigrateFromDigikam4Page::checkForMigration()
0267 {
0268 
0269 #ifdef Q_OS_LINUX
0270 
0271     ::Kdelibs4Migration migration;
0272 
0273     // If there's a digikamrc file in $KDEHOME/share/config,
0274     // then we create the migration page in the wizard
0275 
0276     return (!migration.locateLocal("config", QLatin1String("digikamrc")).isEmpty());
0277 
0278 #endif
0279 
0280     return false;
0281 }
0282 
0283 } // namespace Digikam
0284 
0285 #include "moc_migratefromdigikam4page.cpp"