allow connecting engine sources to pretty much anything in the script

svn path=/trunk/KDE/kdebase/runtime/; revision=1101799
This commit is contained in:
Aaron J. Seigo 2010-03-10 23:10:33 +00:00
parent 7b3c875217
commit 8df3489f24
4 changed files with 256 additions and 18 deletions

View File

@ -7,6 +7,7 @@ set(simple_javascript_engine_SRCS
simplebindings/animationgroup.cpp
simplebindings/appletinterface.cpp
simplebindings/anchorlayout.cpp
simplebindings/dataenginereceiver.cpp
simplebindings/bytearrayclass.cpp
simplebindings/bytearrayprototype.cpp
simplebindings/color.cpp

View File

@ -0,0 +1,190 @@
/*
* 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;
}
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 = 0;
QScriptValue v = context->argument(1);
// 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;
}
}
}
}
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"

View File

@ -0,0 +1,57 @@
/*
* Copyright 2010 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 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.
*/
#ifndef DATAENGINERECEIVER_H
#define DATAENGINERECEIVER_H
#include <QScriptValue>
#include <Plasma/DataEngine>
class QScriptContext;
class QScriptEngine;
class DataEngineReceiver : public QObject
{
Q_OBJECT
public:
DataEngineReceiver(const Plasma::DataEngine *engine, const QString &source, const QScriptValue &func, QObject *parent);
~DataEngineReceiver();
bool isValid() const;
static QScriptValue connectSource(QScriptContext *context, QScriptEngine *engine);
static QScriptValue disconnectSource(QScriptContext *context, QScriptEngine *engine);
static QSet<DataEngineReceiver*> s_receivers;
bool matches(const Plasma::DataEngine *engine, const QString &source, const QScriptValue &v);
public Q_SLOTS:
void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
private:
static DataEngineReceiver *getReceiver(Plasma::DataEngine *dataEngine, const QString &source, const QScriptValue &v);
const Plasma::DataEngine *m_engine;
const QString m_source;
QScriptValue m_func;
QScriptValue m_obj;
};
#endif // DATAENGINERECEIVER_H

View File

@ -55,6 +55,7 @@
#include "scriptenv.h"
#include "simplebindings/animationgroup.h"
#include "simplebindings/dataengine.h"
#include "simplebindings/dataenginereceiver.h"
#include "simplebindings/i18n.h"
#include "simplebindings/appletinterface.h"
#include "simplebindings/bytearrayclass.h"
@ -157,23 +158,9 @@ void SimpleJavaScriptApplet::configChanged()
void SimpleJavaScriptApplet::dataUpdated(const QString &name, const DataEngine::Data &data)
{
QScriptValue fun = m_self.property("dataUpdated");
if (!fun.isFunction()) {
kDebug() << "Script: dataUpdated is not a function, " << fun.toString();
return;
}
QScriptValueList args;
args << m_engine->toScriptValue(name) << m_engine->toScriptValue(data);
QScriptContext *ctx = m_engine->pushContext();
ctx->setActivationObject(m_self);
fun.call(m_self, args);
m_engine->popContext();
if (m_engine->hasUncaughtException()) {
reportError(m_env);
}
callFunction("dataUpdated", args);
}
void SimpleJavaScriptApplet::extenderItemRestored(Plasma::ExtenderItem* item)
@ -413,9 +400,12 @@ QScriptValue SimpleJavaScriptApplet::dataEngine(QScriptContext *context, QScript
return context->throwError(i18n("Could not extract the Applet"));
}
const QString dataEngine = context->argument(0).toString();
DataEngine *data = interface->dataEngine(dataEngine);
return engine->newQObject(data, QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject);
const QString dataEngineName = context->argument(0).toString();
DataEngine *dataEngine = interface->dataEngine(dataEngineName);
QScriptValue v = engine->newQObject(dataEngine, QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject);
v.setProperty("connectSource", engine->newFunction(DataEngineReceiver::connectSource));
v.setProperty("disconnectSource", engine->newFunction(DataEngineReceiver::disconnectSource));
return v;
}
QScriptValue SimpleJavaScriptApplet::service(QScriptContext *context, QScriptEngine *engine)