1/* This file is part of the KDE project
2 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>
3 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; only
8 version 2 of the License.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21// Local
22#include "FunctionRepository.h"
23
24#include "Function.h"
25#include "FunctionDescription.h"
26#include "FunctionModuleRegistry.h"
27
28#include <QDomElement>
29#include <QDomNode>
30#include <QFile>
31#include <QHash>
32
33#include <kdebug.h>
34#include <kglobal.h>
35#include <klocale.h>
36
37using namespace Calligra::Sheets;
38
39class FunctionRepository::Private
40{
41public:
42 QHash<QString, QSharedPointer<Function> > functions;
43 QHash<QString, QSharedPointer<Function> > alternates;
44 QHash<QString, FunctionDescription*> descriptions;
45 QStringList groups;
46 bool initialized;
47};
48
49FunctionRepository* FunctionRepository::self()
50{
51 K_GLOBAL_STATIC(FunctionRepository, s_instance)
52 if (!s_instance.exists()) {
53 *s_instance; // creates the global instance
54
55 // register all existing functions
56 FunctionModuleRegistry::instance()->registerFunctions();
57
58#ifndef NDEBUG
59 kDebug(36005) << "functions registered:" << s_instance->d->functions.count()
60 << "descriptions loaded:" << s_instance->d->descriptions.count();
61
62 // Verify, that every function has a description.
63 QStringList missingDescriptions;
64 typedef QHash<QString, QSharedPointer<Function> > Functions;
65 Functions::ConstIterator end = s_instance->d->functions.constEnd();
66 for (Functions::ConstIterator it = s_instance->d->functions.constBegin(); it != end; ++it) {
67 if (!s_instance->d->descriptions.contains(it.key()))
68 missingDescriptions << it.key();
69 }
70 if (missingDescriptions.count() > 0) {
71 kDebug(36005) << "No function descriptions found for:";
72 foreach(const QString& missingDescription, missingDescriptions) {
73 kDebug(36005) << "\t" << missingDescription;
74 }
75 }
76#endif
77 }
78 return s_instance;
79}
80
81FunctionRepository::FunctionRepository()
82 : d(new Private)
83{
84 d->initialized = false;
85}
86
87FunctionRepository::~FunctionRepository()
88{
89 qDeleteAll(d->descriptions);
90 delete d;
91}
92
93void FunctionRepository::add(const QSharedPointer<Function>& function)
94{
95 if (!function) return;
96 d->functions.insert(function->name().toUpper(), function);
97
98 if (!function->alternateName().isNull()) {
99 d->alternates.insert(function->alternateName().toUpper(), function);
100 }
101}
102
103void FunctionRepository::add(FunctionDescription *desc)
104{
105 if (!desc) return;
106 if (!d->functions.contains(desc->name())) return;
107 d->descriptions.insert(desc->name(), desc);
108}
109
110void FunctionRepository::remove(const QSharedPointer<Function>& function)
111{
112 const QString functionName = function->name().toUpper();
113 delete d->descriptions.take(functionName);
114 if (d->functions.contains(functionName)) {
115 QSharedPointer<Function> function = d->functions.take(functionName);
116 d->alternates.remove(function->alternateName().toUpper());
117 }
118}
119
120QSharedPointer<Function> FunctionRepository::function(const QString& name)
121{
122 const QString n = name.toUpper();
123 QSharedPointer<Function> f = d->functions.value(n);
124 return !f.isNull() ? f : d->alternates.value(n);
125}
126
127FunctionDescription *FunctionRepository::functionInfo(const QString& name)
128{
129 return d->descriptions.value(name.toUpper());
130}
131
132// returns names of function in certain group
133QStringList FunctionRepository::functionNames(const QString& group)
134{
135 QStringList lst;
136
137 foreach(FunctionDescription* description, d->descriptions) {
138 if (group.isNull() || (description->group() == group))
139 lst.append(description->name());
140 }
141
142 lst.sort();
143 return lst;
144}
145
146const QStringList& FunctionRepository::groups() const
147{
148 return d->groups;
149}
150
151void FunctionRepository::addGroup(const QString& groupname)
152{
153 d->groups.append(groupname);
154 d->groups.sort();
155}
156
157void FunctionRepository::loadFunctionDescriptions(const QString& filename)
158{
159 QFile file(filename);
160 if (!file.open(QIODevice::ReadOnly))
161 return;
162
163 QDomDocument doc;
164 doc.setContent(&file);
165 file.close();
166
167 QString group;
168
169 QDomNode n = doc.documentElement().firstChild();
170 for (; !n.isNull(); n = n.nextSibling()) {
171 if (!n.isElement())
172 continue;
173 QDomElement e = n.toElement();
174 if (e.tagName() == "Group") {
175 group = i18n(e.namedItem("GroupName").toElement().text().toUtf8());
176 addGroup(group);
177
178 QDomNode n2 = e.firstChild();
179 for (; !n2.isNull(); n2 = n2.nextSibling()) {
180 if (!n2.isElement())
181 continue;
182 QDomElement e2 = n2.toElement();
183 if (e2.tagName() == "Function") {
184 FunctionDescription* desc = new FunctionDescription(e2);
185 desc->setGroup(group);
186 if (d->functions.contains(desc->name()))
187 d->descriptions.insert(desc->name(), desc);
188 else {
189 kDebug(36005) << "Description for unknown function" << desc->name() << "found.";
190 delete desc;
191 }
192 }
193 }
194 group.clear();
195 }
196 }
197}
198