plasma-framework/scriptengines/javascript/simplebindings/dataenginereceiver.cpp
Aaron Seigo da186219ae give connectAllSources the same magic sauce connectSource does
thanks to emilsedgh for having the special super power of using precisely
what hasn't been properly implemented ... and then reporting it with
nice simple examples we can test with! THAT, my friends, is how it is done.
2011-04-04 14:43:40 +02:00

227 lines
6.9 KiB
C++

/*
* Copyright 2010 Aaron J. 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 version 2 as
* published by the Free Software Foundation
*
* 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.
*/
#include "dataenginereceiver.h"
#include <QScriptEngine>
#include "dataengine.h"
#include "scriptenv.h"
QSet<DataEngineReceiver*> DataEngineReceiver::s_receivers;
DataEngineReceiver::DataEngineReceiver(const Plasma::DataEngine *engine, const QString &source, const QScriptValue &func, QObject *parent)
: QObject(parent),
m_engine(engine),
m_source(source),
m_func(func),
m_obj(m_func)
{
s_receivers.insert(this);
if (!m_func.isFunction()) {
QScriptValue func = m_func.property("dataUpdated");
if (func.isFunction()) {
m_func = func;
} else {
m_obj = QScriptValue();
}
}
}
DataEngineReceiver::~DataEngineReceiver()
{
s_receivers.remove(this);
//kDebug() << s_receivers.count();
}
bool DataEngineReceiver::isValid() const
{
return m_obj.isValid();
}
bool DataEngineReceiver::matches(const Plasma::DataEngine *engine, const QString &source, const QScriptValue &v)
{
return engine == m_engine && m_source == source && v.equals(m_obj);
}
void DataEngineReceiver::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
{
QScriptEngine *engine = m_func.engine();
// QScriptValue appletValue = engine->globalObject().property("plasmoid");
QScriptValueList args;
args << source;
args << qScriptValueFromMap<Plasma::DataEngine::Data>(engine, data);
m_func.call(m_obj, args);
if (engine->hasUncaughtException()) {
ScriptEnv *env = ScriptEnv::findScriptEnv(engine);
env->checkForErrors(false);
}
}
DataEngineReceiver *DataEngineReceiver::getReceiver(Plasma::DataEngine *dataEngine, const QString &source, const QScriptValue &v)
{
foreach (DataEngineReceiver *receiver, DataEngineReceiver::s_receivers) {
if (receiver->matches(dataEngine, source, v)) {
return receiver;
}
}
return 0;
}
QObject *DataEngineReceiver::extractTargetQObject(QScriptEngine *engine, const QString &source, const QScriptValue &v, Plasma::DataEngine *dataEngine)
{
QObject *obj = 0;
// if it's a function we get, then use that directly
// next see if it is a qobject with a good slot; if it is then use that directly
// otherwise, try to use the object with a dataUpdated method call
if (v.isFunction()) {
obj = getReceiver(dataEngine, source, v);
if (!obj) {
obj = new DataEngineReceiver(dataEngine, source, v, ScriptEnv::findScriptEnv(engine));
}
} else if (v.isObject()) {
obj = v.toQObject();
if (!obj || obj->metaObject()->indexOfSlot("dataUpdated(QString,Plasma::DataEngine::Data)") == -1) {
obj = getReceiver(dataEngine, source, v);
if (!obj) {
DataEngineReceiver *receiver = new DataEngineReceiver(dataEngine, source, v, ScriptEnv::findScriptEnv(engine));
if (receiver->isValid()) {
obj = receiver;
} else {
delete receiver;
}
}
}
}
return obj;
}
QScriptValue DataEngineReceiver::connectAllSources(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() < 1) {
return engine->undefinedValue();
}
DataEngine *dataEngine = qobject_cast<DataEngine *>(context->thisObject().toQObject());
if (!dataEngine) {
return engine->undefinedValue();
}
int pollingInterval = 0;
Plasma::IntervalAlignment intervalAlignment = Plasma::NoAlignment;
if (context->argumentCount() > 1) {
pollingInterval = context->argument(2).toInt32();
if (context->argumentCount() > 2) {
intervalAlignment = static_cast<Plasma::IntervalAlignment>(context->argument(4).toInt32());
}
}
QObject *obj = extractTargetQObject(engine, QString(), context->argument(0), dataEngine);
if (!obj) {
return engine->undefinedValue();
}
dataEngine->connectAllSources(obj, pollingInterval, intervalAlignment);
return true;
}
QScriptValue DataEngineReceiver::connectSource(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() < 2) {
return engine->undefinedValue();
}
DataEngine *dataEngine = qobject_cast<DataEngine *>(context->thisObject().toQObject());
if (!dataEngine) {
return engine->undefinedValue();
}
const QString source = context->argument(0).toString();
if (source.isEmpty()) {
return engine->undefinedValue();
}
QObject *obj = extractTargetQObject(engine, source, context->argument(1), dataEngine);
if (!obj) {
return engine->undefinedValue();
}
int pollingInterval = 0;
Plasma::IntervalAlignment intervalAlignment = Plasma::NoAlignment;
if (context->argumentCount() > 2) {
pollingInterval = context->argument(2).toInt32();
if (context->argumentCount() > 3) {
intervalAlignment = static_cast<Plasma::IntervalAlignment>(context->argument(4).toInt32());
}
}
dataEngine->connectSource(source, obj, pollingInterval, intervalAlignment);
return true;
}
QScriptValue DataEngineReceiver::disconnectSource(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() < 2) {
return engine->undefinedValue();
}
DataEngine *dataEngine = qobject_cast<DataEngine *>(context->thisObject().toQObject());
if (!dataEngine) {
//kDebug() << "no engine!";
return engine->undefinedValue();
}
const QString source = context->argument(0).toString();
if (source.isEmpty()) {
//kDebug() << "no source!";
return engine->undefinedValue();
}
QObject *obj = 0;
QScriptValue v = context->argument(1);
if (v.isQObject()) {
obj = v.toQObject();
} else if (v.isObject() || v.isFunction()) {
foreach (DataEngineReceiver *receiver, DataEngineReceiver::s_receivers) {
if (receiver->matches(dataEngine, source, v)) {
obj = receiver;
receiver->deleteLater();
break;
}
}
}
if (!obj) {
//kDebug() << "no object!";
return engine->undefinedValue();
}
dataEngine->disconnectSource(source, obj);
return true;
}
#include "dataenginereceiver.moc"