00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "dataengine.h"
00021 #include "private/dataengine_p.h"
00022
00023 #include <QQueue>
00024 #include <QTimer>
00025 #include <QTime>
00026 #include <QTimerEvent>
00027 #include <QVariant>
00028
00029 #include <kdebug.h>
00030 #include <kplugininfo.h>
00031 #include <kservice.h>
00032 #include <kstandarddirs.h>
00033
00034 #include "datacontainer.h"
00035 #include "package.h"
00036 #include "service.h"
00037 #include "scripting/dataenginescript.h"
00038
00039 #include "private/service_p.h"
00040
00041 namespace Plasma
00042 {
00043
00044 DataEngine::DataEngine(QObject *parent, KService::Ptr service)
00045 : QObject(parent),
00046 d(new DataEnginePrivate(this, service))
00047 {
00048 }
00049
00050 DataEngine::DataEngine(QObject *parent, const QVariantList &args)
00051 : QObject(parent),
00052 d(new DataEnginePrivate(this, KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString())))
00053 {
00054 }
00055
00056 DataEngine::~DataEngine()
00057 {
00058
00059 delete d;
00060 }
00061
00062 QStringList DataEngine::sources() const
00063 {
00064 if (d->script) {
00065 return d->script->sources();
00066 } else {
00067 return d->sources.keys();
00068 }
00069 }
00070
00071 Service *DataEngine::serviceForSource(const QString &source)
00072 {
00073 if (d->script) {
00074 return d->script->serviceForSource(source);
00075 } else {
00076 return new NullService(source, this);
00077 }
00078 }
00079
00080 void DataEngine::connectSource(const QString &source, QObject *visualization,
00081 uint pollingInterval,
00082 Plasma::IntervalAlignment intervalAlignment) const
00083 {
00084
00085 bool newSource;
00086 DataContainer *s = d->requestSource(source, &newSource);
00087
00088 if (s) {
00089
00090
00091
00092
00093 d->connectSource(s, visualization, pollingInterval, intervalAlignment,
00094 !newSource || pollingInterval > 0);
00095
00096 }
00097 }
00098
00099 void DataEngine::connectAllSources(QObject *visualization, uint pollingInterval,
00100 Plasma::IntervalAlignment intervalAlignment) const
00101 {
00102 foreach (DataContainer *s, d->sources) {
00103 d->connectSource(s, visualization, pollingInterval, intervalAlignment);
00104 }
00105 }
00106
00107 void DataEngine::disconnectSource(const QString &source, QObject *visualization) const
00108 {
00109 DataContainer *s = d->source(source, false);
00110
00111 if (s) {
00112 s->disconnectVisualization(visualization);
00113 }
00114 }
00115
00116 DataContainer *DataEngine::containerForSource(const QString &source)
00117 {
00118 return d->source(source, false);
00119 }
00120
00121 DataEngine::Data DataEngine::query(const QString &source) const
00122 {
00123 bool newSource;
00124 DataContainer *s = d->requestSource(source, &newSource);
00125
00126 if (!s) {
00127 return DataEngine::Data();
00128 } else if (!newSource && d->minPollingInterval >= 0 &&
00129 s->timeSinceLastUpdate() >= uint(d->minPollingInterval)) {
00130 DataEngine *unconstThis = const_cast<DataEngine*>(this);
00131 if (unconstThis->updateSourceEvent(source)) {
00132 unconstThis->scheduleSourcesUpdated();
00133 }
00134 }
00135
00136 DataEngine::Data data = s->data();
00137 s->checkUsage();
00138 return data;
00139 }
00140
00141 void DataEngine::init()
00142 {
00143 if (d->script) {
00144 d->script->init();
00145 } else {
00146
00147
00148
00149 }
00150 }
00151
00152 bool DataEngine::sourceRequestEvent(const QString &name)
00153 {
00154 if (d->script) {
00155 return d->script->sourceRequestEvent(name);
00156 } else {
00157 return false;
00158 }
00159 }
00160
00161 bool DataEngine::updateSourceEvent(const QString &source)
00162 {
00163 if (d->script) {
00164 return d->script->updateSourceEvent(source);
00165 } else {
00166
00167 return false;
00168 }
00169 }
00170
00171 void DataEngine::setData(const QString &source, const QVariant &value)
00172 {
00173 setData(source, source, value);
00174 }
00175
00176 void DataEngine::setData(const QString &source, const QString &key, const QVariant &value)
00177 {
00178 DataContainer *s = d->source(source, false);
00179 bool isNew = !s;
00180
00181 if (isNew) {
00182 s = d->source(source);
00183 }
00184
00185 s->setData(key, value);
00186
00187 if (isNew) {
00188 emit sourceAdded(source);
00189 }
00190
00191 scheduleSourcesUpdated();
00192 }
00193
00194 void DataEngine::setData(const QString &source, const Data &data)
00195 {
00196 DataContainer *s = d->source(source, false);
00197 bool isNew = !s;
00198
00199 if (isNew) {
00200 s = d->source(source);
00201 }
00202
00203 Data::const_iterator it = data.constBegin();
00204 while (it != data.constEnd()) {
00205 s->setData(it.key(), it.value());
00206 ++it;
00207 }
00208
00209 if (isNew) {
00210 emit sourceAdded(source);
00211 }
00212
00213 scheduleSourcesUpdated();
00214 }
00215
00216 void DataEngine::removeAllData(const QString &source)
00217 {
00218 DataContainer *s = d->source(source, false);
00219 if (s) {
00220 s->removeAllData();
00221 scheduleSourcesUpdated();
00222 }
00223 }
00224
00225 void DataEngine::removeData(const QString &source, const QString &key)
00226 {
00227 DataContainer *s = d->source(source, false);
00228 if (s) {
00229 s->setData(key, QVariant());
00230 scheduleSourcesUpdated();
00231 }
00232 }
00233
00234 void DataEngine::addSource(DataContainer *source)
00235 {
00236 if (d->sources.contains(source->objectName())) {
00237 kDebug() << "source named \"" << source->objectName() << "\" already exists.";
00238 return;
00239 }
00240
00241 QObject::connect(source, SIGNAL(updateRequested(DataContainer*)),
00242 this, SLOT(internalUpdateSource(DataContainer*)));
00243 d->sources.insert(source->objectName(), source);
00244 emit sourceAdded(source->objectName());
00245 scheduleSourcesUpdated();
00246 }
00247
00248 void DataEngine::setMaxSourceCount(uint limit)
00249 {
00250 if (d->limit == limit) {
00251 return;
00252 }
00253
00254 d->limit = limit;
00255
00256 if (d->limit > 0) {
00257 d->trimQueue();
00258 } else {
00259 d->sourceQueue.clear();
00260 }
00261 }
00262
00263 uint DataEngine::maxSourceCount() const
00264 {
00265 return d->limit;
00266 }
00267
00268 void DataEngine::setMinimumPollingInterval(int minimumMs)
00269 {
00270 if (minimumMs < 0) {
00271 minimumMs = 0;
00272 }
00273
00274 d->minPollingInterval = minimumMs;
00275 }
00276
00277 int DataEngine::minimumPollingInterval() const
00278 {
00279 return d->minPollingInterval;
00280 }
00281
00282 void DataEngine::setPollingInterval(uint frequency)
00283 {
00284 killTimer(d->updateTimerId);
00285 d->updateTimerId = 0;
00286
00287 if (frequency > 0) {
00288 d->updateTimerId = startTimer(frequency);
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 void DataEngine::removeSource(const QString &source)
00304 {
00305
00306 SourceDict::iterator it = d->sources.find(source);
00307 if (it != d->sources.end()) {
00308 DataContainer *s = it.value();
00309
00310
00311 if (d->limit > 0) {
00312 QQueue<DataContainer*>::iterator it = d->sourceQueue.begin();
00313 while (it != d->sourceQueue.end()) {
00314 if (*it == s) {
00315 d->sourceQueue.erase(it);
00316 break;
00317 }
00318 ++it;
00319 }
00320 }
00321
00322 s->deleteLater();
00323 d->sources.erase(it);
00324 emit sourceRemoved(source);
00325 }
00326 }
00327
00328 void DataEngine::removeAllSources()
00329 {
00330 QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00331 while (it.hasNext()) {
00332 it.next();
00333 emit sourceRemoved(it.key());
00334 delete it.value();
00335 it.remove();
00336 }
00337 }
00338
00339 bool DataEngine::isValid() const
00340 {
00341 return d->valid;
00342 }
00343
00344 bool DataEngine::isEmpty() const
00345 {
00346 return d->sources.isEmpty();
00347 }
00348
00349 void DataEngine::setValid(bool valid)
00350 {
00351 d->valid = valid;
00352 }
00353
00354 DataEngine::SourceDict DataEngine::containerDict() const
00355 {
00356 return d->sources;
00357 }
00358
00359 void DataEngine::timerEvent(QTimerEvent *event)
00360 {
00361 if (event->timerId() == d->updateTimerId) {
00362
00363 if (d->minPollingInterval < 0) {
00364
00365 return;
00366 }
00367
00368
00369 if (d->updateTimestamp.elapsed() < d->minPollingInterval) {
00370
00371 return;
00372 }
00373
00374 d->updateTimestamp.restart();
00375 d->updateTimerId = 0;
00376 updateAllSources();
00377 } else if (event->timerId() == d->checkSourcesTimerId) {
00378 QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00379 while (it.hasNext()) {
00380 it.next();
00381 it.value()->checkForUpdate();
00382 }
00383
00384 killTimer(d->checkSourcesTimerId);
00385 d->checkSourcesTimerId = 0;
00386 } else {
00387 QObject::timerEvent(event);
00388 }
00389 }
00390
00391 void DataEngine::updateAllSources()
00392 {
00393 QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00394 while (it.hasNext()) {
00395 it.next();
00396
00397 updateSourceEvent(it.key());
00398 }
00399
00400 scheduleSourcesUpdated();
00401 }
00402
00403 void DataEngine::setIcon(const QString &icon)
00404 {
00405 d->icon = icon;
00406 }
00407
00408 QString DataEngine::icon() const
00409 {
00410 return d->icon;
00411 }
00412
00413 QString DataEngine::pluginName() const
00414 {
00415 if (!d->dataEngineDescription.isValid()) {
00416 return QString();
00417 }
00418
00419 return d->dataEngineDescription.pluginName();
00420 }
00421
00422 const Package *DataEngine::package() const
00423 {
00424 return d->package;
00425 }
00426
00427 void DataEngine::scheduleSourcesUpdated()
00428 {
00429 if (d->checkSourcesTimerId) {
00430 return;
00431 }
00432
00433 d->checkSourcesTimerId = startTimer(0);
00434 }
00435
00436 QString DataEngine::name() const
00437 {
00438 return d->engineName;
00439 }
00440
00441 void DataEngine::setName(const QString &name)
00442 {
00443 d->engineName = name;
00444 setObjectName(name);
00445 }
00446
00447
00448 DataEnginePrivate::DataEnginePrivate(DataEngine *e, KService::Ptr service)
00449 : q(e),
00450 dataEngineDescription(service),
00451 refCount(-1),
00452 checkSourcesTimerId(0),
00453 updateTimerId(0),
00454 minPollingInterval(-1),
00455 limit(0),
00456 valid(true),
00457 script(0),
00458 package(0)
00459 {
00460 updateTimestamp.start();
00461
00462 if (!service) {
00463 engineName = i18n("Unnamed");
00464 return;
00465 }
00466
00467 engineName = service->name();
00468 if (engineName.isEmpty()) {
00469 engineName = i18n("Unnamed");
00470 }
00471 e->setObjectName(engineName);
00472 icon = service->icon();
00473
00474 if (dataEngineDescription.isValid()) {
00475 QString api = dataEngineDescription.property("X-Plasma-API").toString();
00476
00477 if (!api.isEmpty()) {
00478 const QString path =
00479 KStandardDirs::locate("data",
00480 "plasma/dataengines/" + dataEngineDescription.pluginName() + '/');
00481 PackageStructure::Ptr structure =
00482 Plasma::packageStructure(api, Plasma::DataEngineComponent);
00483 structure->setPath(path);
00484 package = new Package(path, structure);
00485
00486 script = Plasma::loadScriptEngine(api, q);
00487 if (!script) {
00488 kDebug() << "Could not create a" << api << "ScriptEngine for the"
00489 << dataEngineDescription.name() << "DataEngine.";
00490 delete package;
00491 package = 0;
00492 }
00493 }
00494 }
00495 }
00496
00497 DataEnginePrivate::~DataEnginePrivate()
00498 {
00499 delete script;
00500 script = 0;
00501 delete package;
00502 package = 0;
00503 }
00504
00505 void DataEnginePrivate::internalUpdateSource(DataContainer *source)
00506 {
00507 if (minPollingInterval > 0 &&
00508 source->timeSinceLastUpdate() < (uint)minPollingInterval) {
00509
00510
00511
00512
00513
00514 source->setNeedsUpdate();
00515 return;
00516 }
00517
00518 if (q->updateSourceEvent(source->objectName())) {
00519
00520 q->scheduleSourcesUpdated();
00521 }
00522
00523
00524 }
00525
00526 void DataEnginePrivate::ref()
00527 {
00528 --refCount;
00529 }
00530
00531 void DataEnginePrivate::deref()
00532 {
00533 ++refCount;
00534 }
00535
00536 bool DataEnginePrivate::isUsed() const
00537 {
00538 return refCount != 0;
00539 }
00540
00541 DataContainer *DataEnginePrivate::source(const QString &sourceName, bool createWhenMissing)
00542 {
00543 DataEngine::SourceDict::const_iterator it = sources.constFind(sourceName);
00544 if (it != sources.constEnd()) {
00545 DataContainer *s = it.value();
00546 if (limit > 0) {
00547 QQueue<DataContainer*>::iterator it = sourceQueue.begin();
00548 while (it != sourceQueue.end()) {
00549 if (*it == s) {
00550 sourceQueue.erase(it);
00551 break;
00552 }
00553 ++it;
00554 }
00555 sourceQueue.enqueue(s);
00556 }
00557 return it.value();
00558 }
00559
00560 if (!createWhenMissing) {
00561 return 0;
00562 }
00563
00564
00565
00566
00567 DataContainer *s = new DataContainer(q);
00568 s->setObjectName(sourceName);
00569 sources.insert(sourceName, s);
00570 QObject::connect(s, SIGNAL(updateRequested(DataContainer*)),
00571 q, SLOT(internalUpdateSource(DataContainer*)));
00572
00573 if (limit > 0) {
00574 trimQueue();
00575 sourceQueue.enqueue(s);
00576 }
00577 return s;
00578 }
00579
00580 void DataEnginePrivate::connectSource(DataContainer *s, QObject *visualization,
00581 uint pollingInterval,
00582 Plasma::IntervalAlignment align,
00583 bool immediateCall)
00584 {
00585
00586 if (pollingInterval > 0) {
00587
00588 uint min = qMax(50, minPollingInterval);
00589 pollingInterval = qMax(min, pollingInterval);
00590
00591
00592 pollingInterval = pollingInterval - (pollingInterval % 50);
00593 }
00594
00595 if (immediateCall) {
00596
00597
00598
00599 immediateCall = !s->visualizationIsConnected(visualization);
00600 }
00601
00602 s->connectVisualization(visualization, pollingInterval, align);
00603
00604 if (immediateCall) {
00605 QMetaObject::invokeMethod(visualization, "dataUpdated",
00606 Q_ARG(QString, s->objectName()),
00607 Q_ARG(Plasma::DataEngine::Data, s->data()));
00608 }
00609 }
00610
00611 DataContainer *DataEnginePrivate::requestSource(const QString &sourceName, bool *newSource)
00612 {
00613 if (newSource) {
00614 *newSource = false;
00615 }
00616
00617
00618 DataContainer *s = source(sourceName, false);
00619
00620 if (!s) {
00621
00622
00623
00624
00625 if (q->sourceRequestEvent(sourceName)) {
00626 s = source(sourceName, false);
00627 if (s) {
00628
00629
00630 if (newSource) {
00631 *newSource = true;
00632 }
00633 QObject::connect(s, SIGNAL(becameUnused(QString)), q, SLOT(removeSource(QString)));
00634 }
00635 }
00636 }
00637
00638 return s;
00639 }
00640
00641 void DataEnginePrivate::trimQueue()
00642 {
00643 uint queueCount = sourceQueue.count();
00644 while (queueCount >= limit && !sourceQueue.isEmpty()) {
00645 DataContainer *punted = sourceQueue.dequeue();
00646 q->removeSource(punted->objectName());
00647 queueCount = sourceQueue.count();
00648 }
00649 }
00650
00651 }
00652
00653 #include "dataengine.moc"