• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

dataengine.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
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             /*kDebug() << "DataEngine " << engine->objectName()
00075                      << ": could not find DataContainer " << sourceName
00076                      << ", creating" << endl;*/
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             //kDebug() << "connect source called with interval" << updateInterval;
00094             if (updateInterval > 0) {
00095                 // never more frequently than allowed, never more than 20 times per second
00096                 uint min = qMax(50, minUpdateInterval); // for qMin below
00097                 updateInterval = qMax(min, updateInterval);
00098 
00099                 // align on the 50ms
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             //kDebug() << "requesting source " << sourceName;
00119             DataContainer* s = source(sourceName, false);
00120 
00121             if (!s) {
00122                 // we didn't find a data source, so give the engine an opportunity to make one
00123                 /*kDebug() << "DataEngine " << engine->objectName()
00124                     << ": could not find DataContainer " << sourceName
00125                     << " will create on request" << endl;*/
00126                 if (engine->sourceRequested(sourceName)) {
00127                     s = source(sourceName, false);
00128                     if (s) {
00129                         // now we have a source; since it was created on demand, assume
00130                         // it should be removed when not used
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     //FIXME: we should delay this call; to when is the question.
00179     //Update DataEngine::init() api docu when fixed
00180     QTimer::singleShot(0, this, SLOT(startInit()));
00181 }
00182 
00183 DataEngine::~DataEngine()
00184 {
00185     //kDebug() << objectName() << ": bye bye birdy! ";
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     //kDebug() << "connectSource" << source;
00198     bool newSource;
00199     DataContainer* s = d->requestSource(source, &newSource);
00200 
00201     if (s) {
00202         // we suppress the immediate invocation of dataUpdated here if the source was prexisting and they
00203         // don't request delayed updates (we want to do an immediate update in that case so they
00204         // don't have to wait for the first time out)
00205         d->connectSource(s, visualization, updateInterval, intervalAlignment, !newSource || updateInterval > 0);
00206         //kDebug() << " ==> source connected";
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         // skip updating this source; it's been too soon
00255         //kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << d->minUpdateInterval;
00256         //but fake an update so that the signalrelay that triggered this gets the data from the
00257         //recent update. this way we don't have to worry about queuing - the relay will send a
00258         //signal immediately and everyone else is undisturbed.
00259         source->setNeedsUpdate();
00260         return;
00261     }
00262 
00263     if (updateSource(source->objectName())) {
00264         d->queueUpdate();
00265     }
00266 }
00267 
00268 void DataEngine::init()
00269 {
00270     // kDebug() << "DataEngine::init() called ";
00271     // default implementation does nothing. this is for engines that have to
00272     // start things in motion external to themselves before they can work
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     //kDebug() << "updateSource source" << endl;
00285     return false; //TODO: should this be true to trigger, even needless, updates on every tick?
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 NOTE: This is not implemented to prevent having to store the value internally.
00379       When there is a good use case for needing access to this value, we can
00380       add another member to the Private class and add this method.
00381 
00382 void DataEngine::updateInterval()
00383 {
00384     return d->updateInterval;
00385 }
00386 */
00387 
00388 void DataEngine::removeSource(const QString& source)
00389 {
00390     //kDebug() << "removing source " << source;
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     // if the freq update is less than 0, don't bother
00454     if (d->minUpdateInterval < 0) {
00455         return;
00456     }
00457 
00458     // minUpdateInterval
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"

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal