File indexing completed on 2024-04-28 16:21:23

0001 /* This file is part of the KDE project
0002    Copyright 2008 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "FunctionModuleRegistry.h"
0021 
0022 #include "SheetsDebug.h"
0023 #include "Function.h"
0024 #include "FunctionRepository.h"
0025 
0026 #include <QGlobalStatic>
0027 #include <KSharedConfig>
0028 
0029 #ifndef SHEETS_NO_PLUGINMODULES
0030 #include <kplugininfo.h>
0031 #include <KPluginFactory>
0032 #include <KoPluginLoader.h>
0033 #else
0034 #include "functions/BitOpsModule.h"
0035 #include "functions/ConversionModule.h"
0036 #include "functions/DatabaseModule.h"
0037 #include "functions/DateTimeModule.h"
0038 #include "functions/EngineeringModule.h"
0039 #include "functions/FinancialModule.h"
0040 #include "functions/InformationModule.h"
0041 #include "functions/LogicModule.h"
0042 #include "functions/MathModule.h"
0043 #include "functions/ReferenceModule.h"
0044 #include "functions/StatisticalModule.h"
0045 #include "functions/TextModule.h"
0046 #include "functions/TrigonometryModule.h"
0047 #endif
0048 
0049 Q_GLOBAL_STATIC(Calligra::Sheets::FunctionModuleRegistry, s_instance)
0050 
0051 using namespace Calligra::Sheets;
0052 
0053 class Q_DECL_HIDDEN FunctionModuleRegistry::Private
0054 {
0055 public:
0056     void registerFunctionModule(FunctionModule* module);
0057     void removeFunctionModule(FunctionModule* module);
0058 
0059 public:
0060     bool repositoryInitialized;
0061 };
0062 
0063 void FunctionModuleRegistry::Private::registerFunctionModule(FunctionModule* module)
0064 {
0065     const QList<QSharedPointer<Function> > functions = module->functions();
0066     for (int i = 0; i < functions.count(); ++i) {
0067         FunctionRepository::self()->add(functions[i]);
0068     }
0069     Q_ASSERT(!module->descriptionFileName().isEmpty());
0070     const QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0071                                                     QStringLiteral("calligrasheets/functions/")+module->descriptionFileName());
0072     if (fileName.isEmpty()) {
0073         debugSheetsFormula << module->descriptionFileName() << "not found.";
0074         return;
0075     }
0076     FunctionRepository::self()->loadFunctionDescriptions(fileName);
0077 }
0078 
0079 void FunctionModuleRegistry::Private::removeFunctionModule(FunctionModule* module)
0080 {
0081     const QList<QSharedPointer<Function> > functions = module->functions();
0082     for (int i = 0; i < functions.count(); ++i) {
0083         FunctionRepository::self()->remove(functions[i]);
0084     }
0085 }
0086 
0087 
0088 FunctionModuleRegistry::FunctionModuleRegistry()
0089         : d(new Private)
0090 {
0091     d->repositoryInitialized = false;
0092 }
0093 
0094 FunctionModuleRegistry::~FunctionModuleRegistry()
0095 {
0096     foreach(const QString &id, keys()) {
0097         get(id)->deleteLater();
0098     }
0099     qDeleteAll(doubleEntries());
0100     delete d;
0101 }
0102 
0103 FunctionModuleRegistry* FunctionModuleRegistry::instance()
0104 {
0105     return s_instance;
0106 }
0107 
0108 void FunctionModuleRegistry::loadFunctionModules()
0109 {
0110 #ifndef SHEETS_NO_PLUGINMODULES
0111     const QList<QPluginLoader *> offers = KoPluginLoader::pluginLoaders(QStringLiteral("calligrasheets/functions"));
0112     debugSheetsFormula << offers.count() << "function modules found.";
0113 
0114     const KConfigGroup pluginsConfigGroup = KSharedConfig::openConfig()->group("Plugins");
0115     foreach (QPluginLoader *loader, offers) {
0116 
0117         QJsonObject metaData = loader->metaData().value("MetaData").toObject();
0118         int version = metaData.value("X-CalligraSheets-InterfaceVersion").toInt();
0119         if (version != 0) {
0120             debugSheetsFormula << "Skipping" << loader->fileName() << ", because interface version is" << version;
0121             continue;
0122         }
0123         QJsonObject pluginData = metaData.value("KPlugin").toObject();
0124         QString category = pluginData.value("Category").toString();
0125         if (category != "FunctionModule") {
0126             debugSheetsFormula << "Skipping" << loader->fileName() << ", because category is " << category;
0127             continue;
0128         }
0129 
0130         const QString pluginId = pluginData.value("Id").toString();
0131         const QString pluginConfigEnableKey = pluginId + QLatin1String("Enabled");
0132         const bool isPluginEnabled = pluginsConfigGroup.hasKey(pluginConfigEnableKey) ?
0133             pluginsConfigGroup.readEntry(pluginConfigEnableKey, true) :
0134             pluginData.value("EnabledByDefault").toBool(true);
0135 
0136         if (isPluginEnabled) {
0137             if(contains(pluginId)) {
0138                 continue;
0139             }
0140             // Plugin enabled, but not registered. Add it.
0141             KPluginFactory* const factory = qobject_cast<KPluginFactory *>(loader->instance());
0142             if (!factory) {
0143                 debugSheetsFormula << "Unable to create plugin factory for" << loader->fileName();
0144                 continue;
0145             }
0146             FunctionModule* const module = qobject_cast<FunctionModule *>(factory->create());
0147             if (!module) {
0148                 debugSheetsFormula << "Unable to create function module for" << loader->fileName();
0149                 continue;
0150             }
0151 
0152             add(pluginId, module);
0153             debugSheetsFormula << "Loaded" << pluginId;
0154 
0155             // Delays the function registration until the user needs one.
0156             if (d->repositoryInitialized) {
0157                 d->registerFunctionModule(module);
0158             }
0159         } else {
0160             if (!contains(pluginId)) {
0161                 continue;
0162             }
0163             // Plugin disabled, but registered. Remove it.
0164             FunctionModule* const module = get(pluginId);
0165             // Delay the function registration until the user needs one.
0166             if (d->repositoryInitialized) {
0167                 d->removeFunctionModule(module);
0168             }
0169             remove(pluginId);
0170             if (module->isRemovable()) {
0171                 delete module;
0172                 KPluginFactory* factory = qobject_cast<KPluginFactory *>(loader->instance());
0173                 delete factory;
0174                 loader->unload();
0175             } else {
0176                 // Put it back in.
0177                 add(pluginId, module);
0178                 // Delay the function registration until the user needs one.
0179                 if (d->repositoryInitialized) {
0180                     d->registerFunctionModule(module);
0181                 }
0182             }
0183         }
0184     }
0185     qDeleteAll(offers);
0186 #else
0187     QList<FunctionModule*> modules;
0188     QObject *parent = 0;
0189 
0190     modules << new BitOpsModule(parent);
0191     modules << new ConversionModule(parent);
0192     modules << new DatabaseModule(parent);
0193     modules << new DateTimeModule(parent);
0194     modules << new EngineeringModule(parent);
0195     modules << new FinancialModule(parent);
0196     modules << new InformationModule(parent);
0197     modules << new LogicModule(parent);
0198     modules << new MathModule(parent);
0199     modules << new ReferenceModule(parent);
0200     modules << new StatisticalModule(parent);
0201     modules << new TextModule(parent);
0202     modules << new TrigonometryModule(parent);
0203 
0204     Q_FOREACH(FunctionModule* module, modules) {
0205         add(module->id(), module);
0206         d->registerFunctionModule(module);
0207     }
0208 #endif
0209 }
0210 
0211 void FunctionModuleRegistry::registerFunctions()
0212 {
0213     d->repositoryInitialized = true;
0214     const QList<FunctionModule*> modules = values();
0215     for (int i = 0; i < modules.count(); ++i) {
0216         d->registerFunctionModule(modules[i]);
0217     }
0218 }