diff --git a/scriptengines/javascript/CMakeLists.txt b/scriptengines/javascript/CMakeLists.txt index 0cc32a8cc..54682f926 100644 --- a/scriptengines/javascript/CMakeLists.txt +++ b/scriptengines/javascript/CMakeLists.txt @@ -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 diff --git a/scriptengines/javascript/simplebindings/dataenginereceiver.cpp b/scriptengines/javascript/simplebindings/dataenginereceiver.cpp new file mode 100644 index 000000000..034cc5eaf --- /dev/null +++ b/scriptengines/javascript/simplebindings/dataenginereceiver.cpp @@ -0,0 +1,190 @@ +/* + * Copyright 2010 Aaron J. Seigo + * + * 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 + +#include "dataengine.h" +#include "scriptenv.h" + +QSet 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(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(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(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(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" + diff --git a/scriptengines/javascript/simplebindings/dataenginereceiver.h b/scriptengines/javascript/simplebindings/dataenginereceiver.h new file mode 100644 index 000000000..b1559d8e6 --- /dev/null +++ b/scriptengines/javascript/simplebindings/dataenginereceiver.h @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Aaron Seigo + * + * 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 + +#include + +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 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 + diff --git a/scriptengines/javascript/simplejavascriptapplet.cpp b/scriptengines/javascript/simplejavascriptapplet.cpp index 004781a69..842156ace 100644 --- a/scriptengines/javascript/simplejavascriptapplet.cpp +++ b/scriptengines/javascript/simplejavascriptapplet.cpp @@ -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)