move dataengine private details into the pimpl

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=802279
This commit is contained in:
Aaron J. Seigo 2008-04-29 01:17:12 +00:00
parent 4b0bc4fb5a
commit 13fcca652e
4 changed files with 288 additions and 241 deletions

View File

@ -18,6 +18,7 @@
*/
#include "dataengine.h"
#include "dataengine_p.h"
#include <QQueue>
#include <QTimer>
@ -37,186 +38,6 @@
namespace Plasma
{
class DataEngine::Private
{
public:
Private(DataEngine* e, KService::Ptr service)
: engine(e),
ref(-1), // first ref
updateTimerId(0),
minPollingInterval(-1),
limit(0),
valid(true),
script(0),
package(0)
{
updateTimer = new QTimer(engine);
updateTimer->setSingleShot(true);
updateTimestamp.start();
if (!service) {
return;
}
engineName = service->property("X-Plasma-EngineName").toString();
if (engineName.isEmpty()) {
engineName = i18n("Anonymous Engine");
}
e->setObjectName(engineName);
icon = service->icon();
KPluginInfo dataEngineDescription(service);
if (dataEngineDescription.isValid()) {
QString language = dataEngineDescription.property("X-Plasma-Language").toString();
if (!language.isEmpty()) {
const QString path = KStandardDirs::locate("data",
"plasma/engines/" + dataEngineDescription.pluginName() + "/");
PackageStructure::Ptr structure = Plasma::packageStructure(language, Plasma::RunnerComponent);
structure->setPath(path);
package = new Package(path, structure);
script = Plasma::loadScriptEngine(language, engine);
if (!script) {
kDebug() << "Could not create a" << language << "ScriptEngine for the"
<< dataEngineDescription.name() << "DataEngine.";
delete package;
package = 0;
}
}
}
}
DataContainer* source(const QString& sourceName, bool createWhenMissing = true)
{
DataEngine::SourceDict::const_iterator it = sources.find(sourceName);
if (it != sources.constEnd()) {
DataContainer* s = it.value();
if (limit > 0) {
QQueue<DataContainer*>::iterator it = sourceQueue.begin();
while (it != sourceQueue.end()) {
if (*it == s) {
sourceQueue.erase(it);
break;
}
++it;
}
sourceQueue.enqueue(s);
}
return it.value();
}
if (!createWhenMissing) {
return 0;
}
/*kDebug() << "DataEngine " << engine->objectName()
<< ": could not find DataContainer " << sourceName
<< ", creating" << endl;*/
DataContainer* s = new DataContainer(engine);
s->setObjectName(sourceName);
sources.insert(sourceName, s);
connect(s, SIGNAL(updateRequested(DataContainer*)), engine, SLOT(internalUpdateSource(DataContainer*)));
if (limit > 0) {
trimQueue();
sourceQueue.enqueue(s);
}
return s;
}
void connectSource(DataContainer* s, QObject* visualization, uint pollingInterval,
Plasma::IntervalAlignment align, bool immediateCall = true)
{
//kDebug() << "connect source called with interval" << pollingInterval;
if (pollingInterval > 0) {
// never more frequently than allowed, never more than 20 times per second
uint min = qMax(50, minPollingInterval); // for qMin below
pollingInterval = qMax(min, pollingInterval);
// align on the 50ms
pollingInterval = pollingInterval - (pollingInterval % 50);
}
if (immediateCall) {
// we don't want to do an immediate call if we are simply
// reconnecting
//kDebug() << "immediate call requested, we have:" << s->visualizationIsConnected(visualization);
immediateCall = !s->visualizationIsConnected(visualization);
}
s->connectVisualization(visualization, pollingInterval, align);
if (immediateCall) {
QMetaObject::invokeMethod(visualization, "dataUpdated",
Q_ARG(QString, s->objectName()),
Q_ARG(Plasma::DataEngine::Data, s->data()));
}
}
DataContainer* requestSource(const QString& sourceName, bool* newSource = 0)
{
if (newSource) {
*newSource = false;
}
//kDebug() << "requesting source " << sourceName;
DataContainer* s = source(sourceName, false);
if (!s) {
// we didn't find a data source, so give the engine an opportunity to make one
/*kDebug() << "DataEngine " << engine->objectName()
<< ": could not find DataContainer " << sourceName
<< " will create on request" << endl;*/
if (engine->sourceRequestEvent(sourceName)) {
s = source(sourceName, false);
if (s) {
// now we have a source; since it was created on demand, assume
// it should be removed when not used
if (newSource) {
*newSource = true;
}
connect(s, SIGNAL(becameUnused(QString)), engine, SLOT(removeSource(QString)));
}
}
}
return s;
}
void trimQueue()
{
uint queueCount = sourceQueue.count();
while (queueCount >= limit) {
DataContainer* punted = sourceQueue.dequeue();
engine->removeSource(punted->objectName());
}
}
void queueUpdate()
{
if (updateTimer->isActive()) {
return;
}
updateTimer->start(0);
}
DataEngine* engine;
int ref;
int updateTimerId;
int minPollingInterval;
QTime updateTimestamp;
DataEngine::SourceDict sources;
QQueue<DataContainer*> sourceQueue;
QTimer* updateTimer;
QString icon;
uint limit;
bool valid;
DataEngineScript* script;
QString engineName;
Package *package;
};
DataEngine::DataEngine(QObject* parent, KService::Ptr service)
: QObject(parent),
@ -294,24 +115,6 @@ DataEngine::Data DataEngine::query(const QString& source) const
return data;
}
void DataEngine::internalUpdateSource(DataContainer* source)
{
if (d->minPollingInterval > 0 &&
source->timeSinceLastUpdate() < (uint)d->minPollingInterval) {
// skip updating this source; it's been too soon
//kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << d->minPollingInterval;
//but fake an update so that the signalrelay that triggered this gets the data from the
//recent update. this way we don't have to worry about queuing - the relay will send a
//signal immediately and everyone else is undisturbed.
source->setNeedsUpdate();
return;
}
if (updateSourceEvent(source->objectName())) {
d->queueUpdate();
}
}
void DataEngine::init()
{
if (d->script) {
@ -504,21 +307,6 @@ void DataEngine::removeAllSources()
}
}
void DataEngine::ref()
{
--d->ref;
}
void DataEngine::deref()
{
++d->ref;
}
bool DataEngine::isUsed() const
{
return d->ref != 0;
}
bool DataEngine::isValid() const
{
return d->valid;
@ -601,6 +389,203 @@ void DataEngine::setName(const QString& name)
setObjectName(name);
}
// Private class implementations
DataEngine::Private::Private(DataEngine* e, KService::Ptr service)
: q(e),
refCount(-1), // first ref
updateTimerId(0),
minPollingInterval(-1),
limit(0),
valid(true),
script(0),
package(0)
{
updateTimer = new QTimer(q);
updateTimer->setSingleShot(true);
updateTimestamp.start();
if (!service) {
return;
}
engineName = service->property("X-Plasma-EngineName").toString();
if (engineName.isEmpty()) {
engineName = i18n("Anonymous Engine");
}
e->setObjectName(engineName);
icon = service->icon();
KPluginInfo dataEngineDescription(service);
if (dataEngineDescription.isValid()) {
QString language = dataEngineDescription.property("X-Plasma-Language").toString();
if (!language.isEmpty()) {
const QString path = KStandardDirs::locate("data",
"plasma/engines/" + dataEngineDescription.pluginName() + "/");
PackageStructure::Ptr structure = Plasma::packageStructure(language, Plasma::RunnerComponent);
structure->setPath(path);
package = new Package(path, structure);
script = Plasma::loadScriptEngine(language, q);
if (!script) {
kDebug() << "Could not create a" << language << "ScriptEngine for the"
<< dataEngineDescription.name() << "DataEngine.";
delete package;
package = 0;
}
}
}
}
void DataEngine::Private::internalUpdateSource(DataContainer* source)
{
if (minPollingInterval > 0 &&
source->timeSinceLastUpdate() < (uint)minPollingInterval) {
// skip updating this source; it's been too soon
//kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << d->minPollingInterval;
//but fake an update so that the signalrelay that triggered this gets the data from the
//recent update. this way we don't have to worry about queuing - the relay will send a
//signal immediately and everyone else is undisturbed.
source->setNeedsUpdate();
return;
}
if (q->updateSourceEvent(source->objectName())) {
queueUpdate();
}
}
void DataEngine::Private::ref()
{
--refCount;
}
void DataEngine::Private::deref()
{
++refCount;
}
bool DataEngine::Private::isUsed() const
{
return refCount != 0;
}
DataContainer* DataEngine::Private::source(const QString& sourceName, bool createWhenMissing)
{
DataEngine::SourceDict::const_iterator it = sources.find(sourceName);
if (it != sources.constEnd()) {
DataContainer* s = it.value();
if (limit > 0) {
QQueue<DataContainer*>::iterator it = sourceQueue.begin();
while (it != sourceQueue.end()) {
if (*it == s) {
sourceQueue.erase(it);
break;
}
++it;
}
sourceQueue.enqueue(s);
}
return it.value();
}
if (!createWhenMissing) {
return 0;
}
/*kDebug() << "DataEngine " << q->objectName()
<< ": could not find DataContainer " << sourceName
<< ", creating" << endl;*/
DataContainer* s = new DataContainer(q);
s->setObjectName(sourceName);
sources.insert(sourceName, s);
connect(s, SIGNAL(updateRequested(DataContainer*)),
q, SLOT(internalUpdateSource(DataContainer*)));
if (limit > 0) {
trimQueue();
sourceQueue.enqueue(s);
}
return s;
}
void DataEngine::Private::connectSource(DataContainer* s, QObject* visualization,
uint pollingInterval,
Plasma::IntervalAlignment align, bool immediateCall)
{
//kDebug() << "connect source called with interval" << pollingInterval;
if (pollingInterval > 0) {
// never more frequently than allowed, never more than 20 times per second
uint min = qMax(50, minPollingInterval); // for qMin below
pollingInterval = qMax(min, pollingInterval);
// align on the 50ms
pollingInterval = pollingInterval - (pollingInterval % 50);
}
if (immediateCall) {
// we don't want to do an immediate call if we are simply
// reconnecting
//kDebug() << "immediate call requested, we have:" << s->visualizationIsConnected(visualization);
immediateCall = !s->visualizationIsConnected(visualization);
}
s->connectVisualization(visualization, pollingInterval, align);
if (immediateCall) {
QMetaObject::invokeMethod(visualization, "dataUpdated",
Q_ARG(QString, s->objectName()),
Q_ARG(Plasma::DataEngine::Data, s->data()));
}
}
DataContainer* DataEngine::Private::requestSource(const QString& sourceName, bool* newSource)
{
if (newSource) {
*newSource = false;
}
//kDebug() << "requesting source " << sourceName;
DataContainer* s = source(sourceName, false);
if (!s) {
// we didn't find a data source, so give the engine an opportunity to make one
/*kDebug() << "DataEngine " << q->objectName()
<< ": could not find DataContainer " << sourceName
<< " will create on request" << endl;*/
if (q->sourceRequestEvent(sourceName)) {
s = source(sourceName, false);
if (s) {
// now we have a source; since it was created on demand, assume
// it should be removed when not used
if (newSource) {
*newSource = true;
}
connect(s, SIGNAL(becameUnused(QString)), q, SLOT(removeSource(QString)));
}
}
}
return s;
}
void DataEngine::Private::trimQueue()
{
uint queueCount = sourceQueue.count();
while (queueCount >= limit) {
DataContainer* punted = sourceQueue.dequeue();
q->removeSource(punted->objectName());
}
}
void DataEngine::Private::queueUpdate()
{
if (updateTimer->isActive()) {
return;
}
updateTimer->start(0);
}
}
#include "dataengine.moc"

View File

@ -56,6 +56,7 @@ class PLASMA_EXPORT DataEngine : public QObject
friend class DataEngineScript;
friend class DataEngineManager;
friend class NullEngine;
Q_OBJECT
Q_PROPERTY( QStringList sources READ sources )
Q_PROPERTY( bool valid READ isValid )
@ -409,30 +410,8 @@ class PLASMA_EXPORT DataEngine : public QObject
**/
void removeSource(const QString& source);
/**
* @internal
**/
void internalUpdateSource(DataContainer* source);
private:
/**
* Reference counting method. Calling this method increases the count
* by one.
**/
void ref();
/**
* Reference counting method. Calling this method decreases the count
* by one.
**/
void deref();
/**
* Reference counting method. Used to determine if this DataEngine is
* used.
* @return true if the reference count is non-zero
**/
bool isUsed() const;
Q_PRIVATE_SLOT(d, void internalUpdateSource(DataContainer* source))
class Private;
Private* const d;

81
dataengine_p.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DATAENGINE_P_H
#define DATAENGINE_P_H
#include <QQueue>
#include <QTime>
class QTime;
namespace Plasma
{
class DataEngine::Private
{
public:
Private(DataEngine* e, KService::Ptr service);
DataContainer* source(const QString& sourceName, bool createWhenMissing = true);
void connectSource(DataContainer* s, QObject* visualization, uint pollingInterval,
Plasma::IntervalAlignment align, bool immediateCall = true);
DataContainer* requestSource(const QString& sourceName, bool* newSource = 0);
void trimQueue();
void queueUpdate();
void internalUpdateSource(DataContainer*);
/**
* Reference counting method. Calling this method increases the count
* by one.
**/
void ref();
/**
* Reference counting method. Calling this method decreases the count
* by one.
**/
void deref();
/**
* Reference counting method. Used to determine if this DataEngine is
* used.
* @return true if the reference count is non-zero
**/
bool isUsed() const;
DataEngine* q;
int refCount;
int updateTimerId;
int minPollingInterval;
QTime updateTimestamp;
DataEngine::SourceDict sources;
QQueue<DataContainer*> sourceQueue;
QTimer* updateTimer;
QString icon;
uint limit;
bool valid;
DataEngineScript* script;
QString engineName;
Package *package;
};
} // Plasma namespace
#endif // multiple inclusion guard

View File

@ -18,11 +18,13 @@
*/
#include "dataenginemanager.h"
#include "scripting/scriptengine.h"
#include <KDebug>
#include <KServiceTypeTrader>
#include "dataengine_p.h"
#include "scripting/scriptengine.h"
namespace Plasma
{
@ -36,7 +38,7 @@ class NullEngine : public DataEngine
setValid(false);
// ref() ourselves to ensure we never get deleted
ref();
d->ref();
}
};
@ -111,7 +113,7 @@ Plasma::DataEngine* DataEngineManager::loadEngine(const QString& name)
if (it != d->engines.end()) {
engine = *it;
engine->ref();
engine->d->ref();
return engine;
}
@ -150,9 +152,9 @@ void DataEngineManager::unloadEngine(const QString& name)
if (it != d->engines.end()) {
Plasma::DataEngine* engine = *it;
engine->deref();
engine->d->deref();
if (!engine->isUsed()) {
if (!engine->d->isUsed()) {
d->engines.erase(it);
delete engine;
}