• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Plasma

datacontainer.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 #include "datacontainer.h"
00020 #include "private/datacontainer_p.h"
00021 #include "private/storage_p.h"
00022 
00023 #include <kdebug.h>
00024 
00025 #include "plasma.h"
00026 
00027 namespace Plasma
00028 {
00029 
00030 DataContainer::DataContainer(QObject *parent)
00031     : QObject(parent),
00032       d(new DataContainerPrivate(this))
00033 {
00034 }
00035 
00036 DataContainer::~DataContainer()
00037 {
00038     delete d;
00039 }
00040 
00041 const DataEngine::Data DataContainer::data() const
00042 {
00043     return d->data;
00044 }
00045 
00046 void DataContainer::setData(const QString &key, const QVariant &value)
00047 {
00048     if (!value.isValid()) {
00049         d->data.remove(key);
00050     } else {
00051         d->data.insert(key, value);
00052     }
00053 
00054     d->dirty = true;
00055     d->updateTs.start();
00056 
00057     //check if storage is enabled and if storage is needed.
00058     //If it is not set to be stored,then this is the first
00059     //setData() since the last time it was stored. This
00060     //gives us only one singleShot timer.
00061     if (isStorageEnabled() || !needsToBeStored()) {
00062         QTimer::singleShot(180000, this, SLOT(store()));
00063     }
00064 
00065     setNeedsToBeStored(true);
00066 }
00067 
00068 void DataContainer::removeAllData()
00069 {
00070     if (d->data.isEmpty()) {
00071         // avoid an update if we don't have any data anyways
00072         return;
00073     }
00074 
00075     d->data.clear();
00076     d->dirty = true;
00077     d->updateTs.start();
00078 }
00079 
00080 bool DataContainer::visualizationIsConnected(QObject *visualization) const
00081 {
00082     return d->relayObjects.contains(visualization);
00083 }
00084 
00085 void DataContainer::connectVisualization(QObject *visualization, uint pollingInterval,
00086                                          Plasma::IntervalAlignment alignment)
00087 {
00088     //kDebug() << "connecting visualization" << visualization << "at interval of"
00089     //         << pollingInterval << "to" << objectName();
00090     QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
00091     bool connected = objIt != d->relayObjects.end();
00092     if (connected) {
00093         // this visualization is already connected. just adjust the update
00094         // frequency if necessary
00095         SignalRelay *relay = objIt.value();
00096         if (relay) {
00097             // connected to a relay
00098             //kDebug() << "     already connected, but to a relay";
00099             if (relay->m_interval == pollingInterval) {
00100                 //kDebug() << "    already connected to a relay of the same interval of"
00101                 //          << pollingInterval << ", nothing to do";
00102                 return;
00103             }
00104 
00105             if (relay->receiverCount() == 1) {
00106                 //kDebug() << "    removing relay, as it is now unused";
00107                 d->relays.remove(relay->m_interval);
00108                 delete relay;
00109             } else {
00110                 disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00111                            visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00112                 //relay->isUnused();
00113             }
00114         } else if (pollingInterval < 1) {
00115             // the visualization was connected already, but not to a relay
00116             // and it still doesn't want to connect to a relay, so we have
00117             // nothing to do!
00118             //kDebug() << "     already connected, nothing to do";
00119             return;
00120         } else {
00121             disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00122                        visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00123         }
00124     } else {
00125         connect(visualization, SIGNAL(destroyed(QObject*)),
00126                 this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
00127     }
00128 
00129     if (pollingInterval < 1) {
00130         //kDebug() << "    connecting directly";
00131         d->relayObjects[visualization] = 0;
00132         connect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00133                 visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00134     } else {
00135         //kDebug() << "    connecting to a relay";
00136         // we only want to do an imediate update if this is not the first object to connect to us
00137         // if it is the first visualization, then the source will already have been populated
00138         // engine's sourceRequested method
00139         bool immediateUpdate = connected || d->relayObjects.count() > 1;
00140         SignalRelay *relay = d->signalRelay(this, visualization, pollingInterval,
00141                                             alignment, immediateUpdate);
00142         connect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00143                 visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00144     }
00145 }
00146 
00147 void DataContainer::setStorageEnabled(bool store)
00148 {
00149     QTime time = QTime::currentTime();
00150     qsrand((uint)time.msec());
00151     d->enableStorage = store;
00152     if (store) {
00153         QTimer::singleShot(qrand() % (2000 + 1) , this, SLOT(retrieve()));
00154     }
00155 }
00156 
00157 bool DataContainer::isStorageEnabled() const
00158 {
00159     return d->enableStorage;
00160 }
00161 
00162 bool DataContainer::needsToBeStored() const
00163 {
00164     return !d->isStored;
00165 }
00166 
00167 void DataContainer::setNeedsToBeStored(bool store)
00168 {
00169     d->isStored = !store;
00170 }
00171 
00172 DataEngine* DataContainer::getDataEngine()
00173 {
00174     QObject *o = NULL;
00175     DataEngine *de = NULL;
00176     o = this;
00177     while (de == NULL)
00178     {
00179         o = dynamic_cast<QObject *> (o->parent());
00180         if (o == NULL) {
00181             return NULL;
00182         }
00183         de = dynamic_cast<DataEngine *> (o);
00184     }
00185     return de;
00186 }
00187 
00188 void DataContainerPrivate::store()
00189 {
00190     if (!q->needsToBeStored() || !q->isStorageEnabled()){
00191         return;
00192     }
00193 
00194     DataEngine* de = q->getDataEngine();
00195     if (de == NULL) {
00196         return;
00197     }
00198 
00199     q->setNeedsToBeStored(false);
00200 
00201     if (storage == NULL) {
00202         storage = new Storage(q);
00203     }
00204 
00205     KConfigGroup op = storage->operationDescription("save");
00206     op.writeEntry("group", q->objectName());
00207     DataEngine::Data dataToStore = q->data();
00208     DataEngine::Data::const_iterator it = dataToStore.constBegin();
00209     while (it != dataToStore.constEnd() && dataToStore.constEnd() == q->data().constEnd()) {
00210         QVariant v = it.value();
00211         if ((it.value().type() == QVariant::String) || (it.value().type() == QVariant::Int)) {
00212             op.writeEntry("key", it.key());
00213             op.writeEntry("data", it.value());
00214         } else {
00215             QByteArray b;
00216             QDataStream ds(&b, QIODevice::WriteOnly);
00217             ds << it.value();
00218             op.writeEntry("key", QString(QLatin1String("base64-") + it.key()));
00219             op.writeEntry("data", b.toBase64());
00220         }
00221         ++it;
00222         if (storage == NULL) {
00223             storage = new Storage(q);
00224         }
00225         ServiceJob* job = storage->startOperationCall(op);
00226         storageCount++;
00227         QObject::connect(job, SIGNAL(finished(KJob*)), q, SLOT(storeJobFinished(KJob*)));
00228     }
00229 }
00230 
00231 void DataContainerPrivate::storeJobFinished(KJob* )
00232 {
00233     --storageCount;
00234     if (storageCount < 1) {
00235         storage->deleteLater();
00236         storage = 0;
00237     }
00238 }
00239 
00240 void DataContainerPrivate::retrieve()
00241 {
00242     DataEngine* de = q->getDataEngine();
00243     if (de == NULL) {
00244         return;
00245     }
00246     if (!storage) {
00247         storage = new Storage(q);
00248     }
00249 
00250     KConfigGroup retrieveGroup = storage->operationDescription("retrieve");
00251     retrieveGroup.writeEntry("group", q->objectName());
00252     ServiceJob* retrieveJob = storage->startOperationCall(retrieveGroup);
00253     QObject::connect(retrieveJob, SIGNAL(result(KJob*)), q,
00254             SLOT(populateFromStoredData(KJob*)));
00255 }
00256 
00257 void DataContainerPrivate::populateFromStoredData(KJob *job)
00258 {
00259     if (job->error()) {
00260         return;
00261     }
00262 
00263     DataEngine::Data dataToInsert;
00264     ServiceJob* ret = dynamic_cast<ServiceJob*>(job);
00265     const QHash<QString, QVariant> h = ret->result().toHash();
00266     QHash<QString, QVariant>::const_iterator it = h.begin();
00267     QHash<QString, QVariant>::const_iterator itEnd = h.end();
00268     for ( ; it != itEnd; ++it) {
00269         QString key = it.key();
00270         if (key.startsWith("base64-")) {
00271             QByteArray b = QByteArray::fromBase64(it.value().toString().toAscii());
00272             QDataStream ds(&b, QIODevice::ReadOnly);
00273             QVariant v(ds);
00274             key.remove(0, 7);
00275             dataToInsert.insert(key, v);
00276         } else {
00277             dataToInsert.insert(key, it.value());
00278         }
00279     }
00280 
00281     KConfigGroup expireGroup = storage->operationDescription("expire");
00282     //expire things older than 4 days
00283     expireGroup.writeEntry("age", 345600);
00284     storage->startOperationCall(expireGroup);
00285 
00286     if (!(data.isEmpty())) {
00287         //Do not fill the source with old stored
00288         //data if it is already populated with new data.
00289         return;
00290     }
00291 
00292     data = dataToInsert;
00293     dirty = true;
00294     q->checkForUpdate();
00295 }
00296 
00297 void DataContainer::disconnectVisualization(QObject *visualization)
00298 {
00299     QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization);
00300     disconnect(visualization, SIGNAL(destroyed(QObject*)),
00301               this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
00302 
00303     if (objIt == d->relayObjects.end() || !objIt.value()) {
00304         // it is connected directly to the DataContainer itself
00305         disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00306                    visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00307     } else {
00308         SignalRelay *relay = objIt.value();
00309 
00310         if (relay->receiverCount() == 1) {
00311             d->relays.remove(relay->m_interval);
00312             delete relay;
00313         } else {
00314             disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)),
00315                        visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data)));
00316         }
00317     }
00318 
00319     d->relayObjects.erase(objIt);
00320     checkUsage();
00321 }
00322 
00323 void DataContainer::checkForUpdate()
00324 {
00325     //kDebug() << objectName() << d->dirty;
00326     if (d->dirty) {
00327         emit dataUpdated(objectName(), d->data);
00328 
00329         foreach (SignalRelay *relay, d->relays) {
00330             relay->checkQueueing();
00331         }
00332 
00333         d->dirty = false;
00334     }
00335 }
00336 
00337 void DataContainer::forceImmediateUpdate()
00338 {
00339     if (d->dirty) {
00340         d->dirty = false;
00341         emit dataUpdated(objectName(), d->data);
00342     }
00343 
00344     foreach (SignalRelay *relay, d->relays) {
00345         relay->forceImmediateUpdate();
00346     }
00347 }
00348 
00349 uint DataContainer::timeSinceLastUpdate() const
00350 {
00351     //FIXME: we still assume it's been <24h
00352     //and ignore possible daylight savings changes
00353     return d->updateTs.elapsed();
00354 }
00355 
00356 void DataContainer::setNeedsUpdate(bool update)
00357 {
00358     d->cached = update;
00359 }
00360 
00361 void DataContainer::checkUsage()
00362 {
00363     if (d->relays.count() < 1 &&
00364         receivers(SIGNAL(dataUpdated(QString, Plasma::DataEngine::Data))) < 1) {
00365         // DO NOT CALL ANYTHING AFTER THIS LINE AS IT MAY GET DELETED!
00366         kDebug() << objectName() << "is unused";
00367         emit becameUnused(objectName());
00368     }
00369 }
00370 
00371 } // Plasma namespace
00372 
00373 #include "datacontainer.moc"
00374 

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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