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