00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "dataengine.h"
00021
00022 #include <QQueue>
00023 #include <QTimer>
00024 #include <QTime>
00025 #include <QTimerEvent>
00026 #include <QVariant>
00027
00028 #include <KDebug>
00029
00030 #include "datacontainer.h"
00031
00032 namespace Plasma
00033 {
00034
00035 class DataEngine::Private
00036 {
00037 public:
00038 Private(DataEngine* e)
00039 : engine(e),
00040 ref(0),
00041 updateTimerId(0),
00042 minUpdateInterval(-1),
00043 limit(0),
00044 valid(true)
00045 {
00046 updateTimer = new QTimer(engine);
00047 updateTimer->setSingleShot(true);
00048 updateTimestamp.start();
00049 }
00050
00051 DataContainer* source(const QString& sourceName, bool createWhenMissing = true)
00052 {
00053 DataEngine::SourceDict::const_iterator it = sources.find(sourceName);
00054 if (it != sources.constEnd()) {
00055 DataContainer* s = it.value();
00056 if (limit > 0) {
00057 QQueue<DataContainer*>::iterator it = sourceQueue.begin();
00058 while (it != sourceQueue.end()) {
00059 if (*it == s) {
00060 sourceQueue.erase(it);
00061 break;
00062 }
00063 ++it;
00064 }
00065 sourceQueue.enqueue(s);
00066 }
00067 return it.value();
00068 }
00069
00070 if (!createWhenMissing) {
00071 return 0;
00072 }
00073
00074
00075
00076
00077 DataContainer* s = new DataContainer(engine);
00078 s->setObjectName(sourceName);
00079 sources.insert(sourceName, s);
00080 connect(s, SIGNAL(requestUpdate(DataContainer*)), engine, SLOT(internalUpdateSource(DataContainer*)));
00081
00082 if (limit > 0) {
00083 trimQueue();
00084 sourceQueue.enqueue(s);
00085 }
00086 emit engine->newSource(sourceName);
00087 return s;
00088 }
00089
00090 void connectSource(DataContainer* s, QObject* visualization, uint updateInterval,
00091 Plasma::IntervalAlignment align, bool immediateCall = true)
00092 {
00093
00094 if (updateInterval > 0) {
00095
00096 uint min = qMax(50, minUpdateInterval);
00097 updateInterval = qMax(min, updateInterval);
00098
00099
00100 updateInterval = updateInterval - (updateInterval % 50);
00101 }
00102
00103 s->connectVisualization(visualization, updateInterval, align);
00104
00105 if (immediateCall) {
00106 QMetaObject::invokeMethod(visualization, "dataUpdated",
00107 Q_ARG(QString, s->objectName()),
00108 Q_ARG(Plasma::DataEngine::Data, s->data()));
00109 }
00110 }
00111
00112 DataContainer* requestSource(const QString& sourceName, bool* newSource = 0)
00113 {
00114 if (newSource) {
00115 *newSource = false;
00116 }
00117
00118
00119 DataContainer* s = source(sourceName, false);
00120
00121 if (!s) {
00122
00123
00124
00125
00126 if (engine->sourceRequested(sourceName)) {
00127 s = source(sourceName, false);
00128 if (s) {
00129
00130
00131 if (newSource) {
00132 *newSource = true;
00133 }
00134 connect(s, SIGNAL(unused(QString)), engine, SLOT(removeSource(QString)));
00135 }
00136 }
00137 }
00138
00139 return s;
00140 }
00141
00142 void trimQueue()
00143 {
00144 uint queueCount = sourceQueue.count();
00145 while (queueCount >= limit) {
00146 DataContainer* punted = sourceQueue.dequeue();
00147 engine->removeSource(punted->objectName());
00148 }
00149 }
00150
00151 void queueUpdate()
00152 {
00153 if (updateTimer->isActive()) {
00154 return;
00155 }
00156 updateTimer->start(0);
00157 }
00158
00159 DataEngine* engine;
00160 int ref;
00161 int updateTimerId;
00162 int minUpdateInterval;
00163 QTime updateTimestamp;
00164 DataEngine::SourceDict sources;
00165 QQueue<DataContainer*> sourceQueue;
00166 QTimer* updateTimer;
00167 QString icon;
00168 uint limit;
00169 bool valid;
00170 };
00171
00172
00173 DataEngine::DataEngine(QObject* parent)
00174 : QObject(parent),
00175 d(new Private(this))
00176 {
00177 connect(d->updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdates()));
00178
00179
00180 QTimer::singleShot(0, this, SLOT(startInit()));
00181 }
00182
00183 DataEngine::~DataEngine()
00184 {
00185
00186 delete d;
00187 }
00188
00189 QStringList DataEngine::sources() const
00190 {
00191 return d->sources.keys();
00192 }
00193
00194 void DataEngine::connectSource(const QString& source, QObject* visualization,
00195 uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const
00196 {
00197
00198 bool newSource;
00199 DataContainer* s = d->requestSource(source, &newSource);
00200
00201 if (s) {
00202
00203
00204
00205 d->connectSource(s, visualization, updateInterval, intervalAlignment, !newSource || updateInterval > 0);
00206
00207 }
00208 }
00209
00210 void DataEngine::connectAllSources(QObject* visualization, uint updateInterval,
00211 Plasma::IntervalAlignment intervalAlignment) const
00212 {
00213 foreach (DataContainer* s, d->sources) {
00214 d->connectSource(s, visualization, updateInterval, intervalAlignment);
00215 }
00216 }
00217
00218 void DataEngine::disconnectSource(const QString& source, QObject* visualization) const
00219 {
00220 DataContainer* s = d->source(source, false);
00221
00222 if (s) {
00223 s->disconnectVisualization(visualization);
00224 }
00225 }
00226
00227 DataContainer* DataEngine::containerForSource(const QString &source)
00228 {
00229 return d->source(source, false);
00230 }
00231
00232 DataEngine::Data DataEngine::query(const QString& source) const
00233 {
00234 DataContainer* s = d->requestSource(source);
00235
00236 if (!s) {
00237 return DataEngine::Data();
00238 }
00239
00240 DataEngine::Data data = s->data();
00241 s->checkUsage();
00242 return data;
00243 }
00244
00245 void DataEngine::startInit()
00246 {
00247 init();
00248 }
00249
00250 void DataEngine::internalUpdateSource(DataContainer* source)
00251 {
00252 if (d->minUpdateInterval > 0 &&
00253 source->timeSinceLastUpdate() < d->minUpdateInterval) {
00254
00255
00256
00257
00258
00259 source->setNeedsUpdate();
00260 return;
00261 }
00262
00263 if (updateSource(source->objectName())) {
00264 d->queueUpdate();
00265 }
00266 }
00267
00268 void DataEngine::init()
00269 {
00270
00271
00272
00273 }
00274
00275 bool DataEngine::sourceRequested(const QString &name)
00276 {
00277 Q_UNUSED(name)
00278 return false;
00279 }
00280
00281 bool DataEngine::updateSource(const QString& source)
00282 {
00283 Q_UNUSED(source);
00284
00285 return false;
00286 }
00287
00288 void DataEngine::setData(const QString& source, const QVariant& value)
00289 {
00290 setData(source, source, value);
00291 }
00292
00293 void DataEngine::setData(const QString& source, const QString& key, const QVariant& value)
00294 {
00295 DataContainer* s = d->source(source);
00296 s->setData(key, value);
00297 d->queueUpdate();
00298 }
00299
00300 void DataEngine::setData(const QString &source, const Data &data)
00301 {
00302 DataContainer *s = d->source(source);
00303 Data::const_iterator it = data.constBegin();
00304 while (it != data.constEnd()) {
00305 s->setData(it.key(), it.value());
00306 ++it;
00307 }
00308 d->queueUpdate();
00309 }
00310
00311
00312 void DataEngine::clearData(const QString& source)
00313 {
00314 DataContainer* s = d->source(source, false);
00315 if (s) {
00316 s->clearData();
00317 d->queueUpdate();
00318 }
00319 }
00320
00321 void DataEngine::removeData(const QString& source, const QString& key)
00322 {
00323 DataContainer* s = d->source(source, false);
00324 if (s) {
00325 s->setData(key, QVariant());
00326 d->queueUpdate();
00327 }
00328 }
00329
00330 void DataEngine::addSource(DataContainer* source)
00331 {
00332 SourceDict::const_iterator it = d->sources.find(source->objectName());
00333 if (it != d->sources.constEnd()) {
00334 kDebug() << "source named \"" << source->objectName() << "\" already exists.";
00335 return;
00336 }
00337
00338 d->sources.insert(source->objectName(), source);
00339 emit newSource(source->objectName());
00340 }
00341
00342 void DataEngine::setSourceLimit(uint limit)
00343 {
00344 if (d->limit == limit) {
00345 return;
00346 }
00347
00348 d->limit = limit;
00349
00350 if (d->limit > 0) {
00351 d->trimQueue();
00352 } else {
00353 d->sourceQueue.clear();
00354 }
00355 }
00356
00357 void DataEngine::setMinimumUpdateInterval(int minimumMs)
00358 {
00359 d->minUpdateInterval = minimumMs;
00360 }
00361
00362 int DataEngine::minimumUpdateInterval() const
00363 {
00364 return d->minUpdateInterval;
00365 }
00366
00367 void DataEngine::setUpdateInterval(uint frequency)
00368 {
00369 killTimer(d->updateTimerId);
00370 d->updateTimerId = 0;
00371
00372 if (frequency > 0) {
00373 d->updateTimerId = startTimer(frequency);
00374 }
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 void DataEngine::removeSource(const QString& source)
00389 {
00390
00391 SourceDict::iterator it = d->sources.find(source);
00392 if (it != d->sources.end()) {
00393 emit sourceRemoved(it.key());
00394 it.value()->deleteLater();
00395 d->sources.erase(it);
00396 }
00397 }
00398
00399 void DataEngine::clearSources()
00400 {
00401 QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00402 while (it.hasNext()) {
00403 it.next();
00404 emit sourceRemoved(it.key());
00405 delete it.value();
00406 it.remove();
00407 }
00408 }
00409
00410 void DataEngine::ref()
00411 {
00412 --d->ref;
00413 }
00414
00415 void DataEngine::deref()
00416 {
00417 ++d->ref;
00418 }
00419
00420 bool DataEngine::isUsed() const
00421 {
00422 return d->ref != 0;
00423 }
00424
00425 bool DataEngine::isValid() const
00426 {
00427 return d->valid;
00428 }
00429
00430 bool DataEngine::isEmpty() const
00431 {
00432 return d->sources.isEmpty();
00433 }
00434
00435 void DataEngine::setValid(bool valid)
00436 {
00437 d->valid = valid;
00438 }
00439
00440 DataEngine::SourceDict DataEngine::sourceDict() const
00441 {
00442 return d->sources;
00443 }
00444
00445 void DataEngine::timerEvent(QTimerEvent *event)
00446 {
00447 if (event->timerId() != d->updateTimerId) {
00448 return;
00449 }
00450
00451 event->accept();
00452
00453
00454 if (d->minUpdateInterval < 0) {
00455 return;
00456 }
00457
00458
00459 if (d->updateTimestamp.elapsed() < d->minUpdateInterval) {
00460 return;
00461 }
00462
00463 d->updateTimestamp.restart();
00464 QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00465 while (it.hasNext()) {
00466 it.next();
00467 updateSource(it.key());
00468 }
00469 checkForUpdates();
00470 }
00471
00472 void DataEngine::setIcon(const QString& icon)
00473 {
00474 d->icon = icon;
00475 }
00476
00477 QString DataEngine::icon() const
00478 {
00479 return d->icon;
00480 }
00481
00482 void DataEngine::checkForUpdates()
00483 {
00484 QHashIterator<QString, Plasma::DataContainer*> it(d->sources);
00485 while (it.hasNext()) {
00486 it.next();
00487 it.value()->checkForUpdate();
00488 }
00489 }
00490
00491 }
00492
00493 #include "dataengine.moc"