src/plugins/script/qtdbus/main.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the plugins of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "main.h"
       
    43 #include <QDebug>
       
    44 #include <QMetaMethod>
       
    45 #include <QScriptExtensionPlugin>
       
    46 
       
    47 QT_USE_NAMESPACE
       
    48 
       
    49 static QScriptValue setupDBusInterface(QScriptEngine *engine, QDBusAbstractInterface *iface);
       
    50 
       
    51 static QScriptValue do_dbus_call(QScriptContext *context, QScriptEngine *engine)
       
    52 {
       
    53     int firstArgument = 0;
       
    54     QString functionName = context->callee().property(QLatin1String("functionName")).toString();
       
    55     if (functionName.isEmpty()) {
       
    56         functionName = context->argument(0).toString();
       
    57         ++firstArgument;
       
    58     }
       
    59 
       
    60     QScriptValue thisObject = context->thisObject();
       
    61     QDBusAbstractInterface *iface = qobject_cast<QDBusAbstractInterface *>(thisObject.toQObject());
       
    62     if (!iface)
       
    63         return QScriptValue();
       
    64 
       
    65     QDBusMessage msg = QDBusMessage::createMethodCall(iface->service(),
       
    66                                                       iface->path(),
       
    67                                                       iface->interface(),
       
    68                                                       functionName);
       
    69 
       
    70     QList<QVariant> args;
       
    71     for (int i = firstArgument; i < context->argumentCount(); ++i) {
       
    72         args.append(context->argument(i).toVariant());
       
    73     }
       
    74     msg.setArguments(args);
       
    75 
       
    76     msg = iface->connection().call(msg);
       
    77 
       
    78     QScriptValue returnValue = engine->nullValue();
       
    79     args = msg.arguments();
       
    80     if (args.count() != 1)
       
    81         return returnValue;
       
    82 
       
    83     QVariant variant = args.first();
       
    84     if (variant.type() == QVariant::UserType
       
    85         && variant.userType() == qMetaTypeId<QDBusObjectPath>()) {
       
    86         QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(variant);
       
    87 
       
    88         QDBusInterface *returnedIface = new QDBusInterface(iface->service(),
       
    89                                                            path.path(),
       
    90                                                            /*interface*/QString(),
       
    91                                                            iface->connection(),
       
    92                                                            engine);
       
    93         returnValue = setupDBusInterface(engine, returnedIface);
       
    94     } else {
       
    95         returnValue = engine->newVariant(variant);
       
    96     }
       
    97 
       
    98     return returnValue;
       
    99 }
       
   100 
       
   101 static QScriptValue setupDBusInterface(QScriptEngine *engine, QDBusAbstractInterface *iface)
       
   102 {
       
   103     QScriptValue v = engine->newQObject(iface);
       
   104 
       
   105     if (!qobject_cast<QDBusConnectionInterface *>(iface)) {
       
   106         const QMetaObject *mo = iface->metaObject();
       
   107         for (int i = 0; i < mo->methodCount(); ++i) {
       
   108             const QMetaMethod method = mo->method(i);
       
   109             const QByteArray signature = method.signature();
       
   110             //qDebug() << "signature" << signature;
       
   111             int parenIndex = signature.indexOf('(');
       
   112             if (parenIndex == -1)
       
   113                 continue;
       
   114             const QByteArray name = signature.left(parenIndex);
       
   115             if (name.isEmpty())
       
   116                 continue;
       
   117 
       
   118             // don't try to override properties
       
   119             if (mo->indexOfProperty(name) != -1)
       
   120                 continue;
       
   121 
       
   122             QScriptValue callWrapper = engine->newFunction(do_dbus_call);
       
   123             const QString nameString = QString::fromAscii(name);
       
   124             callWrapper.setProperty(QLatin1String("functionName"), QScriptValue(engine, nameString));
       
   125             v.setProperty(nameString, callWrapper);
       
   126         }
       
   127     }
       
   128 
       
   129     v.setProperty(QLatin1String("service"), QScriptValue(engine, iface->service()), QScriptValue::ReadOnly);
       
   130     v.setProperty(QLatin1String("path"), QScriptValue(engine, iface->path()), QScriptValue::ReadOnly);
       
   131     v.setProperty(QLatin1String("interface"), QScriptValue(engine, iface->interface()), QScriptValue::ReadOnly);
       
   132     v.setProperty(QLatin1String("isValid"), QScriptValue(engine, iface->isValid()), QScriptValue::ReadOnly);
       
   133     v.setProperty(QLatin1String("connection"), engine->newQObject(new QScriptDBusConnection(iface->connection(), engine)), QScriptValue::ReadOnly);
       
   134 
       
   135     return v;
       
   136 }
       
   137 
       
   138 QDBusConnectionConstructor::QDBusConnectionConstructor(QScriptEngine *engine, QScriptValue extensionObject)
       
   139     : QObject(engine)
       
   140 {
       
   141     QScriptValue ctor = engine->newQObject(this);
       
   142 
       
   143     QScriptValue proto = engine->newQMetaObject(&QDBusConnection::staticMetaObject);
       
   144     proto.setPrototype(engine->globalObject().property(QLatin1String("Function")).property(QLatin1String("prototype")));
       
   145     ctor.setProperty(QLatin1String("prototype"), proto);
       
   146 
       
   147     extensionObject.setProperty(QLatin1String("QDBusConnection"), ctor);
       
   148 }
       
   149 
       
   150 QScriptValue QDBusConnectionConstructor::sessionBus() const
       
   151 {
       
   152     return engine()->newQObject(new QScriptDBusConnection(QDBusConnection::sessionBus(), engine()));
       
   153 }
       
   154 
       
   155 QScriptValue QDBusConnectionConstructor::systemBus() const
       
   156 {
       
   157     return engine()->newQObject(new QScriptDBusConnection(QDBusConnection::systemBus(), engine()));
       
   158 }
       
   159 
       
   160 QObject *QDBusConnectionConstructor::qscript_call(const QString &name)
       
   161 {
       
   162     return new QScriptDBusConnection(QDBusConnection(name), this);
       
   163 }
       
   164 
       
   165 void QDBusConnectionConstructor::disconnectFromBus(const QString &name)
       
   166 {
       
   167     QDBusConnection::disconnectFromBus(name);
       
   168 }
       
   169 
       
   170 QDBusConnection QDBusConnectionConstructor::connectToBus(const QString &address, const QString &name)
       
   171 {
       
   172     return QDBusConnection::connectToBus(address, name);
       
   173 }
       
   174 
       
   175 QDBusConnection QDBusConnectionConstructor::connectToBus(QDBusConnection::BusType type, const QString &name)
       
   176 {
       
   177     return QDBusConnection::connectToBus(type, name);
       
   178 }
       
   179 
       
   180 QScriptDBusConnection::QScriptDBusConnection(const QDBusConnection &conn, QObject *parent)
       
   181     : QObject(parent), connection(conn)
       
   182 {
       
   183 }
       
   184 
       
   185 QScriptValue QScriptDBusConnection::dbusInterface() const
       
   186 {
       
   187     QDBusConnectionInterface *iface = connection.interface();
       
   188     if (!iface)
       
   189         return engine()->nullValue();
       
   190     return setupDBusInterface(engine(), iface);
       
   191 }
       
   192 
       
   193 QScriptDBusInterfaceConstructor::QScriptDBusInterfaceConstructor(QScriptEngine *engine, QScriptValue extensionObject)
       
   194 {
       
   195     QScriptValue ctorValue = engine->newQObject(this);
       
   196     QScriptValue klass = engine->newQMetaObject(metaObject(), ctorValue);
       
   197     extensionObject.setProperty(QLatin1String("QDBusInterface"), klass);
       
   198 }
       
   199 
       
   200 QScriptValue QScriptDBusInterfaceConstructor::qscript_call(const QString &service, const QString &path, const QString &interface,
       
   201                                                            const QScriptValue &conn)
       
   202 {
       
   203     QDBusConnection connection = QDBusConnection::sessionBus();
       
   204 
       
   205     QScriptDBusConnection *connWrapper = qobject_cast<QScriptDBusConnection *>(conn.toQObject());
       
   206     if (connWrapper)
       
   207         connection = connWrapper->dbusConnection();
       
   208 
       
   209     return setupDBusInterface(engine(), new QDBusInterface(service, path, interface, connection, engine()));
       
   210 }
       
   211 
       
   212 QScriptDBusMessageConstructor::QScriptDBusMessageConstructor(QScriptEngine *engine, QScriptValue extensionObject)
       
   213     : QObject(engine)
       
   214 {
       
   215     proto = engine->newQMetaObject(metaObject(), engine->newQObject(this));
       
   216 
       
   217     proto.setProperty(QLatin1String("createReply"), engine->newFunction(createReply));
       
   218     proto.setProperty(QLatin1String("createErrorReply"), engine->newFunction(createErrorReply));
       
   219 
       
   220     extensionObject.setProperty(QLatin1String("QDBusMessage"), proto);
       
   221     engine->setDefaultPrototype(qMetaTypeId<QDBusMessage>(), proto);
       
   222 }
       
   223 
       
   224 QDBusMessage QScriptDBusMessageConstructor::createSignal(const QString &path, const QString &interface, const QString &name)
       
   225 {
       
   226     return QDBusMessage::createSignal(path, interface, name);
       
   227 }
       
   228 
       
   229 QDBusMessage QScriptDBusMessageConstructor::createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
       
   230 {
       
   231     return QDBusMessage::createMethodCall(destination, path, interface, method);
       
   232 }
       
   233 
       
   234 QDBusMessage QScriptDBusMessageConstructor::createError(const QString &name, const QString &msg)
       
   235 {
       
   236     return QDBusMessage::createError(name, msg);
       
   237 }
       
   238 
       
   239 static QScriptValue messageToScriptValue(QScriptEngine *engine, const QDBusMessage &message)
       
   240 {
       
   241     QScriptValue v = engine->newVariant(QVariant::fromValue(message));
       
   242     v.setProperty(QLatin1String("service"), QScriptValue(engine, message.service()), QScriptValue::ReadOnly);
       
   243     v.setProperty(QLatin1String("path"), QScriptValue(engine, message.path()), QScriptValue::ReadOnly);
       
   244     v.setProperty(QLatin1String("interface"), QScriptValue(engine, message.interface()), QScriptValue::ReadOnly);
       
   245     v.setProperty(QLatin1String("member"), QScriptValue(engine, message.member()), QScriptValue::ReadOnly);
       
   246     v.setProperty(QLatin1String("type"), QScriptValue(engine, message.type()), QScriptValue::ReadOnly);
       
   247     v.setProperty(QLatin1String("signature"), QScriptValue(engine, message.signature()), QScriptValue::ReadOnly);
       
   248     v.setProperty(QLatin1String("isReplyRequired"), QScriptValue(engine, message.isReplyRequired()), QScriptValue::ReadOnly);
       
   249 
       
   250     v.setProperty(QLatin1String("delayedReply"), QScriptValue(engine, message.isDelayedReply()));
       
   251     QScriptValue argValue = engine->newArray();
       
   252     const QList<QVariant> args = message.arguments();
       
   253     for (int i = 0; i < args.count(); ++i)
       
   254         argValue.setProperty(QScriptValue(engine, i).toString(),
       
   255                              engine->newVariant(args.at(i)));
       
   256 
       
   257     v.setProperty(QLatin1String("arguments"), argValue);
       
   258 
       
   259     return v;
       
   260 }
       
   261 
       
   262 static void scriptValueToMessage(const QScriptValue &value, QDBusMessage &message)
       
   263 {
       
   264     QVariant v = value.toVariant();
       
   265     message = qvariant_cast<QDBusMessage>(v);
       
   266     message.setDelayedReply(value.property(QLatin1String("delayedReply")).toBoolean());
       
   267 
       
   268     QList<QVariant> args;
       
   269     quint32 len = value.property(QLatin1String("length")).toUInt32();
       
   270     for (quint32 i = 0; i < len; ++i) {
       
   271         QScriptValue item = value.property(i);
       
   272         args.append(item.toVariant());
       
   273     }
       
   274     message.setArguments(args);
       
   275 }
       
   276 
       
   277 QScriptValue QScriptDBusMessageConstructor::createReply(QScriptContext *context, QScriptEngine *engine)
       
   278 {
       
   279     QDBusMessage msg;
       
   280     scriptValueToMessage(context->thisObject(), msg);
       
   281 
       
   282     QList<QVariant> args;
       
   283     for (int i = 0; i < context->argumentCount(); ++i) {
       
   284         QScriptValue value = context->argument(i);
       
   285         args.append(value.toVariant());
       
   286     }
       
   287 
       
   288     return messageToScriptValue(engine, msg.createReply(args));
       
   289 }
       
   290 
       
   291 QScriptValue QScriptDBusMessageConstructor::createErrorReply(QScriptContext *context, QScriptEngine *engine)
       
   292 {
       
   293     if (context->argumentCount() != 2)
       
   294         return engine->nullValue();
       
   295 
       
   296     QDBusMessage msg;
       
   297     scriptValueToMessage(context->thisObject(), msg);
       
   298 
       
   299     QString name = context->argument(0).toString();
       
   300     QString errMsg = context->argument(1).toString();
       
   301     return messageToScriptValue(engine, msg.createErrorReply(name, errMsg));
       
   302 }
       
   303 
       
   304 template <typename T>
       
   305 QScriptValue qDBusReplyToScriptValue(QScriptEngine *eng, const QDBusReply<T> &reply)
       
   306 {
       
   307     return QScriptValue(eng, reply.value());
       
   308 }
       
   309 
       
   310 template <>
       
   311 QScriptValue qDBusReplyToScriptValue(QScriptEngine *eng, const QDBusReply<QStringList> &reply)
       
   312 {
       
   313     QScriptValue v = eng->newArray();
       
   314     const QStringList &lst = reply.value();
       
   315     for (int i = 0; i < lst.count(); ++i)
       
   316         v.setProperty(i, QScriptValue(eng, lst.at(i)));
       
   317     return v;
       
   318 }
       
   319 
       
   320 template <typename T>
       
   321 void qDBusReplyFromScriptValue(const QScriptValue &, QDBusReply<T> &)
       
   322 {
       
   323     // never called
       
   324 }
       
   325 
       
   326 QScriptValue qDBusErrorToScriptValue(QScriptEngine *engine, const QDBusError &error)
       
   327 {
       
   328     QScriptValue v = engine->newObject();
       
   329     v.setProperty(QLatin1String("type"), QScriptValue(engine, error.type()), QScriptValue::ReadOnly);
       
   330     v.setProperty(QLatin1String("name"), QScriptValue(engine, error.name()), QScriptValue::ReadOnly);
       
   331     v.setProperty(QLatin1String("message"), QScriptValue(engine, error.message()), QScriptValue::ReadOnly);
       
   332     v.setProperty(QLatin1String("isValid"), QScriptValue(engine, error.isValid()), QScriptValue::ReadOnly);
       
   333     return v;
       
   334 }
       
   335 
       
   336 void scriptValueToQDBusError(const QScriptValue &value, QDBusError &error)
       
   337 {
       
   338     Q_UNUSED(value)
       
   339     Q_UNUSED(error)
       
   340     // never called
       
   341 }
       
   342 
       
   343 Q_DECLARE_METATYPE(QDBusReply<QString>)
       
   344 Q_DECLARE_METATYPE(QDBusReply<QStringList>)
       
   345 Q_DECLARE_METATYPE(QDBusReply<uint>)
       
   346 Q_DECLARE_METATYPE(QDBusReply<bool>)
       
   347 Q_DECLARE_METATYPE(QDBusReply<QDBusConnectionInterface::RegisterServiceReply>)
       
   348 Q_DECLARE_METATYPE(QDBusError)
       
   349 
       
   350 class QtDBusScriptPlugin : public QScriptExtensionPlugin
       
   351 {
       
   352 public:
       
   353     QStringList keys() const;
       
   354     void initialize(const QString &key, QScriptEngine *engine);
       
   355 };
       
   356 
       
   357 QStringList QtDBusScriptPlugin::keys() const
       
   358 {
       
   359     return QStringList(QLatin1String("qt.dbus"));
       
   360 }
       
   361 
       
   362 void QtDBusScriptPlugin::initialize(const QString &key, QScriptEngine *engine)
       
   363 {
       
   364     if (key != QLatin1String("qt.dbus")) {
       
   365         Q_ASSERT_X(false, "initialize", qPrintable(key));
       
   366         return;
       
   367     }
       
   368 
       
   369     QScriptValue extensionObject = engine->globalObject();
       
   370 
       
   371     qScriptRegisterMetaType<QDBusReply<QString> >(engine, qDBusReplyToScriptValue, qDBusReplyFromScriptValue);
       
   372     qScriptRegisterMetaType<QDBusReply<QStringList> >(engine, qDBusReplyToScriptValue, qDBusReplyFromScriptValue);
       
   373     qScriptRegisterMetaType<QDBusReply<uint> >(engine, qDBusReplyToScriptValue, qDBusReplyFromScriptValue);
       
   374     qScriptRegisterMetaType<QDBusReply<bool> >(engine, qDBusReplyToScriptValue, qDBusReplyFromScriptValue);
       
   375     qScriptRegisterMetaType<QDBusReply<QDBusConnectionInterface::RegisterServiceReply> >(engine, qDBusReplyToScriptValue, qDBusReplyFromScriptValue);
       
   376     qScriptRegisterMetaType<QDBusMessage>(engine, messageToScriptValue, scriptValueToMessage);
       
   377     qScriptRegisterMetaType<QDBusError>(engine, qDBusErrorToScriptValue, scriptValueToQDBusError);
       
   378 
       
   379     QScriptValue connIfaceProto = engine->newQMetaObject(&QDBusConnectionInterface::staticMetaObject, engine->nullValue());
       
   380     extensionObject.setProperty(QLatin1String("QDBusConnectionInterface"), connIfaceProto);
       
   381 
       
   382     QScriptValue qdbus = engine->newObject();
       
   383     qdbus.setProperty(QLatin1String("NoBlock"), QScriptValue(engine, QDBus::NoBlock));
       
   384     qdbus.setProperty(QLatin1String("Block"), QScriptValue(engine, QDBus::Block));
       
   385     qdbus.setProperty(QLatin1String("BlockWithGui"), QScriptValue(engine, QDBus::BlockWithGui));
       
   386     qdbus.setProperty(QLatin1String("AutoDetect"), QScriptValue(engine, QDBus::AutoDetect));
       
   387     engine->globalObject().setProperty(QLatin1String("QDBus"), qdbus);
       
   388 
       
   389     (void)new QDBusConnectionConstructor(engine, extensionObject);
       
   390     (void)new QScriptDBusInterfaceConstructor(engine, extensionObject);
       
   391     (void)new QScriptDBusMessageConstructor(engine, extensionObject);
       
   392 }
       
   393 
       
   394 
       
   395 Q_EXPORT_STATIC_PLUGIN(QtDBusScriptPlugin)
       
   396 Q_EXPORT_PLUGIN2(qtscriptdbus, QtDBusScriptPlugin)