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 d->storageTimer.start(180000, this); 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) { 00196 return; 00197 } 00198 00199 q->setNeedsToBeStored(false); 00200 00201 if (!storage) { 00202 storage = new Storage(q); 00203 } 00204 00205 KConfigGroup op = storage->operationDescription("save"); 00206 op.writeEntry("group", q->objectName()); 00207 StorageJob *job = static_cast<StorageJob *>(storage->startOperationCall(op)); 00208 job->setData(data); 00209 storageCount++; 00210 QObject::connect(job, SIGNAL(finished(KJob*)), q, SLOT(storeJobFinished(KJob*))); 00211 } 00212 00213 void DataContainerPrivate::storeJobFinished(KJob* ) 00214 { 00215 --storageCount; 00216 if (storageCount < 1) { 00217 storage->deleteLater(); 00218 storage = 0; 00219 } 00220 } 00221 00222 void DataContainerPrivate::retrieve() 00223 { 00224 DataEngine* de = q->getDataEngine(); 00225 if (de == NULL) { 00226 return; 00227 } 00228 00229 if (!storage) { 00230 storage = new Storage(q); 00231 } 00232 00233 KConfigGroup retrieveGroup = storage->operationDescription("retrieve"); 00234 retrieveGroup.writeEntry("group", q->objectName()); 00235 ServiceJob* retrieveJob = storage->startOperationCall(retrieveGroup); 00236 QObject::connect(retrieveJob, SIGNAL(result(KJob*)), q, 00237 SLOT(populateFromStoredData(KJob*))); 00238 } 00239 00240 void DataContainerPrivate::populateFromStoredData(KJob *job) 00241 { 00242 if (job->error()) { 00243 return; 00244 } 00245 00246 StorageJob *ret = dynamic_cast<StorageJob*>(job); 00247 if (!ret) { 00248 return; 00249 } 00250 00251 // Only fill the source with old stored 00252 // data if it is not already populated with new data. 00253 if (data.isEmpty() && !ret->data().isEmpty()) { 00254 data = ret->data(); 00255 dirty = true; 00256 q->forceImmediateUpdate(); 00257 } 00258 00259 KConfigGroup expireGroup = storage->operationDescription("expire"); 00260 //expire things older than 4 days 00261 expireGroup.writeEntry("age", 345600); 00262 storage->startOperationCall(expireGroup); 00263 } 00264 00265 void DataContainer::disconnectVisualization(QObject *visualization) 00266 { 00267 QMap<QObject *, SignalRelay *>::iterator objIt = d->relayObjects.find(visualization); 00268 disconnect(visualization, SIGNAL(destroyed(QObject*)), 00269 this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection); 00270 00271 if (objIt == d->relayObjects.end() || !objIt.value()) { 00272 // it is connected directly to the DataContainer itself 00273 disconnect(this, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)), 00274 visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data))); 00275 } else { 00276 SignalRelay *relay = objIt.value(); 00277 00278 if (relay->receiverCount() == 1) { 00279 d->relays.remove(relay->m_interval); 00280 delete relay; 00281 } else { 00282 disconnect(relay, SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data)), 00283 visualization, SLOT(dataUpdated(QString,Plasma::DataEngine::Data))); 00284 } 00285 } 00286 00287 d->relayObjects.erase(objIt); 00288 checkUsage(); 00289 } 00290 00291 void DataContainer::checkForUpdate() 00292 { 00293 //kDebug() << objectName() << d->dirty; 00294 if (d->dirty) { 00295 emit dataUpdated(objectName(), d->data); 00296 00297 foreach (SignalRelay *relay, d->relays) { 00298 relay->checkQueueing(); 00299 } 00300 00301 d->dirty = false; 00302 } 00303 } 00304 00305 void DataContainer::forceImmediateUpdate() 00306 { 00307 if (d->dirty) { 00308 d->dirty = false; 00309 emit dataUpdated(objectName(), d->data); 00310 } 00311 00312 foreach (SignalRelay *relay, d->relays) { 00313 relay->forceImmediateUpdate(); 00314 } 00315 } 00316 00317 uint DataContainer::timeSinceLastUpdate() const 00318 { 00319 //FIXME: we still assume it's been <24h 00320 //and ignore possible daylight savings changes 00321 return d->updateTs.elapsed(); 00322 } 00323 00324 void DataContainer::setNeedsUpdate(bool update) 00325 { 00326 d->cached = update; 00327 } 00328 00329 void DataContainer::checkUsage() 00330 { 00331 if (!d->checkUsageTimer.isActive()) { 00332 d->checkUsageTimer.start(10, this); 00333 } 00334 } 00335 00336 void DataContainer::timerEvent(QTimerEvent * event) 00337 { 00338 if (event->timerId() == d->checkUsageTimer.timerId()) { 00339 if (d->relays.count() < 1 && 00340 receivers(SIGNAL(dataUpdated(QString,Plasma::DataEngine::Data))) < 1) { 00341 // DO NOT CALL ANYTHING AFTER THIS LINE AS IT MAY GET DELETED! 00342 kDebug() << objectName() << "is unused"; 00343 emit becameUnused(objectName()); 00344 } 00345 d->checkUsageTimer.stop(); 00346 } else if (event->timerId() == d->storageTimer.timerId()) { 00347 d->store(); 00348 d->storageTimer.stop(); 00349 } 00350 } 00351 00352 } // Plasma namespace 00353 00354 #include "datacontainer.moc" 00355
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:51:35 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:51:35 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.