1/*
2 * Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "dataenginemanager.h"
21
22#include <QFile>
23#include <QTextStream>
24
25#include <kdebug.h>
26#include <kglobal.h>
27#include <kstandarddirs.h>
28#include <kservicetypetrader.h>
29
30#include "datacontainer.h"
31#include "pluginloader.h"
32#include "private/componentinstaller_p.h"
33#include "private/dataengine_p.h"
34#include "private/datacontainer_p.h"
35#include "scripting/scriptengine.h"
36
37namespace Plasma
38{
39
40class NullEngine : public DataEngine
41{
42 public:
43 NullEngine(QObject *parent = 0)
44 : DataEngine(parent)
45 {
46 setValid(false);
47
48 // ref() ourselves to ensure we never get deleted
49 d->ref();
50 }
51};
52
53class DataEngineManagerPrivate
54{
55 public:
56 DataEngineManagerPrivate()
57 : nullEng(0)
58 {}
59
60 ~DataEngineManagerPrivate()
61 {
62 foreach (Plasma::DataEngine *engine, engines) {
63 delete engine;
64 }
65 engines.clear();
66 delete nullEng;
67 }
68
69 DataEngine *nullEngine()
70 {
71 if (!nullEng) {
72 nullEng = new NullEngine;
73 }
74
75 return nullEng;
76 }
77
78 DataEngine::Dict engines;
79 DataEngine *nullEng;
80};
81
82class DataEngineManagerSingleton
83{
84 public:
85 DataEngineManager self;
86};
87
88K_GLOBAL_STATIC(DataEngineManagerSingleton, privateDataEngineManagerSelf)
89
90DataEngineManager *DataEngineManager::self()
91{
92 return &privateDataEngineManagerSelf->self;
93}
94
95DataEngineManager::DataEngineManager()
96 : d(new DataEngineManagerPrivate)
97{
98 //startTimer(30000);
99}
100
101DataEngineManager::~DataEngineManager()
102{
103 delete d;
104}
105
106Plasma::DataEngine *DataEngineManager::engine(const QString &name) const
107{
108 if (name.isEmpty()) {
109 return d->nullEngine();
110 }
111
112 Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
113 if (it != d->engines.constEnd()) {
114 // ref and return the engine
115 //Plasma::DataEngine *engine = *it;
116 return *it;
117 }
118
119 return d->nullEngine();
120}
121
122Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name)
123{
124 Plasma::DataEngine::Dict::const_iterator it = d->engines.constFind(name);
125
126 if (it != d->engines.constEnd()) {
127 DataEngine *engine = *it;
128 engine->d->ref();
129 return engine;
130 }
131
132 DataEngine *engine = PluginLoader::pluginLoader()->loadDataEngine(name);
133 if (!engine) {
134 // Try installing the engine. However, it's too late for this request.
135 ComponentInstaller::self()->installMissingComponent("dataengine", name);
136
137 return d->nullEngine();
138 }
139
140 engine->init();
141 d->engines[name] = engine;
142 return engine;
143}
144
145void DataEngineManager::unloadEngine(const QString &name)
146{
147 Plasma::DataEngine::Dict::iterator it = d->engines.find(name);
148
149 if (it != d->engines.end()) {
150 Plasma::DataEngine *engine = *it;
151 engine->d->deref();
152
153 if (!engine->d->isUsed()) {
154 d->engines.erase(it);
155 delete engine;
156 }
157 }
158}
159
160QStringList DataEngineManager::listAllEngines(const QString &parentApp)
161{
162 QString constraint;
163
164 if (parentApp.isEmpty()) {
165 constraint.append("(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
166 } else {
167 constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
168 }
169
170 KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
171
172 QStringList engines;
173 foreach (const KService::Ptr &service, offers) {
174 QString name = service->property("X-KDE-PluginInfo-Name").toString();
175 if (!name.isEmpty()) {
176 engines.append(name);
177 }
178 }
179
180 return engines;
181}
182
183KPluginInfo::List DataEngineManager::listEngineInfo(const QString &parentApp)
184{
185 return PluginLoader::pluginLoader()->listDataEngineInfo(parentApp);
186}
187
188KPluginInfo::List DataEngineManager::listEngineInfoByCategory(const QString &category, const QString &parentApp)
189{
190 QString constraint = QString("[X-KDE-PluginInfo-Category] == '%1'").arg(category);
191
192 if (parentApp.isEmpty()) {
193 constraint.append(" and not exist [X-KDE-ParentApp]");
194 } else {
195 constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'");
196 }
197
198 KService::List offers = KServiceTypeTrader::self()->query("Plasma/DataEngine", constraint);
199 return KPluginInfo::fromServices(offers);
200}
201
202void DataEngineManager::timerEvent(QTimerEvent *)
203{
204#ifndef NDEBUG
205 QString path = KGlobal::dirs()->locateLocal("appdata", "plasma_dataenginemanager_log");
206 QFile f(path);
207 if (!f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
208 kDebug() << "faild to open" << path;
209 return;
210 }
211
212 QTextStream out(&f);
213
214 QHashIterator<QString, DataEngine*> it(d->engines);
215 out << "================================== " << KGlobal::locale()->formatDateTime(QDateTime::currentDateTime()) << endl;
216 while (it.hasNext()) {
217 it.next();
218 DataEngine *engine = it.value();
219 out << "DataEngine: " << it.key() << ' ' << engine << endl;
220 out << " Claimed # of sources: " << engine->sources().count() << endl;
221 out << " Actual # of sources: " << engine->containerDict().count() << endl;
222 out << endl << " Source Details" << endl;
223
224 foreach (DataContainer *dc, engine->containerDict()) {
225 out << " * " << dc->objectName() << endl;
226 out << " Data count: " << dc->d->data.count() << endl;
227 out << " Stored: " << dc->isStorageEnabled() << ' ' << endl;
228 const int directs = dc->receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)));
229 if (directs > 0) {
230 out << " Direction Connections: " << directs << ' ' << endl;
231 }
232
233 const int relays = dc->d->relays.count();
234 if (relays > 0) {
235 out << " Relays: " << dc->d->relays.count() << endl;
236 QString times;
237 foreach (SignalRelay *relay, dc->d->relays) {
238 times.append(' ').append(QString::number(relay->m_interval));
239 }
240 out << " Relay Timeouts: " << times << ' ' << endl;
241 }
242 }
243
244 out << endl << "-----" << endl;
245 }
246 out << endl << endl;
247#endif
248// killTimer(event->timerId());
249}
250
251} // namespace Plasma
252
253#include "dataenginemanager.moc"
254