1/* This file is part of the KDE project
2 Copyright 2008 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "FunctionModuleRegistry.h"
21
22#include "Function.h"
23#include "FunctionRepository.h"
24
25#include <kdebug.h>
26#include <kglobal.h>
27#include <kstandarddirs.h>
28
29#ifndef SHEETS_NO_PLUGINMODULES
30#include <kplugininfo.h>
31#include <kservicetypetrader.h>
32#else
33#include "functions/BitOpsModule.h"
34#include "functions/ConversionModule.h"
35#include "functions/DatabaseModule.h"
36#include "functions/DateTimeModule.h"
37#include "functions/EngineeringModule.h"
38#include "functions/FinancialModule.h"
39#include "functions/InformationModule.h"
40#include "functions/LogicModule.h"
41#include "functions/MathModule.h"
42#include "functions/ReferenceModule.h"
43#include "functions/StatisticalModule.h"
44#include "functions/TextModule.h"
45#include "functions/TrigonometryModule.h"
46#endif
47
48using namespace Calligra::Sheets;
49
50class FunctionModuleRegistry::Private
51{
52public:
53 void registerFunctionModule(FunctionModule* module);
54 void removeFunctionModule(FunctionModule* module);
55
56public:
57 bool repositoryInitialized;
58};
59
60void FunctionModuleRegistry::Private::registerFunctionModule(FunctionModule* module)
61{
62 const QList<QSharedPointer<Function> > functions = module->functions();
63 for (int i = 0; i < functions.count(); ++i) {
64 FunctionRepository::self()->add(functions[i]);
65 }
66 Q_ASSERT(!module->descriptionFileName().isEmpty());
67 const KStandardDirs* dirs = KGlobal::activeComponent().dirs();
68 const QString fileName = dirs->findResource("functions", module->descriptionFileName());
69 if (fileName.isEmpty()) {
70 kDebug(36002) << module->descriptionFileName() << "not found.";
71 return;
72 }
73 FunctionRepository::self()->loadFunctionDescriptions(fileName);
74}
75
76void FunctionModuleRegistry::Private::removeFunctionModule(FunctionModule* module)
77{
78 const QList<QSharedPointer<Function> > functions = module->functions();
79 for (int i = 0; i < functions.count(); ++i) {
80 FunctionRepository::self()->remove(functions[i]);
81 }
82}
83
84
85FunctionModuleRegistry::FunctionModuleRegistry()
86 : d(new Private)
87{
88 d->repositoryInitialized = false;
89}
90
91FunctionModuleRegistry::~FunctionModuleRegistry()
92{
93 foreach(const QString &id, keys()) {
94 get(id)->deleteLater();
95 }
96 qDeleteAll(doubleEntries());
97 delete d;
98}
99
100FunctionModuleRegistry* FunctionModuleRegistry::instance()
101{
102 K_GLOBAL_STATIC(FunctionModuleRegistry, s_instance)
103 return s_instance;
104}
105
106void FunctionModuleRegistry::loadFunctionModules()
107{
108#ifndef SHEETS_NO_PLUGINMODULES
109 const quint32 minKSpreadVersion = CALLIGRA_MAKE_VERSION(2, 1, 0);
110 const QString serviceType = QLatin1String("CalligraSheets/Plugin");
111 const QString query = QLatin1String("([X-CalligraSheets-InterfaceVersion] == 0) and "
112 "([X-KDE-PluginInfo-Category] == 'FunctionModule')");
113 const KService::List offers = KServiceTypeTrader::self()->query(serviceType, query);
114 const KConfigGroup moduleGroup = KGlobal::config()->group("Plugins");
115 const KPluginInfo::List pluginInfos = KPluginInfo::fromServices(offers, moduleGroup);
116 kDebug(36002) << pluginInfos.count() << "function modules found.";
117 foreach(KPluginInfo pluginInfo, pluginInfos) {
118 pluginInfo.load(); // load activation state
119 KPluginLoader loader(*pluginInfo.service());
120 // Let's be paranoid: do not believe the service type.
121 if (loader.pluginVersion() < minKSpreadVersion) {
122 kDebug(36002) << pluginInfo.name()
123 << "was built against Caligra Sheets" << loader.pluginVersion()
124 << "; required version >=" << minKSpreadVersion;
125 continue;
126 }
127 if (pluginInfo.isPluginEnabled() && !contains(pluginInfo.pluginName())) {
128 // Plugin enabled, but not registered. Add it.
129 KPluginFactory* const factory = loader.factory();
130 if (!factory) {
131 kDebug(36002) << "Unable to create plugin factory for" << pluginInfo.name();
132 continue;
133 }
134 FunctionModule* const module = factory->create<FunctionModule>();
135 if (!module) {
136 kDebug(36002) << "Unable to create function module for" << pluginInfo.name();
137 continue;
138 }
139 add(pluginInfo.pluginName(), module);
140
141 // Delays the function registration until the user needs one.
142 if (d->repositoryInitialized) {
143 d->registerFunctionModule(module);
144 }
145 } else if (!pluginInfo.isPluginEnabled() && contains(pluginInfo.pluginName())) {
146 // Plugin disabled, but registered. Remove it.
147 FunctionModule* const module = get(pluginInfo.pluginName());
148 // Delay the function registration until the user needs one.
149 if (d->repositoryInitialized) {
150 d->removeFunctionModule(module);
151 }
152 remove(pluginInfo.pluginName());
153 if (module->isRemovable()) {
154 delete module;
155 delete loader.factory();
156 loader.unload();
157 } else {
158 // Put it back in.
159 add(pluginInfo.pluginName(), module);
160 // Delay the function registration until the user needs one.
161 if (d->repositoryInitialized) {
162 d->registerFunctionModule(module);
163 }
164 }
165 }
166 }
167#else
168 QList<FunctionModule*> modules;
169 QObject *parent = 0;
170
171 modules << new BitOpsModule(parent);
172 modules << new ConversionModule(parent);
173 modules << new DatabaseModule(parent);
174 modules << new DateTimeModule(parent);
175 modules << new EngineeringModule(parent);
176 modules << new FinancialModule(parent);
177 modules << new InformationModule(parent);
178 modules << new LogicModule(parent);
179 modules << new MathModule(parent);
180 modules << new ReferenceModule(parent);
181 modules << new StatisticalModule(parent);
182 modules << new TextModule(parent);
183 modules << new TrigonometryModule(parent);
184
185 Q_FOREACH(FunctionModule* module, modules) {
186 add(module->id(), module);
187 d->registerFunctionModule(module);
188 }
189#endif
190}
191
192void FunctionModuleRegistry::registerFunctions()
193{
194 d->repositoryInitialized = true;
195 const QList<FunctionModule*> modules = values();
196 for (int i = 0; i < modules.count(); ++i) {
197 d->registerFunctionModule(modules[i]);
198 }
199}
200