File indexing completed on 2024-05-12 16:40:16

0001 /* This file is part of the KDE project
0002    Daniel Molkentin <molkentin@kde.org>
0003    Joseph Wenninger <jowenn@kde.org>
0004    Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this program; see the file COPYING.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "migratemanager.h"
0023 #include "migratemanager_p.h"
0024 #include "keximigrate.h"
0025 #include "KexiMigratePluginMetaData.h"
0026 #include <core/KexiMainWindowIface.h>
0027 #include <KexiJsonTrader.h>
0028 #include <config-kexi.h>
0029 
0030 #include <KDbVersionInfo>
0031 
0032 #include <KLocalizedString>
0033 
0034 #include <QDebug>
0035 #include <QApplication>
0036 
0037 #include <assert.h>
0038 
0039 #ifdef KEXI_MIGRATEMANAGER_DEBUG
0040 #define KexiMigrateManagerDebug qDebug()
0041 #else
0042 #define KexiMigrateManagerDebug while (0) qDebug()
0043 #endif
0044 
0045 using namespace KexiMigration;
0046 
0047 Q_GLOBAL_STATIC(MigrateManagerInternal, s_self)
0048 Q_GLOBAL_STATIC_WITH_ARGS(KexiJsonTrader, KexiMigrateTrader_instance, (KEXI_BASE_PATH "/migrate"))
0049 
0050 
0051 MigrateManagerInternal::MigrateManagerInternal()
0052     : m_lookupDriversNeeded(true)
0053 {
0054 }
0055 
0056 MigrateManagerInternal::~MigrateManagerInternal()
0057 {
0058     KexiMigrateManagerDebug;
0059     clear();
0060     KexiMigrateManagerDebug << "ok";
0061 }
0062 
0063 void MigrateManagerInternal::clear()
0064 {
0065     KexiMigrateManagerDebug << "Clearing drivers...";
0066     qDeleteAll(m_drivers);
0067     m_drivers.clear();
0068     qDeleteAll(m_driversMetaData);
0069     m_driversMetaData.clear();
0070 }
0071 
0072 void MigrateManagerInternal::slotAppQuits()
0073 {
0074     if (qApp && !qApp->topLevelWidgets().isEmpty()
0075             && qApp->topLevelWidgets().first()->isVisible()) {
0076         return; //what a hack! - we give up when app is still there
0077     }
0078     clear();
0079 }
0080 
0081 bool MigrateManagerInternal::lookupDrivers()
0082 {
0083     if (!m_lookupDriversNeeded)
0084         return true;
0085 
0086     if (qApp) {
0087         connect(qApp, &QApplication::aboutToQuit, this, &MigrateManagerInternal::slotAppQuits);
0088     }
0089 
0090     m_lookupDriversNeeded = false;
0091     clearResult();
0092 
0093     QList<QPluginLoader*> offers
0094             = KexiMigrateTrader_instance->query(QLatin1String("Kexi/MigrationDriver"));
0095     const QString expectedVersion = QString::fromLatin1("%1.%2")
0096             .arg(KexiMigration::version().major()).arg(KexiMigration::version().minor());
0097     for(const QPluginLoader *loader : offers) {
0098         QScopedPointer<KexiMigratePluginMetaData> metaData(new KexiMigratePluginMetaData(*loader));
0099         if (m_driversMetaData.contains(metaData->id())) {
0100             qWarning() << "Migration driver with ID" << metaData->id() << "already found at"
0101                          << m_driversMetaData.value(metaData->id())->fileName()
0102                          << "-- skipping another at" << metaData->fileName();
0103             continue;
0104         }
0105 //! @todo Similar version check could be merged with KDbDriverManager
0106         if (metaData->version() != expectedVersion) {
0107             qWarning() << QString("Migration driver '%1' (%2) has version '%3' but "
0108                                   "KexiMigration library requires version '%4'\n"
0109                                   " -- skipping this driver!")
0110                           .arg(metaData->id()).arg(metaData->fileName())
0111                           .arg(metaData->version())
0112                           .arg(expectedVersion);
0113             m_possibleProblems += QString("Migration driver \"%1\" (%2) has version \"%3\" "
0114                                         "but required version is \"%4\"")
0115                           .arg(metaData->id()).arg(metaData->fileName())
0116                           .arg(metaData->version())
0117                           .arg(expectedVersion);
0118             continue;
0119         }
0120         foreach (const QString& mimeType, metaData->mimeTypes()) {
0121             m_metadata_by_mimetype.insertMulti(mimeType, metaData.data());
0122         }
0123         foreach (const QString& sourceDriverId, metaData->supportedSourceDrivers()) {
0124             m_metadataBySourceDrivers.insertMulti(sourceDriverId, metaData.data());
0125         }
0126         m_driversMetaData.insert(metaData->id(), metaData.data());
0127         KexiMigrateManagerDebug << "registered driver" << metaData->id() << '(' << metaData->fileName() << ")";
0128         metaData.take();
0129     }
0130 
0131     if (m_driversMetaData.isEmpty()) {
0132         m_result = KDbResult(ERR_DRIVERMANAGER, xi18n("Could not find any migration database drivers."));
0133         return false;
0134     }
0135     return true;
0136 }
0137 
0138 QStringList MigrateManagerInternal::driverIds()
0139 {
0140     if (!lookupDrivers()) {
0141         return QStringList();
0142     }
0143     if (m_driversMetaData.isEmpty() && result().isError()) {
0144         return QStringList();
0145     }
0146     return m_driversMetaData.keys();
0147 }
0148 
0149 const KexiMigratePluginMetaData* MigrateManagerInternal::driverMetaData(const QString &id)
0150 {
0151     if (!lookupDrivers()) {
0152         return 0;
0153     }
0154     const KexiMigratePluginMetaData *metaData = m_driversMetaData.value(id.toLower());
0155     if (!metaData || m_result.isError()) {
0156         m_result = KDbResult(ERR_DRIVERMANAGER,
0157                              tr("Could not find migration driver \"%1\".").arg(id));
0158     }
0159     return metaData;
0160 }
0161 
0162 QStringList MigrateManagerInternal::driverIdsForMimeType(const QString &mimeType)
0163 {
0164     if (!lookupDrivers()) {
0165         return QStringList();
0166     }
0167     const QList<KexiMigratePluginMetaData*> metaDatas(m_metadata_by_mimetype.values(mimeType.toLower()));
0168     QStringList result;
0169     for (const KexiMigratePluginMetaData* metaData : metaDatas) {
0170         result.append(metaData->id());
0171     }
0172     return result;
0173 }
0174 
0175 QStringList MigrateManagerInternal::driverIdsForSourceDriver(const QString &sourceDriverId)
0176 {
0177     if (!lookupDrivers()) {
0178         return QStringList();
0179     }
0180     QStringList result;
0181     for (const KexiMigratePluginMetaData* metaData : m_metadataBySourceDrivers.values(sourceDriverId.toLower())) {
0182         result.append(metaData->id());
0183     }
0184     return result;
0185 }
0186 
0187 KexiMigrate* MigrateManagerInternal::driver(const QString& id)
0188 {
0189     if (!lookupDrivers()) {
0190         qWarning() << "lookupDrivers failed";
0191         return 0;
0192     }
0193 
0194     clearResult();
0195     KexiMigrateManagerDebug << "loading" << id;
0196 
0197     KexiMigrate *driver = m_drivers.value(id.toLatin1().toLower());
0198     if (driver) {
0199         return driver; //cached
0200     }
0201 
0202     if (!m_driversMetaData.contains(id.toLower())) {
0203         m_result = KDbResult(ERR_OBJECT_NOT_FOUND,
0204                              tr("Could not find migration driver \"%1\".").arg(id));
0205         return 0;
0206     }
0207 
0208     const KexiMigratePluginMetaData *metaData = m_driversMetaData.value(id.toLower());
0209     KPluginFactory *factory = qobject_cast<KPluginFactory*>(metaData->instantiate());
0210     if (!factory) {
0211         m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT,
0212                              tr("Could not load migration driver's plugin file \"%1\".")
0213                                 .arg(metaData->fileName()));
0214         QPluginLoader loader(metaData->fileName()); // use this to get the message
0215         (void)loader.load();
0216         m_result.setServerMessage(loader.errorString());
0217         qWarning() << m_result.message() << m_result.serverMessage();
0218         return 0;
0219     }
0220     driver = factory->create<KexiMigrate>();
0221     if (!driver) {
0222         m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT,
0223                              tr("Could not open migration driver \"%1\" from plugin file \"%2\".")
0224                                 .arg(metaData->id())
0225                                 .arg(metaData->fileName()));
0226         qWarning() << m_result.message();
0227         return 0;
0228     }
0229     driver->setMetaData(metaData);
0230     m_drivers.insert(id.toLower(), driver);
0231     return driver;
0232 }
0233 
0234 QStringList MigrateManagerInternal::possibleProblemsMessage() const
0235 {
0236     return m_possibleProblems;
0237 }
0238 
0239 QStringList MigrateManagerInternal::supportedFileMimeTypes()
0240 {
0241     if (!lookupDrivers()) {
0242         qWarning() << "lookupDrivers failed";
0243         return QStringList();
0244     }
0245     return m_metadata_by_mimetype.uniqueKeys();
0246 }
0247 
0248 QStringList MigrateManagerInternal::supportedSourceDriverIds()
0249 {
0250     if (!lookupDrivers()) {
0251         qWarning() << "lookupDrivers failed";
0252         return QStringList();
0253     }
0254     return m_metadataBySourceDrivers.uniqueKeys();
0255 }
0256 
0257 // ---------------------------
0258 // --- DriverManager impl. ---
0259 // ---------------------------
0260 
0261 MigrateManager::MigrateManager()
0262         : QObject(0)
0263 {
0264     setObjectName("KexiMigrate::MigrateManager");
0265 }
0266 
0267 MigrateManager::~MigrateManager()
0268 {
0269     KexiMigrateManagerDebug;
0270 }
0271 
0272 QStringList MigrateManager::driverIdsForMimeType(const QString &mimeType)
0273 {
0274     return s_self->driverIdsForMimeType(mimeType);
0275 }
0276 
0277 QStringList MigrateManager::driverIdsForSourceDriver(const QString &sourceDriverId)
0278 {
0279     return s_self->driverIdsForSourceDriver(sourceDriverId);
0280 }
0281 
0282 KexiMigrate* MigrateManager::driver(const QString &id)
0283 {
0284     return s_self->driver(id);
0285 }
0286 
0287 QString MigrateManager::possibleProblemsMessage() const
0288 {
0289     if (s_self->possibleProblemsMessage().isEmpty())
0290         return QString();
0291     QString str = "<ul>";
0292     for(const QString &message : s_self->possibleProblemsMessage()) {
0293         str += (QString::fromLatin1("<li>") + message + QString::fromLatin1("</li>"));
0294     }
0295     str += "</ul>";
0296     return str;
0297 }
0298 
0299 QStringList MigrateManager::supportedFileMimeTypes()
0300 {
0301     return s_self->supportedFileMimeTypes();
0302 }
0303 
0304 QStringList MigrateManager::supportedSourceDriverIds()
0305 {
0306     return s_self->supportedSourceDriverIds();
0307 }
0308 
0309 KDbResult MigrateManager::result() const
0310 {
0311     return s_self->result();
0312 }
0313 
0314 const KDbResultable* MigrateManager::resultable() const
0315 {
0316     return s_self;
0317 }